001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.docsearch;
018:
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.Collections;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.StringTokenizer;
027:
028: import edu.iu.uis.eden.KEWServiceLocator;
029: import edu.iu.uis.eden.WorkflowServiceError;
030: import edu.iu.uis.eden.WorkflowServiceErrorException;
031: import edu.iu.uis.eden.WorkflowServiceErrorImpl;
032: import edu.iu.uis.eden.docsearch.dao.DocumentSearchDAO;
033: import edu.iu.uis.eden.doctype.DocumentType;
034: import edu.iu.uis.eden.doctype.DocumentTypeService;
035: import edu.iu.uis.eden.engine.node.RouteNode;
036: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
037: import edu.iu.uis.eden.lookupable.Field;
038: import edu.iu.uis.eden.lookupable.Row;
039: import edu.iu.uis.eden.user.AuthenticationUserId;
040: import edu.iu.uis.eden.user.UserService;
041: import edu.iu.uis.eden.user.WorkflowUser;
042: import edu.iu.uis.eden.useroptions.UserOptions;
043: import edu.iu.uis.eden.useroptions.UserOptionsService;
044: import edu.iu.uis.eden.util.Utilities;
045: import edu.iu.uis.eden.web.KeyValue;
046: import edu.iu.uis.eden.workgroup.GroupNameId;
047: import edu.iu.uis.eden.workgroup.Workgroup;
048:
049: public class DocumentSearchServiceImpl implements DocumentSearchService {
050:
051: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
052: .getLogger(DocumentSearchServiceImpl.class);
053:
054: private static final int MAX_SEARCH_ITEMS = 5;
055: private static final String LAST_SEARCH_ORDER_OPTION = "DocSearch.LastSearch.Order";
056: private static final String NAMED_SEARCH_ORDER_BASE = "DocSearch.NamedSearch.";
057: private static final String LAST_SEARCH_BASE_NAME = "DocSearch.LastSearch.Holding";
058:
059: private DocumentSearchDAO docSearchDao;
060: private UserOptionsService userOptionsService;
061:
062: public void setDocumentSearchDAO(DocumentSearchDAO docSearchDao) {
063: this .docSearchDao = docSearchDao;
064: }
065:
066: public void setUserOptionsService(
067: UserOptionsService userOptionsService) {
068: this .userOptionsService = userOptionsService;
069: }
070:
071: public void clearNamedSearches(WorkflowUser user) {
072: String[] clearListNames = { NAMED_SEARCH_ORDER_BASE + "%",
073: LAST_SEARCH_BASE_NAME + "%",
074: LAST_SEARCH_ORDER_OPTION + "%" };
075: for (int i = 0; i < clearListNames.length; i++) {
076: List records = userOptionsService.findByUserQualified(user,
077: clearListNames[i]);
078: for (Iterator iter = records.iterator(); iter.hasNext();) {
079: userOptionsService.deleteUserOptions((UserOptions) iter
080: .next());
081: }
082: }
083: }
084:
085: public SavedSearchResult getSavedSearchResults(WorkflowUser user,
086: String savedSearchName) throws EdenUserNotFoundException {
087: UserOptions savedSearch = userOptionsService.findByOptionId(
088: savedSearchName, user);
089: if (savedSearch == null || savedSearch.getOptionId() == null) {
090: return null;
091: }
092: DocSearchCriteriaVO criteria = getCriteriaFromSavedSearch(savedSearch);
093: return new SavedSearchResult(criteria, getList(user, criteria));
094: }
095:
096: public DocumentSearchResultComponents getList(WorkflowUser user,
097: DocSearchCriteriaVO criteria)
098: throws EdenUserNotFoundException {
099: DocumentSearchGenerator docSearchGenerator = null;
100: DocumentSearchResultProcessor docSearchResultProcessor = null;
101: if (!Utilities.isEmpty(criteria.getDocTypeFullName())) {
102: DocumentType documentType = KEWServiceLocator
103: .getDocumentTypeService().findByName(
104: criteria.getDocTypeFullName());
105: if (documentType == null) {
106: String errorMsg = "Document Type '"
107: + criteria.getDocTypeFullName()
108: + "' is invalid";
109: LOG.error("getList() " + errorMsg
110: + " and not found via DocumentTypeService");
111: throw new WorkflowServiceErrorException(
112: errorMsg,
113: new WorkflowServiceErrorImpl(
114: errorMsg,
115: "docsearch.DocumentSearchService.generalError",
116: errorMsg));
117: }
118: docSearchGenerator = documentType
119: .getDocumentSearchGenerator();
120: docSearchResultProcessor = documentType
121: .getDocumentSearchResultProcessor();
122: } else {
123: docSearchGenerator = new StandardDocumentSearchGenerator();
124: docSearchResultProcessor = new StandardDocumentSearchResultProcessor();
125: }
126: docSearchGenerator.setSearchingUser(user);
127: performPreSearchConditions(docSearchGenerator, user, criteria);
128: validateDocumentSearchCriteria(docSearchGenerator, criteria);
129: DocumentSearchResultComponents searchResult = null;
130: try {
131: List docListResults = docSearchDao.getList(
132: docSearchGenerator, criteria);
133: searchResult = docSearchResultProcessor
134: .processIntoFinalResults(docListResults, criteria,
135: user);
136: } catch (Exception e) {
137: String errorMsg = "Error received trying to execute search: "
138: + e.getLocalizedMessage();
139: LOG.error("getList() " + errorMsg, e);
140: throw new WorkflowServiceErrorException(
141: errorMsg,
142: new WorkflowServiceErrorImpl(
143: errorMsg,
144: "docsearch.DocumentSearchService.generalError",
145: errorMsg));
146: }
147: try {
148: saveSearch(user, criteria);
149: } catch (RuntimeException e) {
150: // swallerin it, cuz we look to be read only
151: }
152: return searchResult;
153: }
154:
155: public void performPreSearchConditions(
156: DocumentSearchGenerator docSearchGenerator,
157: WorkflowUser user, DocSearchCriteriaVO criteria) {
158: List<WorkflowServiceError> errors = docSearchGenerator
159: .performPreSearchConditions(user, criteria);
160: if (!errors.isEmpty()) {
161: throw new WorkflowServiceErrorException(
162: "Document Search Precondition Errors", errors);
163: }
164: }
165:
166: public void validateDocumentSearchCriteria(
167: DocumentSearchGenerator docSearchGenerator,
168: DocSearchCriteriaVO criteria) {
169: List<WorkflowServiceError> errors = this
170: .validateWorkflowDocumentSearchCriteria(criteria);
171: errors.addAll(docSearchGenerator
172: .validateSearchableAttributes(criteria));
173: if (!errors.isEmpty()) {
174: throw new WorkflowServiceErrorException(
175: "Document Search Validation Errors", errors);
176: }
177: }
178:
179: protected List<WorkflowServiceError> validateWorkflowDocumentSearchCriteria(
180: DocSearchCriteriaVO criteria) {
181: List<WorkflowServiceError> errors = new ArrayList<WorkflowServiceError>();
182:
183: // validate the network id's
184: if (!validateNetworkId(criteria.getApprover())) {
185: errors
186: .add(new WorkflowServiceErrorImpl(
187: "Approver network id is invalid",
188: "docsearch.DocumentSearchService.networkid.approver"));
189: } else {
190: if (criteria.getApprover() != null
191: && !"".equals(criteria.getApprover().trim())) {
192: criteria.setApprover(criteria.getApprover().trim());
193: }
194: }
195: if (!validateNetworkId(criteria.getViewer())) {
196: errors
197: .add(new WorkflowServiceErrorImpl(
198: "Viewer network id is invalid",
199: "docsearch.DocumentSearchService.networkid.viewer"));
200: } else {
201: if (criteria.getViewer() != null
202: && !"".equals(criteria.getViewer().trim())) {
203: criteria.setViewer(criteria.getViewer().trim());
204: }
205: }
206: if (!validateNetworkId(criteria.getInitiator())) {
207: errors
208: .add(new WorkflowServiceErrorImpl(
209: "Initiator network id is invalid",
210: "docsearch.DocumentSearchService.networkid.initiator"));
211: } else {
212: if (criteria.getInitiator() != null
213: && !"".equals(criteria.getInitiator().trim())) {
214: criteria.setInitiator(criteria.getInitiator().trim());
215: }
216: }
217:
218: if (!validateWorkgroup(criteria.getWorkgroupViewerName())) {
219: errors
220: .add(new WorkflowServiceErrorImpl(
221: "Workgroup Viewer Name is not a workgroup",
222: "docsearch.DocumentSearchService.workgroup.viewer"));
223: } else {
224: if (!Utilities.isEmpty(criteria.getWorkgroupViewerName())) {
225: criteria.setWorkgroupViewerName(criteria
226: .getWorkgroupViewerName().trim());
227: }
228: }
229:
230: // validate any numbers
231: if (!validateNumber(criteria.getDocRouteNodeId())) {
232: errors.add(new WorkflowServiceErrorImpl(
233: "Non-numeric route level",
234: "docsearch.DocumentSearchService.routeLevel"));
235: } else {
236: if (criteria.getDocRouteNodeId() != null
237: && !"".equals(criteria.getDocRouteNodeId().trim())) {
238: criteria.setDocRouteNodeId(criteria.getDocRouteNodeId()
239: .trim());
240: }
241: }
242: if (!validateNumber(criteria.getDocVersion())) {
243: errors.add(new WorkflowServiceErrorImpl(
244: "Non-numeric document version",
245: "docsearch.DocumentSearchService.docVersion"));
246: } else {
247: if (criteria.getDocVersion() != null
248: && !"".equals(criteria.getDocVersion().trim())) {
249: criteria.setDocVersion(criteria.getDocVersion().trim());
250: }
251: }
252:
253: if (!validateNumber(criteria.getRouteHeaderId())) {
254: errors.add(new WorkflowServiceErrorImpl(
255: "Non-numeric document id",
256: "docsearch.DocumentSearchService.routeHeaderId"));
257: } else {
258: if (criteria.getRouteHeaderId() != null
259: && !"".equals(criteria.getRouteHeaderId().trim())) {
260: criteria.setRouteHeaderId(criteria.getRouteHeaderId()
261: .trim());
262: }
263: }
264:
265: // validate any dates
266: boolean compareDatePairs = true;
267: if (!validateDate(criteria.getFromDateCreated())) {
268: errors.add(new WorkflowServiceErrorImpl(
269: "Invalid create date",
270: "docsearch.DocumentSearchService.dateCreated"));
271: compareDatePairs = false;
272: } else {
273: if (criteria.getFromDateCreated() != null
274: && !"".equals(criteria.getFromDateCreated().trim())) {
275: criteria.setFromDateCreated(criteria
276: .getFromDateCreated().trim());
277: } else {
278: compareDatePairs = false;
279: }
280: }
281: if (!validateDate(criteria.getToDateCreated())) {
282: errors.add(new WorkflowServiceErrorImpl(
283: "Invalid create date",
284: "docsearch.DocumentSearchService.dateCreated"));
285: compareDatePairs = false;
286: } else {
287: if (criteria.getToDateCreated() != null
288: && !"".equals(criteria.getToDateCreated().trim())) {
289: criteria.setToDateCreated(criteria.getToDateCreated()
290: .trim());
291: } else {
292: compareDatePairs = false;
293: }
294: }
295: if (compareDatePairs) {
296: if (!checkDateRanges(criteria.getFromDateCreated(),
297: criteria.getToDateCreated())) {
298: errors
299: .add(new WorkflowServiceErrorImpl(
300: "Invalid create date range",
301: "docsearch.DocumentSearchService.dateCreatedRange"));
302: }
303: }
304: compareDatePairs = true;
305: if (!validateDate(criteria.getFromDateApproved())) {
306: errors.add(new WorkflowServiceErrorImpl(
307: "Invalid approved date",
308: "docsearch.DocumentSearchService.dateApproved"));
309: compareDatePairs = false;
310: } else {
311: if (criteria.getFromDateApproved() != null
312: && !""
313: .equals(criteria.getFromDateApproved()
314: .trim())) {
315: criteria.setFromDateApproved(criteria
316: .getFromDateApproved().trim());
317: } else {
318: compareDatePairs = false;
319: }
320: }
321: if (!validateDate(criteria.getToDateApproved())) {
322: errors.add(new WorkflowServiceErrorImpl(
323: "Invalid approved date",
324: "docsearch.DocumentSearchService.dateApproved"));
325: compareDatePairs = false;
326: } else {
327: if (criteria.getToDateApproved() != null
328: && !"".equals(criteria.getToDateApproved().trim())) {
329: criteria.setToDateApproved(criteria.getToDateApproved()
330: .trim());
331: } else {
332: compareDatePairs = false;
333: }
334: }
335: if (compareDatePairs) {
336: if (!checkDateRanges(criteria.getFromDateApproved(),
337: criteria.getToDateApproved())) {
338: errors
339: .add(new WorkflowServiceErrorImpl(
340: "Invalid approved date range",
341: "docsearch.DocumentSearchService.dateApprovedRange"));
342: }
343: }
344: compareDatePairs = true;
345: if (!validateDate(criteria.getFromDateFinalized())) {
346: errors.add(new WorkflowServiceErrorImpl(
347: "Invalid finalized date",
348: "docsearch.DocumentSearchService.dateFinalized"));
349: compareDatePairs = false;
350: } else {
351: if (criteria.getFromDateFinalized() != null
352: && !"".equals(criteria.getFromDateFinalized()
353: .trim())) {
354: criteria.setFromDateFinalized(criteria
355: .getFromDateFinalized().trim());
356: } else {
357: compareDatePairs = false;
358: }
359: }
360: if (!validateDate(criteria.getToDateFinalized())) {
361: errors.add(new WorkflowServiceErrorImpl(
362: "Invalid finalized date",
363: "docsearch.DocumentSearchService.dateFinalized"));
364: compareDatePairs = false;
365: } else {
366: if (criteria.getToDateFinalized() != null
367: && !"".equals(criteria.getToDateFinalized().trim())) {
368: criteria.setToDateFinalized(criteria
369: .getToDateFinalized().trim());
370: } else {
371: compareDatePairs = false;
372: }
373: }
374: if (compareDatePairs) {
375: if (!checkDateRanges(criteria.getFromDateFinalized(),
376: criteria.getToDateFinalized())) {
377: errors
378: .add(new WorkflowServiceErrorImpl(
379: "Invalid finalized date range",
380: "docsearch.DocumentSearchService.dateFinalizedRange"));
381: }
382: }
383: compareDatePairs = true;
384: if (!validateDate(criteria.getFromDateLastModified())) {
385: errors
386: .add(new WorkflowServiceErrorImpl(
387: "Invalid last modified date",
388: "docsearch.DocumentSearchService.dateLastModified"));
389: compareDatePairs = false;
390: } else {
391: if (criteria.getFromDateLastModified() != null
392: && !"".equals(criteria.getFromDateLastModified()
393: .trim())) {
394: criteria.setFromDateLastModified(criteria
395: .getFromDateLastModified().trim());
396: } else {
397: compareDatePairs = false;
398: }
399: }
400: if (!validateDate(criteria.getToDateLastModified())) {
401: errors
402: .add(new WorkflowServiceErrorImpl(
403: "Invalid last modified date",
404: "docsearch.DocumentSearchService.dateLastModified"));
405: compareDatePairs = false;
406: } else {
407: if (criteria.getToDateLastModified() != null
408: && !"".equals(criteria.getToDateLastModified()
409: .trim())) {
410: criteria.setToDateLastModified(criteria
411: .getToDateLastModified().trim());
412: } else {
413: compareDatePairs = false;
414: }
415: }
416: if (compareDatePairs) {
417: if (!checkDateRanges(criteria.getFromDateLastModified(),
418: criteria.getToDateLastModified())) {
419: errors
420: .add(new WorkflowServiceErrorImpl(
421: "Invalid last modified date range",
422: "docsearch.DocumentSearchService.dateLastModifiedRange"));
423: }
424: }
425: return errors;
426: }
427:
428: private boolean validateNetworkId(String networkId) {
429: if ((networkId == null) || networkId.trim().equals("")) {
430: return true;
431: }
432: try {
433: UserService userService = (UserService) KEWServiceLocator
434: .getService(KEWServiceLocator.USER_SERVICE);
435: userService.getWorkflowUser(new AuthenticationUserId(
436: networkId.trim()));
437: return true;
438: } catch (Exception ex) {
439: LOG.debug(ex, ex);
440: return false;
441: }
442: }
443:
444: private boolean validateDate(String date) {
445: return Utilities.validateDate(date, true);
446: }
447:
448: private boolean checkDateRanges(String fromDate, String toDate) {
449: return Utilities.checkDateRanges(fromDate, toDate);
450: }
451:
452: private boolean validateNumber(String integer) {
453: if ((integer == null) || integer.trim().equals("")) {
454: return true;
455: }
456: try {
457: new Long(integer.trim());
458: return true;
459: } catch (NumberFormatException ex) {
460: return false;
461: }
462: }
463:
464: private boolean validateWorkgroup(String workgroupName) {
465: if (Utilities.isEmpty(workgroupName)) {
466: return true;
467: }
468: Workgroup workgroup = KEWServiceLocator.getWorkgroupService()
469: .getWorkgroup(new GroupNameId(workgroupName.trim()));
470: return workgroup != null;
471: }
472:
473: public List getNamedSearches(WorkflowUser user) {
474: List namedSearches = userOptionsService.findByUserQualified(
475: user, NAMED_SEARCH_ORDER_BASE + "%");
476: List sortedNamedSearches = new ArrayList();
477: if (namedSearches != null && namedSearches.size() > 0) {
478: Collections.sort(namedSearches);
479: for (Iterator iter = namedSearches.iterator(); iter
480: .hasNext();) {
481: UserOptions namedSearch = (UserOptions) iter.next();
482: KeyValue keyValue = new KeyValue(namedSearch
483: .getOptionId(), namedSearch.getOptionId()
484: .substring(NAMED_SEARCH_ORDER_BASE.length(),
485: namedSearch.getOptionId().length()));
486: sortedNamedSearches.add(keyValue);
487: }
488: }
489: return sortedNamedSearches;
490: }
491:
492: public List getMostRecentSearches(WorkflowUser user) {
493: UserOptions order = userOptionsService.findByOptionId(
494: LAST_SEARCH_ORDER_OPTION, user);
495: List sortedMostRecentSearches = new ArrayList();
496: if (order != null && order.getOptionVal() != null
497: && !"".equals(order.getOptionVal())) {
498: List mostRecentSearches = userOptionsService
499: .findByUserQualified(user, LAST_SEARCH_BASE_NAME
500: + "%");
501: String[] ordered = order.getOptionVal().split(",");
502: for (int i = 0; i < ordered.length; i++) {
503: UserOptions matchingOption = null;
504: for (Iterator iter = mostRecentSearches.iterator(); iter
505: .hasNext();) {
506: UserOptions option = (UserOptions) iter.next();
507: if (ordered[i].equals(option.getOptionId())) {
508: matchingOption = option;
509: break;
510: }
511: }
512: if (matchingOption != null) {
513: try {
514: sortedMostRecentSearches
515: .add(new KeyValue(
516: ordered[i],
517: getCriteriaFromSavedSearch(
518: matchingOption)
519: .getDocumentSearchAbbreviatedString()));
520: } catch (Exception e) {
521: String errorMessage = "Error found atttempting to get 'recent search' using user (authentication id "
522: + user.getAuthenticationUserId()
523: + ") with option having id "
524: + matchingOption.getOptionId()
525: + " and value '"
526: + matchingOption.getOptionVal() + "'";
527: LOG.error("getMostRecentSearches() "
528: + errorMessage, e);
529: }
530: }
531: }
532: }
533: return sortedMostRecentSearches;
534: }
535:
536: private void saveSearch(WorkflowUser user,
537: DocSearchCriteriaVO criteria) {
538: StringBuffer savedSearchString = new StringBuffer();
539: savedSearchString.append(criteria.getAppDocId() == null
540: || "".equals(criteria.getAppDocId()) ? ""
541: : ",,appDocId=" + criteria.getAppDocId());
542: savedSearchString.append(criteria.getApprover() == null
543: || "".equals(criteria.getApprover()) ? ""
544: : ",,approver=" + criteria.getApprover());
545:
546: if (!Utilities.isEmpty(criteria.getDocRouteNodeId())
547: && !criteria.getDocRouteNodeId().equals("-1")) {
548: RouteNode routeNode = KEWServiceLocator
549: .getRouteNodeService().findRouteNodeById(
550: new Long(criteria.getDocRouteNodeId()));
551: savedSearchString.append(",,docRouteNodeId="
552: + routeNode.getRouteNodeId());
553: savedSearchString
554: .append(criteria.getDocRouteNodeLogic() == null
555: || "".equals(criteria
556: .getDocRouteNodeLogic()) ? ""
557: : ",,docRouteNodeLogic="
558: + criteria.getDocRouteNodeLogic());
559: }
560:
561: savedSearchString.append(criteria.getDocRouteStatus() == null
562: || "".equals(criteria.getDocRouteStatus()) ? ""
563: : ",,docRouteStatus=" + criteria.getDocRouteStatus());
564: savedSearchString.append(criteria.getDocTitle() == null
565: || "".equals(criteria.getDocTitle()) ? ""
566: : ",,docTitle=" + criteria.getDocTitle());
567: savedSearchString.append(criteria.getDocTypeFullName() == null
568: || "".equals(criteria.getDocTypeFullName()) ? ""
569: : ",,docTypeFullName=" + criteria.getDocTypeFullName());
570: savedSearchString.append(criteria.getDocVersion() == null
571: || "".equals(criteria.getDocVersion()) ? ""
572: : ",,docVersion=" + criteria.getDocVersion());
573: savedSearchString.append(criteria.getFromDateApproved() == null
574: || "".equals(criteria.getFromDateApproved()) ? ""
575: : ",,fromDateApproved="
576: + criteria.getFromDateApproved());
577: savedSearchString.append(criteria.getFromDateCreated() == null
578: || "".equals(criteria.getFromDateCreated()) ? ""
579: : ",,fromDateCreated=" + criteria.getFromDateCreated());
580: savedSearchString
581: .append(criteria.getFromDateFinalized() == null
582: || "".equals(criteria.getFromDateFinalized()) ? ""
583: : ",,fromDateFinalized="
584: + criteria.getFromDateFinalized());
585: savedSearchString
586: .append(criteria.getFromDateLastModified() == null
587: || ""
588: .equals(criteria
589: .getFromDateLastModified()) ? ""
590: : ",,fromDateLastModified="
591: + criteria.getFromDateLastModified());
592: savedSearchString.append(criteria.getInitiator() == null
593: || "".equals(criteria.getInitiator()) ? ""
594: : ",,initiator=" + criteria.getInitiator());
595: savedSearchString.append(criteria.getOverrideInd() == null
596: || "".equals(criteria.getOverrideInd()) ? ""
597: : ",,overrideInd=" + criteria.getOverrideInd());
598: savedSearchString.append(criteria.getRouteHeaderId() == null
599: || "".equals(criteria.getRouteHeaderId()) ? ""
600: : ",,routeHeaderId=" + criteria.getRouteHeaderId());
601: savedSearchString.append(criteria.getToDateApproved() == null
602: || "".equals(criteria.getToDateApproved()) ? ""
603: : ",,toDateApproved=" + criteria.getToDateApproved());
604: savedSearchString.append(criteria.getToDateCreated() == null
605: || "".equals(criteria.getToDateCreated()) ? ""
606: : ",,toDateCreated=" + criteria.getToDateCreated());
607: savedSearchString.append(criteria.getToDateFinalized() == null
608: || "".equals(criteria.getToDateFinalized()) ? ""
609: : ",,toDateFinalized=" + criteria.getToDateFinalized());
610: savedSearchString
611: .append(criteria.getToDateLastModified() == null
612: || "".equals(criteria.getToDateLastModified()) ? ""
613: : ",,toDateLastModified="
614: + criteria.getToDateLastModified());
615: savedSearchString.append(criteria.getViewer() == null
616: || "".equals(criteria.getViewer()) ? "" : ",,viewer="
617: + criteria.getViewer());
618: savedSearchString
619: .append(criteria.getWorkgroupViewerName() == null
620: || "".equals(criteria.getWorkgroupViewerName()) ? ""
621: : ",,workgroupViewerName="
622: + criteria.getWorkgroupViewerName());
623: savedSearchString.append(criteria.getNamedSearch() == null
624: || "".equals(criteria.getNamedSearch()) ? ""
625: : ",,namedSearch=" + criteria.getNamedSearch());
626: savedSearchString.append(criteria.getSearchableAttributes()
627: .isEmpty() ? "" : ",,searchableAttributes="
628: + buildSearchableAttributeString(criteria
629: .getSearchableAttributes()));
630:
631: if (savedSearchString.toString() != null
632: && !"".equals(savedSearchString.toString().trim())) {
633:
634: savedSearchString
635: .append(criteria.getDocRouteStatus() == null
636: || ""
637: .equals(criteria
638: .getIsAdvancedSearch()) ? ""
639: : ",,isAdvancedSearch="
640: + criteria.getIsAdvancedSearch());
641: savedSearchString
642: .append(criteria.getSuperUserSearch() == null
643: || "".equals(criteria.getSuperUserSearch()) ? ""
644: : ",,superUserSearch="
645: + criteria.getSuperUserSearch());
646:
647: if (criteria.getNamedSearch() != null
648: && !"".equals(criteria.getNamedSearch().trim())) {
649: userOptionsService.save(user, NAMED_SEARCH_ORDER_BASE
650: + criteria.getNamedSearch(), savedSearchString
651: .toString());
652: } else {
653: // first determine the current ordering
654: UserOptions searchOrder = userOptionsService
655: .findByOptionId(LAST_SEARCH_ORDER_OPTION, user);
656: if (searchOrder == null) {
657: userOptionsService.save(user, LAST_SEARCH_BASE_NAME
658: + "0", savedSearchString.toString());
659: userOptionsService.save(user,
660: LAST_SEARCH_ORDER_OPTION,
661: LAST_SEARCH_BASE_NAME + "0");
662: } else {
663: String[] currentOrder = searchOrder.getOptionVal()
664: .split(",");
665: if (currentOrder.length == MAX_SEARCH_ITEMS) {
666: String searchName = currentOrder[currentOrder.length - 1];
667: String[] newOrder = new String[MAX_SEARCH_ITEMS];
668: newOrder[0] = searchName;
669: for (int i = 0; i < currentOrder.length - 1; i++) {
670: newOrder[i + 1] = currentOrder[i];
671: }
672: String newSearchOrder = "";
673: for (int i = 0; i < newOrder.length; i++) {
674: if (!"".equals(newSearchOrder)) {
675: newSearchOrder += ",";
676: }
677: newSearchOrder += newOrder[i];
678: }
679: userOptionsService.save(user, searchName,
680: savedSearchString.toString());
681: userOptionsService.save(user,
682: LAST_SEARCH_ORDER_OPTION,
683: newSearchOrder);
684: } else {
685: // here we need to do a push so identify the highest used number which is from the
686: // first one in the array, and then add one to it, and push the rest back one
687: int absMax = 0;
688: for (int i = 0; i < currentOrder.length; i++) {
689: int current = new Integer(currentOrder[i]
690: .substring(LAST_SEARCH_BASE_NAME
691: .length(), currentOrder[i]
692: .length())).intValue();
693: if (current > absMax) {
694: absMax = current;
695: }
696: }
697:
698: String searchName = LAST_SEARCH_BASE_NAME
699: + ++absMax;
700: String[] newOrder = new String[currentOrder.length + 1];
701: newOrder[0] = searchName;
702: for (int i = 0; i < currentOrder.length; i++) {
703: newOrder[i + 1] = currentOrder[i];
704: }
705: String newSearchOrder = "";
706: for (int i = 0; i < newOrder.length; i++) {
707: if (!"".equals(newSearchOrder)) {
708: newSearchOrder += ",";
709: }
710: newSearchOrder += newOrder[i];
711: }
712: userOptionsService.save(user, searchName,
713: savedSearchString.toString());
714: userOptionsService.save(user,
715: LAST_SEARCH_ORDER_OPTION,
716: newSearchOrder);
717: }
718: }
719: }
720: }
721: }
722:
723: /**
724: * Build String of searchable attributes that can be saved with search criteria
725: *
726: * @param searchableAttributes
727: * searchable attributes to save
728: * @return String representation of searchable attributes
729: */
730: private String buildSearchableAttributeString(
731: List searchableAttributes) {
732: StringBuffer searchableAttributeBuffer = new StringBuffer();
733:
734: for (Iterator iterator = searchableAttributes.iterator(); iterator
735: .hasNext();) {
736: SearchAttributeCriteriaComponent component = (SearchAttributeCriteriaComponent) iterator
737: .next();
738: // the following code will remove quickfinder fields
739: if ((component.getFormKey() == null)
740: || (component.getValue() == null && (Utilities
741: .isEmpty(component.getValues())))) {
742: continue;
743: }
744:
745: if (component.getValue() != null) {
746: if (searchableAttributeBuffer.length() > 0) {
747: searchableAttributeBuffer.append(",");
748: }
749: searchableAttributeBuffer
750: .append(component.getFormKey());
751: searchableAttributeBuffer.append(":");
752: searchableAttributeBuffer.append(component.getValue());
753: } else if (!Utilities.isEmpty(component.getValues())) {
754: for (Iterator iter = component.getValues().iterator(); iter
755: .hasNext();) {
756: String value = (String) iter.next();
757: if (searchableAttributeBuffer.length() > 0) {
758: searchableAttributeBuffer.append(",");
759: }
760: searchableAttributeBuffer.append(component
761: .getFormKey());
762: searchableAttributeBuffer.append(":");
763: searchableAttributeBuffer.append(value);
764: }
765: } else {
766: throw new RuntimeException(
767: "Error occurred building searchable attribute string trying to find search attribute component value or values");
768: }
769: }
770:
771: return searchableAttributeBuffer.toString();
772: }
773:
774: /**
775: * Build List of searchable attributes from saved searchable attributes string
776: *
777: * @param searchableAttributeString
778: * String representation of searchable attributes
779: * @return searchable attributes list
780: */
781: private List buildSearchableAttributesFromString(
782: String searchableAttributeString, String documentTypeName) {
783: List searchableAttributes = new ArrayList();
784: Map criteriaComponentsByKey = new HashMap();
785:
786: if (!Utilities.isEmpty(documentTypeName)) {
787: DocumentType docType = ((DocumentTypeService) KEWServiceLocator
788: .getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE))
789: .findByName(documentTypeName);
790: if (docType == null) {
791: String errorMsg = "Cannot find document type for given name '"
792: + documentTypeName + "'";
793: LOG.error("buildSearchableAttributesFromString() "
794: + errorMsg);
795: throw new RuntimeException(errorMsg);
796: }
797: for (SearchableAttribute searchableAttribute : docType
798: .getSearchableAttributes()) {
799: for (Row row : searchableAttribute.getSearchingRows()) {
800: for (Field field : row.getFields()) {
801: SearchableAttributeValue searchableAttributeValue = DocSearchUtils
802: .getSearchableAttributeValueByDataTypeString(field
803: .getFieldDataType());
804: SearchAttributeCriteriaComponent sacc = new SearchAttributeCriteriaComponent(
805: field.getPropertyName(), null, field
806: .getSavablePropertyName(),
807: searchableAttributeValue);
808: sacc.setRangeSearch(field.isMemberOfRange());
809: sacc.setAllowWildcards(field
810: .isAllowingWildcards());
811: sacc.setAutoWildcardBeginning(field
812: .isAutoWildcardAtBeginning());
813: sacc.setAutoWildcardEnd(field
814: .isAutoWildcardAtEnding());
815: sacc.setCaseSensitive(field.isCaseSensitive());
816: sacc.setSearchInclusive(field.isInclusive());
817: sacc.setSearchable(field.isSearchable());
818: sacc
819: .setCanHoldMultipleValues(Field.MULTI_VALUE_FIELD_TYPES
820: .contains(field.getFieldType()));
821: criteriaComponentsByKey.put(field
822: .getPropertyName(), sacc);
823: }
824: }
825: }
826: }
827:
828: Map<String, List<String>> checkForMultiValueSearchableAttributes = new HashMap<String, List<String>>();
829: if ((searchableAttributeString != null)
830: && (searchableAttributeString.trim().length() > 0)) {
831: StringTokenizer tokenizer = new StringTokenizer(
832: searchableAttributeString, ",");
833: while (tokenizer.hasMoreTokens()) {
834: String searchableAttribute = tokenizer.nextToken();
835: int index = searchableAttribute.indexOf(":");
836: if (index != -1) {
837: String key = searchableAttribute
838: .substring(0, index);
839: // String savedKey = key;
840: // if (key.indexOf(SearchableAttribute.RANGE_LOWER_BOUND_PROPERTY_PREFIX) == 0) {
841: // savedKey = key.substring(SearchableAttribute.RANGE_LOWER_BOUND_PROPERTY_PREFIX.length());
842: // } else if (key.indexOf(SearchableAttribute.RANGE_UPPER_BOUND_PROPERTY_PREFIX) == 0) {
843: // savedKey = key.substring(SearchableAttribute.RANGE_UPPER_BOUND_PROPERTY_PREFIX.length());
844: // }
845: String value = searchableAttribute
846: .substring(index + 1);
847: SearchAttributeCriteriaComponent critComponent = (SearchAttributeCriteriaComponent) criteriaComponentsByKey
848: .get(key);
849: if (critComponent == null) {
850: // here we potentially have a change to the searchable attributes dealing with naming or ranges... so we just ignore the values
851: continue;
852: }
853: if (critComponent.getSearchableAttributeValue() == null) {
854: String errorMsg = "Cannot find SearchableAttributeValue for given key '"
855: + key + "'";
856: LOG
857: .error("buildSearchableAttributesFromString() "
858: + errorMsg);
859: throw new RuntimeException(errorMsg);
860: }
861: if (critComponent.isCanHoldMultipleValues()) {
862: // should be multivalue
863: if (checkForMultiValueSearchableAttributes
864: .containsKey(key)) {
865: List<String> keyList = checkForMultiValueSearchableAttributes
866: .get(key);
867: keyList.add(value);
868: checkForMultiValueSearchableAttributes.put(
869: key, keyList);
870: } else {
871: List<String> tempList = new ArrayList<String>();
872: tempList.add(value);
873: // tempList.addAll(Arrays.asList(new String[]{value}));
874: checkForMultiValueSearchableAttributes.put(
875: key, tempList);
876: searchableAttributes.add(critComponent);
877: }
878: } else {
879: // should be single value
880: if (checkForMultiValueSearchableAttributes
881: .containsKey(key)) {
882: // attempting to use multiple values in a field that does not support it
883: String error = "Attempting to add multiple values to a search attribute (key: '"
884: + key
885: + "') that does not suppor them";
886: LOG
887: .error("buildSearchableAttributesFromString() "
888: + error);
889: // we don't blow chunks here in case an attribute has been altered from multi-value to non-multi-value
890: }
891: critComponent.setValue(value);
892: searchableAttributes.add(critComponent);
893: }
894:
895: }
896: }
897: for (Iterator iter = searchableAttributes.iterator(); iter
898: .hasNext();) {
899: SearchAttributeCriteriaComponent criteriaComponent = (SearchAttributeCriteriaComponent) iter
900: .next();
901: if (criteriaComponent.isCanHoldMultipleValues()) {
902: List values = (List) checkForMultiValueSearchableAttributes
903: .get(criteriaComponent.getFormKey());
904: criteriaComponent.setValue(null);
905: criteriaComponent.setValues(values);
906: }
907: }
908: }
909:
910: return searchableAttributes;
911: }
912:
913: private DocSearchCriteriaVO getCriteriaFromSavedSearch(
914: UserOptions savedSearch) {
915: DocSearchCriteriaVO criteria = new DocSearchCriteriaVO();
916: if (savedSearch != null) {
917: criteria.setAppDocId(getOptionCriteriaField(savedSearch,
918: "appDocId"));
919: criteria.setApprover(getOptionCriteriaField(savedSearch,
920: "approver"));
921: criteria.setDocRouteNodeId(getOptionCriteriaField(
922: savedSearch, "docRouteNodeId"));
923: if (criteria.getDocRouteNodeId() != null) {
924: criteria.setDocRouteNodeLogic(getOptionCriteriaField(
925: savedSearch, "docRouteNodeLogic"));
926: }
927: criteria.setIsAdvancedSearch(getOptionCriteriaField(
928: savedSearch, "isAdvancedSearch"));
929: criteria.setSuperUserSearch(getOptionCriteriaField(
930: savedSearch, "superUserSearch"));
931: criteria.setDocRouteStatus(getOptionCriteriaField(
932: savedSearch, "docRouteStatus"));
933: criteria.setDocTitle(getOptionCriteriaField(savedSearch,
934: "docTitle"));
935: criteria.setDocTypeFullName(getOptionCriteriaField(
936: savedSearch, "docTypeFullName"));
937: criteria.setDocVersion(getOptionCriteriaField(savedSearch,
938: "docVersion"));
939: criteria.setFromDateApproved(getOptionCriteriaField(
940: savedSearch, "fromDateApproved"));
941: criteria.setFromDateCreated(getOptionCriteriaField(
942: savedSearch, "fromDateCreated"));
943: criteria.setFromDateFinalized(getOptionCriteriaField(
944: savedSearch, "fromDateFinalized"));
945: criteria.setFromDateLastModified(getOptionCriteriaField(
946: savedSearch, "fromDateLastModified"));
947: criteria.setInitiator(getOptionCriteriaField(savedSearch,
948: "initiator"));
949: criteria.setOverrideInd(getOptionCriteriaField(savedSearch,
950: "overrideInd"));
951: criteria.setRouteHeaderId(getOptionCriteriaField(
952: savedSearch, "routeHeaderId"));
953: criteria.setToDateApproved(getOptionCriteriaField(
954: savedSearch, "toDateApproved"));
955: criteria.setToDateCreated(getOptionCriteriaField(
956: savedSearch, "toDateCreated"));
957: criteria.setToDateFinalized(getOptionCriteriaField(
958: savedSearch, "toDateFinalized"));
959: criteria.setToDateLastModified(getOptionCriteriaField(
960: savedSearch, "toDateLastModified"));
961: criteria.setViewer(getOptionCriteriaField(savedSearch,
962: "viewer"));
963: criteria.setWorkgroupViewerName(getOptionCriteriaField(
964: savedSearch, "workgroupViewerName"));
965: criteria.setNamedSearch(getOptionCriteriaField(savedSearch,
966: "namedSearch"));
967: criteria
968: .setSearchableAttributes(buildSearchableAttributesFromString(
969: getOptionCriteriaField(savedSearch,
970: "searchableAttributes"), criteria
971: .getDocTypeFullName()));
972: }
973: return criteria;
974: }
975:
976: private String getOptionCriteriaField(UserOptions userOption,
977: String fieldName) {
978: String value = userOption.getOptionVal();
979: if (value != null) {
980: String[] fields = value.split(",,");
981: for (int i = 0; i < fields.length; i++) {
982: if (fields[i].startsWith(fieldName + "=")) {
983: return new String(fields[i].substring(fields[i]
984: .indexOf(fieldName)
985: + fieldName.length() + 1, fields[i]
986: .length()));
987: }
988: }
989: }
990: return null;
991: }
992:
993: }
|