Source code: com/jcorporate/expresso/services/controller/dbmaint/Lookup.java
1 /* ====================================================================
2 * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3 *
4 * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * 3. The end-user documentation included with the redistribution,
19 * if any, must include the following acknowledgment:
20 * "This product includes software developed by Jcorporate Ltd.
21 * (http://www.jcorporate.com/)."
22 * Alternately, this acknowledgment may appear in the software itself,
23 * if and wherever such third-party acknowledgments normally appear.
24 *
25 * 4. "Jcorporate" and product names such as "Expresso" must
26 * not be used to endorse or promote products derived from this
27 * software without prior written permission. For written permission,
28 * please contact info@jcorporate.com.
29 *
30 * 5. Products derived from this software may not be called "Expresso",
31 * or other Jcorporate product names; nor may "Expresso" or other
32 * Jcorporate product names appear in their name, without prior
33 * written permission of Jcorporate Ltd.
34 *
35 * 6. No product derived from this software may compete in the same
36 * market space, i.e. framework, without prior written permission
37 * of Jcorporate Ltd. For written permission, please contact
38 * partners@jcorporate.com.
39 *
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43 * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This software consists of voluntary contributions made by many
55 * individuals on behalf of the Jcorporate Ltd. Contributions back
56 * to the project(s) are encouraged when you make modifications.
57 * Please send them to support@jcorporate.com. For more information
58 * on Jcorporate Ltd. and its products, please see
59 * <http://www.jcorporate.com/>.
60 *
61 * Portions of this software are based upon other open source
62 * products and are subject to their respective licenses.
63 */
64
65 /**
66 * [Currently not used.... volunteers to integrate?]
67 *
68 *
69 * can filter its lookup popup according to some conditions. For example: list
70 * only cities within a given state.
71 *
72 *
73 * Some note on the design:
74 *
75 * - modifying getValidValues() to some extend (to allow filtering) would be
76 * great. But I still haven't had a clear picture how things work out. That's
77 * one of the reasons that I came up with this 'surgical operation'.
78 *
79 * - One advantage of this surgical operation is that, extending
80 * functionality of getValidValues will still not able to solve the
81 * 'MultiDBObjects-lookup' problem. So I thought it is necessary to put all
82 * this kind of lookup into one place.
83 *
84 * Talking about conditional lookup, I think that flexibility is most
85 * important. The lookup function should allow user to do ORed-condition
86 * lookup on joined tables and views. My plan is to use the same lookup
87 * interface (API), both in add and search, for all cases mentioned above:
88 * full lookup (no filter), partial lookup (with simple/advanced filtering
89 * condition(s)), and MultiDBObjects lookups. The difference of the HashMap
90 * controls the different behavior.
91 *
92 * @version $Revision: 1.12 $ $Date: 2004/11/18 02:03:30 $
93 * @author Tong Sun
94 *
95 */
96
97 // ========================================================= &declare ===
98
99 package com.jcorporate.expresso.services.controller.dbmaint;
100
101 import com.jcorporate.expresso.core.controller.session.HTTPPersistentSession;
102 import com.jcorporate.expresso.core.db.DBException;
103 import com.jcorporate.expresso.core.dbobj.DBObject;
104 import com.jcorporate.expresso.core.dbobj.ValidValue;
105 import com.jcorporate.expresso.core.misc.SerializableString;
106 import com.jcorporate.expresso.core.misc.StringUtil;
107 import org.apache.log4j.Logger;
108
109 import javax.servlet.http.HttpServletRequest;
110 import java.io.IOException;
111 import java.io.ObjectInputStream;
112 import java.io.ObjectOutputStream;
113 import java.io.Serializable;
114 import java.lang.reflect.Method;
115 import java.util.HashMap;
116 import java.util.Iterator;
117 import java.util.Vector;
118
119 // ======================================================= &class_def ===
120
121 public class Lookup implements Serializable {
122
123 /* the logs */
124 transient private static Logger log = Logger.getLogger(Lookup.class);
125
126 public static final String DBF_DBNAME = "dbf_dbname";
127 public static final String DBF_DBKEY = "dbf_dbkey";
128 public static final String DBF_DBDESC = "dbf_dbdesc";
129 public static final String DBF_DB_FILTER_FNAME = "dbf_db_filter_fname";
130 public static final String DBF_DB_FILTER_VALUE = "dbf_db_filter_value";
131 public static final String DBF_DB_FILTER_WHERE = "dbf_db_filter_where";
132
133 public static final String DBM_ACTION_KEY = "dbm_action";
134 public static final String DBM_ACTION_SEARCH = "search";
135
136 protected HashMap theFilter;
137
138
139 // -------------------------------------------------------------- &mf ---
140 // .................................................. member function ...
141 /**
142 * Default Constructor
143 */
144 public Lookup() {
145 super();
146 theFilter = new HashMap();
147 }
148
149 // -------------------------------------------------------------- &mf ---
150 // .................................................. member function ...
151 /**
152 * Get property: theFilter
153 *
154 * @return java.util.HashMap
155 */
156 public HashMap getTheFilter() {
157 return theFilter;
158 }
159
160 // -------------------------------------------------------------- &mf ---
161 // .................................................. member function ...
162 /**
163 * Adding simple partial lookup filter.
164 * <p/>
165 * Parameters are: lookup db name, key field name, description
166 * field name, filter field name and filter field value.
167 *
168 * @param dbname the data context
169 * @param dbkey The key field name
170 * @param dbdesc The description field name
171 * @param db_filter_fname The field name to filter against
172 * @param db_filter_value The value field name to filter against
173 */
174 public void setFilter(String dbname, String dbkey, String dbdesc,
175 String db_filter_fname, String db_filter_value) {
176 theFilter.put(DBF_DBNAME, dbname);
177 theFilter.put(DBF_DBKEY, dbkey);
178 theFilter.put(DBF_DBDESC, dbdesc);
179 theFilter.put(DBF_DB_FILTER_FNAME, db_filter_fname);
180 theFilter.put(DBF_DB_FILTER_VALUE, db_filter_value);
181 }
182
183 // -------------------------------------------------------------- &mf ---
184 // .................................................. member function ...
185 /**
186 * Adding advanced partial lookup filter.
187 * <p/>
188 * Parameters are: lookup db name, key field name, description
189 * field name, filter where clause.
190 *
191 * @param dbname the data context name
192 * @param dbkey The key field name
193 * @param dbdesc Description Field Name
194 * @param db_filter_where the where clause to filter against.
195 */
196 public void setFilter(String dbname, String dbkey, String dbdesc,
197 String db_filter_where) {
198 theFilter.put(DBF_DBNAME, dbname);
199 theFilter.put(DBF_DBKEY, dbkey);
200 theFilter.put(DBF_DBDESC, dbdesc);
201 theFilter.put(DBF_DB_FILTER_WHERE, db_filter_where);
202 }
203
204 // -------------------------------------------------------------- &mf ---
205 // .................................................. member function ...
206
207 /**
208 * Performs the lookup.
209 * <p/>
210 * The basic idea is pre-setting some session variables, i.e.,
211 * <DBObjectName>_filter_<fieldName>. They are HashMap objects that contain
212 * information such as lookup db name, key field name, description field
213 * name, filter field name and filter field value, etc. It is used by
214 * Lookup.java to return ValidValue pairs.
215 * <p/>
216 * The Lookup.java object will be intelligent enough to handle cases like
217 * full lookup (no filter), partial lookup (with simple/advanced filtering
218 * condition(s)), and MultiDBObjects lookups.
219 *
220 * @param myDBObj The DBObject to get the lookup Values from.
221 * @param fieldName ?
222 * @param mySession ?
223 * @return a Vector of lookup values
224 */
225 public static Vector getLookupValues
226 (DBObject myDBObj, String fieldName, HTTPPersistentSession mySession)
227 throws DBException {
228
229 Vector values = null;
230 String sessionString;
231
232 //System.err.println("\n*** getLookupValues entered");
233 if (log.isDebugEnabled()) {
234 log.debug("*** getLookupValues entered");
235 }
236
237 sessionString = myDBObj.getMetaData().getName().replace('.', '_')
238 + "_filter_" + fieldName;
239 //System.err.println("DB: "+ myDBObj.getDBName()+ "\nName: " + sessionString);
240
241 HashMap dbFilter = null;
242 boolean getPersistentAttribute_bug_fixed;
243
244 getPersistentAttribute_bug_fixed = true;
245 getPersistentAttribute_bug_fixed = false;
246
247 if (getPersistentAttribute_bug_fixed) {
248 // FIXME: unable to get back the Lookup Javabean!
249 /*
250 * I suspect that there's a minor bug in the 'getPersistentAttribute'
251 * function, because I can use it to retrieve plain JSP session
252 * variables, but not Javabean variables. Both kinds of variables can be
253 * retrieved correctly within JSP, using 'session.getAttribute'. It
254 * seems to me there is a glitch between State.getSession() and
255 * HTTPPersistentSession.getPersistentAttribute(). No javabeans defined
256 * as <jsp:useBean /> in JSP can be retrieved that way. After spending
257 * for over 3 days exploring different ways to do it, I'm now curious
258 * whether anybody has eventually retrieve any javabeans defined in JSP
259 * or not. This bug is beyond my capability to solve. So I'm just
260 * leaving my test code here, until someone can find a
261 * solution. Meanwhile, please define plain JSP session variables.
262 */
263 sessionString += "_";
264 Object lookup_obj = mySession.getPersistentAttribute(sessionString);
265 Lookup lookup = (Lookup) lookup_obj;
266 dbFilter = lookup.getTheFilter();
267 } else {
268 dbFilter = (HashMap) mySession.getPersistentAttribute(sessionString);
269 }
270
271 //System.err.println("HashMap: " + dbFilter);
272 if (dbFilter == null) {
273 // full lookup (no filter)
274 values = myDBObj.getValidValues(fieldName);
275 } else {
276 // partial lookup (with filtering)
277 // getValidValues according to user provided filter
278 values = new Vector();
279
280 try {
281 Class c = Class.forName((String) dbFilter.get(DBF_DBNAME));
282 Object dbo = c.newInstance();
283
284 //System.err.println("DBO: "+ dbo);
285 // setDBName. CALL it ONLY if it exists in the class. It
286 // might not be necessary across contexts.
287 try {
288 Class params[] = {java.lang.String.class};
289 Method m = c.getMethod("setDBName", params);
290 if (m != null) {
291 Object paramValues[] = {myDBObj.getDataContext()};
292 m.invoke(dbo, paramValues);
293 }
294 } catch (NoSuchMethodException nsme) {
295 //Do nothing, the method just doesn't exist.
296 } catch (SecurityException se) {
297 throw new DBException("Security Exception trying to call"
298 + " setDBName in loading lookup object", se);
299 } catch (java.lang.reflect.InvocationTargetException ive) {
300 ive.printStackTrace();
301 throw new DBException("Error calling setDBName in " +
302 "loading lookup object", ive.getTargetException());
303 } catch (IllegalAccessException ilae) {
304 //Do nothing, setDBName is not public
305 }
306
307 // Get ValidValues
308 DBObject dboList = (DBObject) dbo;
309 DBObject oneRecord = null;
310 // set user provided filter
311 String dbf_key;
312 String dbf_val;
313 //System.err.println("Key: "+ (String)dbFilter.get(DBF_DB_FILTER_FNAME) + "\nVal: " + (String)dbFilter.get(DBF_DB_FILTER_VALUE));
314 dboList.setField((String) dbFilter.get(DBF_DB_FILTER_FNAME),
315 (String) dbFilter.get(DBF_DB_FILTER_VALUE));
316 dbf_key = (String) dbFilter.get(DBF_DBKEY);
317 dbf_val = (String) dbFilter.get(DBF_DBDESC);
318 //System.err.println("Key: "+ dbf_key + "\nVal: " + dbf_val);
319 Iterator ii = dboList.searchAndRetrieveList().iterator();
320 while (ii.hasNext()) {
321 oneRecord = (DBObject) ii.next();
322 values.addElement(new
323 ValidValue(oneRecord.getField(dbf_key),
324 oneRecord.getField(dbf_val)));
325 }
326 } catch (ClassNotFoundException cn) {
327 throw new DBException("Lookup object not found", cn);
328 } catch (InstantiationException ie) {
329 throw new DBException("Lookup object cannot be instantiated", ie);
330 } catch (IllegalAccessException iae) {
331 throw new DBException("llegal access loading Lookup object", iae);
332 }
333
334 } // !dbFilter
335
336 //System.err.println("Values: "+ values);
337 if (values == null) {
338 throw new DBException("Valid values for field "
339 + fieldName + " from object "
340 + myDBObj.getMetaData().getName() + " were null");
341 }
342
343 // Add "All Values" entry if searching
344 sessionString = StringUtil.notNull
345 ((SerializableString) mySession.getPersistentAttribute(DBM_ACTION_KEY));
346 if (DBM_ACTION_SEARCH.equalsIgnoreCase(sessionString)) {
347 values.add(new ValidValue("", "All Values"));
348 }
349 return values;
350 }
351
352 // -------------------------------------------------------------- &mf ---
353 // .................................................. member function ...
354
355 public String toString() {
356 return theFilter.toString();
357 }
358
359 // -------------------------------------------------------------- &mf ---
360 // .................................................. member function ...
361
362 /* ************ Serialization Functions *********************** */
363 private void writeObject(ObjectOutputStream oos) throws IOException {
364 oos.defaultWriteObject();
365 }
366
367 private void readObject(ObjectInputStream ois) throws IOException,
368 ClassNotFoundException {
369 ois.defaultReadObject();
370 }
371
372 // -------------------------------------------------------------- &mf ---
373 // .................................................. member function ...
374
375 /**
376 * Remove lookup session variable.
377 *
378 * @param request The Servlet Request
379 */
380 private void remove(HttpServletRequest request) {
381 // TODO: how to?
382 }
383 }
384
385
386