001 /*************************************************************************************************** 002 * MODULE DESCRIPTION 003 **************************************************************************************************** 004 * 005 * NAME: SearchHandler.java 006 * LANGUAGE: Java2 007 * DATE: 14.1.2003 008 * AUTHOR: Miika Nurminen, Jyväskylän yliopisto 009 * 010 **************************************************************************************************** 011 * COPYRIGHT (C) KIURU-PROJEKTIRYHMÄ 012 * Limited rights granted. Please refer to license 013 **************************************************************************************************** 014 * 015 **************************************************************************************************** 016 * UPDATES 017 **************************************************************************************************** 018 * 019 * 14.1.2003 Initial release 020 * 021 ****************************************************************************************************/ 022 package kiurubeans; 023 024 import kotkabeans.Log; 025 import kotkabeans.Encoder; 026 import javax.servlet.http.HttpServletRequest; 027 028 /** 029 * Superclass for searchobjects (eg. SpaceSearch, PersonSearch...) 030 * 031 * @author Miika Nurminen 032 */ 033 public abstract class SearchHandler extends KiuruHandler { 034 035 // Attributes 036 037 /** Submits search with current field value. */ 038 public static final int SUBMIT_SEARCH=1; 039 040 /** Clears search field. Search does not return anything. */ 041 public static final int RESET_SEARCH=2; 042 043 /** Fields used for ordering sorted in preferred order */ 044 private Field[] visibleFields; 045 046 /** Value for SQL ordering. Multiple values are separated by ,*/ 047 private String order = new String(); 048 049 050 // Constructors 051 052 /** Dummy empty constructor. */ 053 public SearchHandler() { 054 } 055 056 // Access methods 057 058 /** 059 * Returns current max state value. Inherited classes may override this 060 * when new states are introduced. 061 * 062 * @return max state value 063 */ 064 protected int getMaxState() { 065 return 2; 066 } 067 068 /** 069 * Indexed getter for property visibleFields. 070 * 071 * @param index Index of the property. 072 * @return Value of the property at <CODE>index</CODE>. 073 */ 074 public Field getVisibleFields(int index) { 075 return this.visibleFields[index]; 076 } 077 078 /** 079 * Getter for property visibleFields. 080 * 081 * @return Value of property visibleFields. 082 */ 083 public Field[] getVisibleFields() { 084 return this.visibleFields; 085 } 086 087 /** 088 * Indexed setter for property visibleFields. 089 * 090 * @param index Index of the property. 091 * @param visibleFields New value of the property at <CODE>index</CODE>. 092 */ 093 public void setVisibleFields(int index, Field visibleFields) { 094 this.visibleFields[index] = visibleFields; 095 } 096 097 /** 098 * Setter for property visibleFields. 099 * 100 * @param visibleFields New value of property visibleFields. 101 */ 102 public void setVisibleFields(Field[] visibleFields) { 103 this.visibleFields = visibleFields; 104 } 105 106 /** 107 * Getter for property order. 108 * 109 * @return Value of property order. 110 */ 111 public String getOrder() { 112 return this.order; 113 } 114 115 /** 116 * Sets bean state to SUBMIT_SEARCH. Usually called from a web form. 117 * 118 * @param s any nonempty string. 119 * @see #SUBMIT_SEARCH 120 */ 121 public void setSubmitSearch(String s) { 122 setEnumState(SUBMIT_SEARCH); 123 } 124 125 /** 126 * Sets bean state to NO_ACTION. Usually called from a web form. 127 * 128 * @param s any nonempty string. 129 * @see #NO_ACTION 130 */ 131 public void setContinueSearch(String s) { 132 setEnumState(NO_ACTION); 133 } 134 135 136 /** 137 * Returns incasesensitive index of field alias. 138 * 139 * @param name field alias name 140 * @return index of field, -1 if not valid 141 */ 142 public int fieldIndexOf(String name) { 143 for (int i=0; i<getVisibleFields().length; i++) { 144 if (getVisibleFields(i).getAlias().equalsIgnoreCase(name)) { 145 return i; 146 } 147 } 148 return -1; 149 } 150 151 152 153 /** 154 * Setter for property order. 155 * 156 * @param order New value of property order. Multiple fields are separated by , 157 */ 158 public void setOrder(String order) { 159 if ((getVisibleFields()!=null) && (getVisibleFields().length>0)) { 160 if (order.indexOf(',') ==-1) { 161 order = kotkabeans.Encoder.SQLEncode(order); 162 int index = fieldIndexOf(order); 163 164 // if order is not valid, do nothing (it might be meant for somewhere else...) 165 if (index==-1) return; 166 StringBuffer newOrder = new StringBuffer(10*getVisibleFields().length); 167 // first chosen order, default ordering follows 168 newOrder.append(getVisibleFields(index).getOrderName()); 169 for (int i=0; i<getVisibleFields().length; i++) { 170 if (i!=index) { 171 newOrder.append(", "); 172 newOrder.append(getVisibleFields(i).getOrderName()); 173 } 174 } 175 this.order=newOrder.toString(); 176 } 177 else { 178 setMultiOrder(order); 179 } 180 } 181 else this.order = order; 182 } 183 184 185 /** 186 * Setter for property order when string contains multiple fields. 187 * 188 * @param order New value of property order. Multiple fields are separated by , 189 */ 190 private void setMultiOrder(String order) { 191 if ((order==null) || (order.length()==0)) return; 192 193 java.util.StringTokenizer sT = new java.util.StringTokenizer(order,","); 194 java.util.ArrayList fields = new java.util.ArrayList(6); 195 String s; 196 int i,j; 197 while(sT.hasMoreElements()) { 198 s = kotkabeans.Encoder.SQLEncode( ((String)(sT.nextElement())).trim() ); 199 i = fieldIndexOf(s); 200 if (i>-1) { 201 if (fields.size()>0) { 202 j=fields.indexOf(new Integer(i)); 203 if (j>-1) continue; // value already exists in list 204 } 205 fields.add(new Integer(i)); 206 } 207 } 208 // if order is not valid, do nothing (it might be meant for somewhere else...) 209 if (fields.size()==0) return; 210 StringBuffer newOrder = new StringBuffer(10*getVisibleFields().length); 211 for (i=0; i<fields.size(); i++) { 212 if (i>0) newOrder.append(", "); 213 newOrder.append(getVisibleFields(((Integer)(fields.get(i))).intValue()).getOrderName()); 214 } 215 216 // first chosen order, default ordering follows 217 for (i=0; i<getVisibleFields().length; i++) { 218 if (fields.indexOf(new Integer(i))==-1) { 219 newOrder.append(", "); 220 newOrder.append(getVisibleFields(i).getOrderName()); 221 } 222 } 223 this.order=newOrder.toString(); 224 } 225 226 // Operations 227 228 /** 229 * Returns order clause to be appended in search SQL. 230 * 231 * @return order part of SQL clause or nothing if there is no ordering. 232 */ 233 public String getOrderClause() { 234 if ((getOrder()!=null) && (getOrder().length()>0)) { 235 return " order by "+getOrder(); 236 } 237 else return " "; 238 } 239 240 241 /** Assigns order according to visibleFields. */ 242 public void assignDefaultOrder() { 243 if ((getVisibleFields()!=null) && (getVisibleFields().length>0)) { 244 StringBuffer newOrder = new StringBuffer(10*getVisibleFields().length); 245 for (int i=0; i<getVisibleFields().length; i++) { 246 if (i>0) newOrder.append(", "); 247 newOrder.append(getVisibleFields(i).getOrderName()); 248 } 249 this.order=newOrder.toString(); 250 } 251 else setOrder(""); 252 } 253 254 /** 255 * Ensures empty request parameters are clearer when entity is posted. 256 * <p> 257 * If bean is used in a JSP, this should be called in the beginning of page. 258 * If form content is "" or null it is not sent via HTTP, so those fields 259 * must be cleared manually. Method may be called from a handler or UI page. 260 * Descendant classes should redefine conditions for calling 261 * doClearEmpty parameters method. 262 * 263 * @param request HTTP request with parameters 264 * @see #doClearEmptyParameters(HttpServletRequest) 265 */ 266 public void clearEmptyParameters(HttpServletRequest request) { 267 super.clearEmptyParameters(request); 268 if ((getEnumState()==SUBMIT_SEARCH)){ //or: action!= NO_ACTION && :=CONTINUE_SEARCH 269 kotkabeans.Log.log("Clearing empty parameters"); 270 doClearEmptyParameters(request); 271 } 272 } 273 274 /** 275 * Implementation of clearing action state. Inherited classes should always override this. 276 * 277 * @param request Http request used for parameter parsing. 278 */ 279 protected void doClearActionState(javax.servlet.http.HttpServletRequest request) { 280 if ((KiuruString.isEmpty(request.getParameter("submitSearch"))) && 281 (KiuruString.isEmpty(request.getParameter("continueSearch")))) { 282 setEnumState(RESET_SEARCH); 283 } 284 } 285 286 /** 287 * Implementation for SUBMIT_SEARCH 288 */ 289 public abstract void submitSearch(); 290 291 /** 292 * Implementation for RESET_SEARCH 293 */ 294 public abstract void resetSearch(); 295 296 /** 297 * Performs action based on actionType. Called from performAction. 298 * Descendant classes should override this and call the same method 299 * in inherited class as default. 300 * 301 * @throws Exception If something went wrong during actual executed action. 302 * @see KiuruHandler#performAction() 303 */ 304 protected void defaultAction() throws java.lang.Exception { 305 switch (getEnumState()) { 306 case SUBMIT_SEARCH: 307 submitSearch(); 308 break; 309 default: // RESET_SEARCH by default 310 resetSearch(); 311 break; 312 } 313 } 314 315 protected void doClearEmptyParameters(javax.servlet.http.HttpServletRequest request) { 316 } 317 318 } 319 /*************************************************************************************************** 320 * COPYRIGHT (C) KIURU -PROJECT GROUP 321 * Limited rights granted. Please refer to license. 322 **************************************************************************************************/