001: package org.openedit.search;
002:
003: import java.text.DateFormat;
004: import java.text.ParseException;
005: import java.text.SimpleDateFormat;
006: import java.util.Calendar;
007: import java.util.Date;
008: import java.util.GregorianCalendar;
009: import java.util.Iterator;
010: import java.util.List;
011:
012: import org.apache.commons.logging.Log;
013: import org.apache.commons.logging.LogFactory;
014: import org.openedit.logger.Change;
015: import org.openedit.logger.LogArchive;
016: import org.openedit.logger.LogDirectory;
017: import org.openedit.xml.FieldArchive;
018:
019: import com.openedit.OpenEditException;
020: import com.openedit.WebPageRequest;
021: import com.openedit.config.Configuration;
022: import com.openedit.hittracker.HitTracker;
023: import com.openedit.hittracker.SearchQuery;
024: import com.openedit.modules.search.BaseLuceneSearch;
025: import com.openedit.modules.search.BaseSearchIndex;
026: import com.openedit.modules.search.LuceneSearchQuery;
027: import com.openedit.modules.xml.Types;
028: import com.openedit.util.URLUtilities;
029: import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
030:
031: public abstract class BaseSearcher {
032: private static final Log log = LogFactory
033: .getLog(BaseSearcher.class);
034: protected LogArchive fieldLogArchive;
035: protected DateFormat fieldDefaultDateFormat;
036:
037: public BaseSearcher() {
038: super ();
039: }
040:
041: protected List deselect(String inField, String[] toremove,
042: FieldArchive inFields) throws OpenEditException {
043: Types options = inFields.getProperties(inField);
044: List list = options.keys();
045: if (toremove != null) {
046: for (int i = 0; i < toremove.length; i++) {
047: String name = toremove[i];
048: list.remove(name);
049: }
050: }
051: return list;
052: }
053:
054: public HitTracker cachedSearch(WebPageRequest inPageRequest,
055: SearchQuery inQuery, String inCatalogId,
056: BaseSearchIndex inSearchIndex) throws OpenEditException {
057: HitTracker tracker;
058: String fullq = inQuery.toQuery();
059: if (fullq == null) {
060: return null;
061: }
062: String hitsname = inPageRequest.findValue("hitsname");
063: if (hitsname == null) {
064: hitsname = "hits";
065: }
066: boolean storesearch = true;
067: String insession = inPageRequest.findValue("resultsinsession");
068: if (insession != null) {
069: storesearch = Boolean.parseBoolean(insession);
070: }
071:
072: tracker = loadHits(inPageRequest, hitsname, inCatalogId,
073: inSearchIndex);
074: boolean runsearch = true;
075:
076: if (fullq != null) {
077: if (tracker != null) {
078: if (inQuery.getSortBy() == null) {
079: String oldSort = tracker.getOrdering();
080: inQuery.setSortBy(oldSort);
081: }
082: String id = inSearchIndex.getIndexId();
083: if (tracker.getIndexId().equals(id)) {
084: if (fullq.length() == 0) {
085: runsearch = false; // they are just going to the next page
086: } else if (fullq.equals(tracker.getQuery())) {
087: String pagenumber = inPageRequest
088: .getRequestParameter("page");
089: if (pagenumber != null) {
090: tracker.setPage(Integer
091: .parseInt(pagenumber));
092: runsearch = false;
093: }
094: // duplicate search skip it
095: // tracker.setPage(1);
096: String cache = inPageRequest
097: .getRequestParameter("cache");
098:
099: if (cache != null
100: && !Boolean.parseBoolean(cache)) {
101: runsearch = true;
102: }
103: }
104: }
105: }
106: if (runsearch) {
107: try {
108: if (inQuery.getSortBy() == null) {
109: String sort = inPageRequest
110: .findValue("defaultsort");
111: inQuery.setSortBy(sort);
112: }
113: tracker = inSearchIndex.search(fullq, inQuery
114: .getSortBy());
115: tracker.setSearchQuery(inQuery);
116:
117: Change change = new Change();
118: change.put("query", inQuery.toFriendly());
119: change.put("user", inPageRequest.getUserName());
120: change.put("hits", String.valueOf(tracker
121: .getTotal()));
122: change.put("sort", inQuery.getSortBy());
123:
124: logEntry(inCatalogId, change);
125:
126: if (storesearch) {
127: inPageRequest.putSessionValue(hitsname
128: + inCatalogId, tracker);
129: }
130: inPageRequest.putPageValue(hitsname, tracker);
131: } catch (Exception ex) {
132: inPageRequest.putPageValue("error",
133: "Invalid search input. "
134: + URLUtilities.xmlEscape(fullq));
135: log.error(ex + " on " + fullq);
136: inQuery.putInput("error", "Invalid search "
137: + URLUtilities.xmlEscape(fullq));
138: }
139: } else {
140: loadHits(inPageRequest, hitsname, inCatalogId,
141: inSearchIndex);
142: }
143: }
144: return tracker;
145: }
146:
147: public HitTracker loadHits(WebPageRequest inReq, String hitsname,
148: String inCatalogId, BaseSearchIndex inSearchIndex)
149: throws OpenEditException {
150: HitTracker otracker = (HitTracker) inReq
151: .getSessionValue(hitsname + inCatalogId);
152:
153: HitTracker tracker = checkCurrent(otracker, inSearchIndex);
154: if (tracker != otracker) {
155: inReq.putSessionValue(hitsname + inCatalogId, tracker);
156: }
157: if (tracker != null) {
158: inReq.putPageValue(hitsname, tracker);
159: }
160: return tracker;
161:
162: }
163:
164: public HitTracker checkCurrent(HitTracker tracker,
165: BaseSearchIndex inSearchIndex) throws OpenEditException {
166: if (tracker != null) {
167: if (!tracker.getIndexId()
168: .equals(inSearchIndex.getIndexId())) {
169: int oldNum = tracker.getPage();
170: HitTracker tracker2 = inSearchIndex.search(tracker
171: .getQuery(), tracker.getOrdering());
172: tracker2.setPage(oldNum);
173: tracker2.setSearchQuery(tracker.getSearchQuery());
174: return tracker2;
175: }
176: }
177: return tracker;
178: }
179:
180: public LogArchive getLogArchive() {
181: return fieldLogArchive;
182: }
183:
184: public void setLogArchive(LogArchive inLogArchive) {
185: fieldLogArchive = inLogArchive;
186: }
187:
188: protected void logEntry(String inCatalogId, Change inChange) {
189: LogDirectory dir = getLogArchive().getLogDirectory(
190: inCatalogId + "_Search");
191: dir.addChange(inChange);
192: }
193:
194: public DateFormat getDefaultDateFormat() {
195: if (fieldDefaultDateFormat == null) {
196: fieldDefaultDateFormat = new SimpleDateFormat("MM/dd/yyyy");
197: }
198: return fieldDefaultDateFormat;
199: }
200:
201: public void setDefaultDateFormat(DateFormat inDefaultDateFormat) {
202: fieldDefaultDateFormat = inDefaultDateFormat;
203: }
204:
205: protected HitTracker search(WebPageRequest inPageRequest,
206: SearchQuery search, String inCatalogId,
207: BaseSearchIndex inIndex) throws OpenEditException {
208: String defaultjoin = inPageRequest
209: .getRequestParameter("defaultjoin");
210: if (defaultjoin != null) {
211: boolean andall = Boolean.parseBoolean(defaultjoin);
212: search.setAndTogether(andall);
213: search.putInput("defaultjoin", defaultjoin);
214: }
215: String sort = inPageRequest.getRequestParameter("sortby");
216: if (sort != null) {
217: search.setSortBy(sort);
218: }
219:
220: return cachedSearch(inPageRequest, search, inCatalogId, inIndex);
221: }
222:
223: public SearchQuery addStandardSearchTerms(
224: WebPageRequest inPageRequest, FieldArchive inFieldArchive)
225: throws OpenEditException {
226: String[] fieldid = inPageRequest
227: .getRequestParameters("fieldid");
228: if (fieldid == null) {
229: return null;
230: }
231: String[] operations = inPageRequest
232: .getRequestParameters("operation");
233: // String[] values = inPageRequest.getRequestParameters("value");
234: // check the new naming convention for values (fieldid.value)
235: if (operations == null) {
236: return null;
237: }
238: String[] fields = inPageRequest.getRequestParameters("field");
239:
240: inPageRequest.removeSessionValue("crumb");
241:
242: SearchQuery search = new LuceneSearchQuery();
243:
244: DateFormat formater = null;
245: String dateFormat = inPageRequest
246: .getRequestParameter("dateformat");
247: if (dateFormat != null) {
248: formater = new SimpleDateFormat(dateFormat);
249: } else {
250: formater = getDefaultDateFormat(); // dateFormat = "MM/dd/yyyy";
251:
252: }
253: for (int i = 0; i < fieldid.length; i++) {
254: String field = fieldid[i];
255: String friendly = null;
256: if (fields != null) {
257: friendly = fields[i];
258: } else {
259: friendly = fieldid[i];
260: }
261: String val = inPageRequest.getRequestParameter(field
262: + ".value");
263:
264: search.putInput(field, val);
265: if (val != null && val.length() > 0) {
266: String op = operations[i];
267: if ("matches".equals(op)) {
268: search.addMatches(field, val, friendly);
269: } else if ("exact".equals(op)) {
270: search.addExact(field, val, friendly);
271: } else if ("startswith".equals(op)) {
272: search.addStartsWith(field, val, friendly);
273: } else if ("not".equals(op)) {
274: search.addNot(field, val, friendly);
275: } else {
276: addDate(inPageRequest, search, formater, field,
277: friendly, val, op);
278: addSelect(inPageRequest, inFieldArchive, search,
279: field, friendly, op);
280: }
281: }
282: }
283: return search;
284: }
285:
286: private void addSelect(WebPageRequest inPageRequest,
287: FieldArchive inFieldArchive, SearchQuery search,
288: String field, String friendly, String op)
289: throws OpenEditException {
290: if ("multiselect".equals(op)) {
291: String param = field + ".value";
292:
293: String[] select = inPageRequest.getRequestParameters(param);
294: if (select != null) {
295: List remaining = deselect(field, select, inFieldArchive);
296: for (int j = 0; j < remaining.size(); j++) {
297: search.addNot(field, (String) remaining.get(j),
298: friendly);
299: }
300: // search.addCategoryFilter(remaining, friendly);
301: }
302: } else if ("picker".equals(op)) {
303: String param = field + ".value";
304:
305: String[] select = inPageRequest.getRequestParameters(param);
306: if (select != null) {
307: SearchQuery or = new LuceneSearchQuery();
308: or.setAndTogether(false);
309: for (int j = 0; j < select.length; j++) {
310: or.addMatches(field, select[j], friendly);
311: }
312: //String query = field + ":(" + or.toQuery() + ")";
313:
314: search.addQuery(field, or.toQuery(), friendly);
315: search.putInput("picker." + param, select);
316: }
317: }
318: }
319:
320: private void addDate(WebPageRequest inPageRequest,
321: SearchQuery search, DateFormat formater, String field,
322: String friendly, String val, String op)
323: throws OpenEditException {
324: try {
325: if ("before".equals(op)) {
326: Date d = formater.parse(val);
327: search.addBefore(field, d, friendly);
328: search.putInput("datedirection" + field, "before");
329: } else if ("after".equals(op)) {
330: Date d = formater.parse(val);
331: search.addAfter(field, d, friendly);
332: search.putInput("datedirection" + field, "after");
333: } else if ("equals".equals(op)) {
334: Date d = formater.parse(val);
335: Calendar c = new GregorianCalendar();
336: Calendar c2 = new GregorianCalendar();
337:
338: c.setTime(d);
339: c2.setTime(d);
340:
341: c.add(Calendar.DAY_OF_YEAR, -1);
342: c2.add(Calendar.DAY_OF_YEAR, 1);
343:
344: search.addBetween(field, c.getTime(), c2.getTime(),
345: "equals");
346:
347: }
348:
349: else if ("betweendates".equals(op)) {
350: String beforeString = inPageRequest
351: .getRequestParameter(field + ".before");
352: String afterString = inPageRequest
353: .getRequestParameter(field + ".after");
354:
355: if (beforeString == null && afterString == null) {
356:
357: } else if (beforeString == null) {
358: Date after = formater.parse(afterString);
359: search.addAfter(field, after, friendly);
360: search.putInput(field + ".after", beforeString);
361:
362: } else if (afterString == null) {
363: Date before = formater.parse(beforeString);
364: search.addBefore(field, before, friendly);
365: search.putInput(field + ".before", beforeString);
366: } else {
367: Date before = formater.parse(beforeString);
368: Date after = formater.parse(afterString);
369: search.addBetween(field, after, before, friendly);
370: search.putInput(field + ".before", beforeString);
371: search.putInput(field + ".after", afterString);
372: }
373: } else if ("betweenages".equals(op)) {
374: String beforeString = inPageRequest
375: .getRequestParameter(field + ".before");
376: String afterString = inPageRequest
377: .getRequestParameter(field + ".after");
378:
379: if (beforeString == null && afterString == null) {
380:
381: } else if (beforeString == null) {
382: Calendar rightNow = Calendar.getInstance();
383: int before = Integer.parseInt(afterString);
384: rightNow.add(Calendar.YEAR, (-1 * before));
385: Date after = rightNow.getTime();
386: search.addBefore(field, after, friendly);
387: search.putInput(field + ".after", afterString);
388:
389: } else if (afterString == null) {
390: Calendar rightNow = Calendar.getInstance();
391: int after = Integer.parseInt(beforeString);
392: rightNow.add(Calendar.YEAR, (-1 * after));
393: Date before = rightNow.getTime();
394: search.addAfter(field, before, friendly);
395: search.putInput(field + ".before", beforeString);
396: } else {
397: // before
398: Calendar rightNow = Calendar.getInstance();
399: int a = Integer.parseInt(afterString);
400: rightNow.add(Calendar.YEAR, (-1 * a));
401: Date before = rightNow.getTime();
402: // after
403: rightNow = Calendar.getInstance();
404: int b = Integer.parseInt(beforeString);
405: rightNow.add(Calendar.YEAR, (-1 * b));
406: Date after = rightNow.getTime();
407: // add search term
408: search.addBetween(field, after, before, friendly);
409: search.putInput(field + ".before", beforeString);
410: search.putInput(field + ".after", afterString);
411: }
412: }
413: } catch (ParseException ex) {
414: throw new OpenEditException(ex);
415: }
416: }
417:
418: /**
419: * Use this to automatically filter a search with the .xconf that declares the action.
420: * Example:
421: * <page-action name="OrderModule.getOrdersForUser">
422: * <not>
423: * <orderstatus>completed</orderstatus>
424: * </not>
425: * </page-action>
426: * @param inReq
427: * @param search
428: * @return
429: */
430:
431: public SearchQuery addActionFilters(WebPageRequest inReq,
432: SearchQuery search) {
433: Configuration config = inReq.getCurrentAction().getConfig();
434: Configuration matchesConfig = config.getChild("matches");
435: if (matchesConfig != null) {
436: for (Iterator iterator = matchesConfig.getChildren()
437: .iterator(); iterator.hasNext();) {
438: Configuration child = (Configuration) iterator.next();
439: String fieldName = child.getName();
440: String value = child.getValue();
441: search.addMatches(fieldName, value, fieldName);
442: search.putInput(fieldName, value); //The last one wins, only for matches
443: }
444: }
445: Configuration notConfig = config.getChild("not");
446: if (notConfig != null) {
447: for (Iterator iterator = notConfig.getChildren().iterator(); iterator
448: .hasNext();) {
449: Configuration child = (Configuration) iterator.next();
450: String fieldName = child.getName();
451: String value = child.getValue();
452: search.addNot(fieldName, value, fieldName);
453: }
454: }
455: return search;
456: }
457:
458: public HitTracker loadPageOfSearch(WebPageRequest inPageRequest,
459: String inCategoryId, BaseSearchIndex inIndex)
460: throws OpenEditException {
461: String page = inPageRequest.getRequestParameter("page");
462:
463: if (page != null) {
464: String hitsname = inPageRequest.findValue("hitsname");
465: if (hitsname == null) {
466: hitsname = "hits";
467: }
468: HitTracker tracker = loadHits(inPageRequest, hitsname,
469: inCategoryId, inIndex);
470: if (tracker != null) {
471: int jumpToPage = Integer.parseInt(page);
472: if (jumpToPage <= tracker.getTotalPages()
473: && jumpToPage > 0) {
474: tracker.setPage(jumpToPage);
475: } else {
476: tracker.setPage(1);
477: }
478: return tracker;
479: } else {
480: log.error("No search found to turn page on "
481: + inPageRequest.getPathUrl());
482: }
483: }
484: return null;
485: }
486:
487: protected void changeSort(WebPageRequest inReq,
488: BaseLuceneSearch search, String sort, String hitsname,
489: String catalogid) throws OpenEditException {
490: HitTracker hits = loadHits(inReq, hitsname, catalogid, search);
491:
492: if (hits != null) {
493: SearchQuery group = hits.getSearchQuery();
494: group.setSortBy(sort);
495: hits.setIndexId(hits.getIndexId() + sort); //Causes the hits to be reloaded
496: // inReq.removeSessionValue("hits");
497: cachedSearch(inReq, group, catalogid, search);
498: }
499: }
500:
501: }
|