001: /*
002: * Copyright 2005-2006 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.web;
018:
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.HashMap;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import org.apache.commons.lang.StringUtils;
029: import org.apache.struts.action.ActionForm;
030:
031: import edu.iu.uis.eden.EdenConstants;
032: import edu.iu.uis.eden.KEWServiceLocator;
033: import edu.iu.uis.eden.docsearch.DocSearchCriteriaVO;
034: import edu.iu.uis.eden.docsearch.DocSearchUtils;
035: import edu.iu.uis.eden.docsearch.SavedSearchResult;
036: import edu.iu.uis.eden.docsearch.SearchAttributeCriteriaComponent;
037: import edu.iu.uis.eden.docsearch.SearchableAttribute;
038: import edu.iu.uis.eden.docsearch.SearchableAttributeValue;
039: import edu.iu.uis.eden.doctype.DocumentType;
040: import edu.iu.uis.eden.doctype.DocumentTypeService;
041: import edu.iu.uis.eden.lookupable.Column;
042: import edu.iu.uis.eden.lookupable.Field;
043: import edu.iu.uis.eden.lookupable.Row;
044: import edu.iu.uis.eden.util.Utilities;
045:
046: /**
047: * Struts form for document search action
048: *
049: * @author rkirkend
050: */
051: public class DocumentSearchForm extends ActionForm {
052:
053: private static final long serialVersionUID = 8680419749805107805L;
054: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
055: .getLogger(DocumentSearchForm.class);
056: private DocSearchCriteriaVO criteria = new DocSearchCriteriaVO();
057:
058: private String searchTarget;
059: private String searchIdValue;
060: private String searchLabelValue;
061: private String backIdPropName;
062: private String backLabelPropName;
063: private String backURL;
064: private String searchAction;
065: private String action;
066:
067: private String returnAction;
068: private String namedSearch = "";
069: private String lookupableImplServiceName;
070: private String conversionFields = "";
071: private String methodToCall = "";
072: private String quickFinderLookupable;
073: private String lookupType;
074: private List searchableAttributeRows;
075: private List searchableAttributeColumns;
076: private List propertyFields;
077:
078: public DocumentSearchForm() {
079: super ();
080: searchableAttributeRows = new ArrayList();
081: searchableAttributeColumns = new ArrayList();
082: propertyFields = new ArrayList();
083: }
084:
085: public DocSearchCriteriaVO getCriteria() {
086: return this .criteria;
087: }
088:
089: public void setDocTypeFullName(String docTypeFullName) {
090: criteria.setDocTypeFullName(docTypeFullName);
091: }
092:
093: public void clearSearchableAttributes() {
094: searchableAttributeRows = new ArrayList();
095: searchableAttributeColumns = new ArrayList();
096: propertyFields = new ArrayList();
097: }
098:
099: public void updateFormUsingSavedSearch(SavedSearchResult result) {
100: setCriteria(result.getDocSearchCriteriaVO());
101: clearSearchableAttributes();
102: checkForAdditionalFields();
103: setupPropertyFieldsUsingCriteria();
104: setNamedSearch("");
105: //TODO this is for historic reasons only and can be deleted after release 2.1
106: // but we need to check and notify that any user option saved search without a key containing 'isAdvancedSearch'
107: // will lose the search location context and will always be brought to the 'basic' search screen
108: //if ("".equals(getIsAdvancedSearch()) || "NO".equals(getIsAdvancedSearch())) {
109: // setIsAdvancedSearch(result.isAdvancedSearch() ? "YES" : "NO");
110: //}
111: }
112:
113: public void checkForAdditionalFields() {
114: DocumentType documentType = getDocumentType();
115: // String docTypeFullName = criteria.getDocTypeFullName();
116: if (documentType != null) {
117: List<SearchableAttribute> searchableAttributes = documentType
118: .getSearchableAttributes();
119: // we only want to initialize the searchable attribute fields, rows,
120: // and columns if this is the first time that they are being
121: // displayed
122: // on the form, therefore we check that each of the lists is empty.
123: // Originally, this code was clearing these lists out on every
124: // entry to the DocumentSearch screen which would only work in the
125: // case of a post of the entire form. In the case of lookups, this
126: // would result in the searchable attribute field values being
127: // cleared out, this fix resolves EN-122.
128: if (searchableAttributeRows.isEmpty()
129: && searchableAttributeColumns.isEmpty()
130: && propertyFields.isEmpty()) {
131: Set alreadyProcessedFieldKeys = new HashSet();
132: for (SearchableAttribute searchableAttribute : searchableAttributes) {
133: List<Row> searchRows = searchableAttribute
134: .getSearchingRows();
135: if (searchRows == null) {
136: continue;
137: }
138: for (Row row : searchRows) {
139: for (Field field : row.getFields()) {
140: if (!Utilities.isEmpty(field
141: .getPropertyName())) {
142: if (Field.MULTI_VALUE_FIELD_TYPES
143: .contains(field.getFieldType())) {
144: SearchAttributeFormContainer newFormContainer = new SearchAttributeFormContainer();
145: newFormContainer.setKey(field
146: .getPropertyName());
147: newFormContainer.setValues(field
148: .getPropertyValues());
149: propertyFields
150: .add(newFormContainer);
151: } else {
152: propertyFields
153: .add(new SearchAttributeFormContainer(
154: field
155: .getPropertyName(),
156: field
157: .getPropertyValue()));
158: }
159: }
160: // TODO delyea - check this... do we need it still?
161: if ((field.getSavablePropertyName() == null)
162: || (!alreadyProcessedFieldKeys
163: .contains(field
164: .getSavablePropertyName()))) {
165: if (field.isColumnVisible()) {
166: for (Iterator iter = Field.SEARCH_RESULT_DISPLAYABLE_FIELD_TYPES
167: .iterator(); iter.hasNext();) {
168: String displayableFieldType = (String) iter
169: .next();
170: if (field
171: .getFieldType()
172: .equals(
173: displayableFieldType)) {
174: searchableAttributeColumns
175: .add(new Column(
176: field
177: .getFieldLabel(),
178: Column.COLUMN_IS_SORTABLE_VALUE,
179: "searchableAttribute("
180: + field
181: .getSavablePropertyName()
182: + ").label"));
183: if (field
184: .getSavablePropertyName() != null) {
185: alreadyProcessedFieldKeys
186: .add(field
187: .getSavablePropertyName());
188: }
189: break;
190: }
191: }
192: }
193: }
194: }
195: searchableAttributeRows.add(row);
196: }
197: }
198: } else {
199: updateSearchableAttributeData(documentType,
200: searchableAttributes);
201: }
202: }
203: }
204:
205: /**
206: * Updates the field valid values since they aren't submitted with the form.
207: *
208: */
209: private void updateSearchableAttributeData(
210: DocumentType documentType,
211: List<SearchableAttribute> searchableAttributes) {
212: // searchableAttributeRows is a List containing rows from all attributes, so we need to keep a global row count
213: int totalRowIndex = 0;
214: for (SearchableAttribute searchableAttribute : searchableAttributes) {
215: List<Row> rows = searchableAttribute.getSearchingRows();
216: for (Row row : rows) {
217: Row existingRow = (Row) searchableAttributeRows
218: .get(totalRowIndex++);
219: int fieldIndex = 0;
220: for (Field field : row.getFields()) {
221: // get existing field
222: Field existingField = existingRow
223: .getField(fieldIndex++);
224: // now update the valid values
225: existingField.setFieldValidValues(field
226: .getFieldValidValues());
227: }
228: }
229: }
230:
231: }
232:
233: public void addSearchableAttributesToCriteria() {
234: DocumentType docType = getDocumentType();
235: if (docType == null) {
236: return;
237: }
238: if (!propertyFields.isEmpty()) {
239: Map criteriaComponentsByFormKey = new HashMap();
240: for (SearchableAttribute searchableAttribute : docType
241: .getSearchableAttributes()) {
242: for (Row row : searchableAttribute.getSearchingRows()) {
243: for (Field field : row.getFields()) {
244: SearchableAttributeValue searchableAttributeValue = DocSearchUtils
245: .getSearchableAttributeValueByDataTypeString(field
246: .getFieldDataType());
247: SearchAttributeCriteriaComponent sacc = new SearchAttributeCriteriaComponent(
248: field.getPropertyName(), null, field
249: .getSavablePropertyName(),
250: searchableAttributeValue);
251: sacc.setRangeSearch(field.isMemberOfRange());
252: sacc.setAllowWildcards(field
253: .isAllowingWildcards());
254: sacc.setAutoWildcardBeginning(field
255: .isAutoWildcardAtBeginning());
256: sacc.setAutoWildcardEnd(field
257: .isAutoWildcardAtEnding());
258: sacc.setCaseSensitive(field.isCaseSensitive());
259: sacc.setSearchInclusive(field.isInclusive());
260: sacc.setLookupableFieldType(field
261: .getFieldType());
262: sacc.setSearchable(field.isSearchable());
263: sacc
264: .setCanHoldMultipleValues(Field.MULTI_VALUE_FIELD_TYPES
265: .contains(field.getFieldType()));
266: criteriaComponentsByFormKey.put(field
267: .getPropertyName(), sacc);
268: }
269: }
270: }
271: for (Iterator iterator = propertyFields.iterator(); iterator
272: .hasNext();) {
273: SearchAttributeFormContainer propertyField = (SearchAttributeFormContainer) iterator
274: .next();
275: SearchAttributeCriteriaComponent sacc = (SearchAttributeCriteriaComponent) criteriaComponentsByFormKey
276: .get(propertyField.getKey());
277: if (sacc != null) {
278: if (sacc.getSearchableAttributeValue() == null) {
279: String errorMsg = "Searchable attribute with form field key "
280: + sacc.getFormKey()
281: + " does not have a valid SearchableAttributeValue";
282: LOG
283: .error("addSearchableAttributesToCriteria() "
284: + errorMsg);
285: throw new RuntimeException(errorMsg);
286: }
287: if ((Field.CHECKBOX_YES_NO.equals(sacc
288: .getLookupableFieldType()))
289: && (!propertyField.isValueSet())) {
290: // value was not set on the form so we must use the alternate value which for checkbox is the 'unchecked' value
291: sacc
292: .setValue(propertyField
293: .getAlternateValue());
294: } else if (Field.MULTI_VALUE_FIELD_TYPES
295: .contains(sacc.getLookupableFieldType())) {
296: sacc.setCanHoldMultipleValues(true);
297: if (propertyField.getValues() == null) {
298: sacc.setValues(new ArrayList<String>());
299: } else {
300: sacc.setValues(Arrays.asList(propertyField
301: .getValues()));
302: }
303: } else {
304: sacc.setValue(propertyField.getValue());
305: }
306: criteria.addSearchableAttribute(sacc);
307: }
308: }
309: }
310: }
311:
312: private void setupPropertyFieldsUsingCriteria() {
313: for (Iterator iter = criteria.getSearchableAttributes()
314: .iterator(); iter.hasNext();) {
315: SearchAttributeCriteriaComponent searchableAttribute = (SearchAttributeCriteriaComponent) iter
316: .next();
317: SearchAttributeFormContainer container = getPropertyField(searchableAttribute
318: .getFormKey());
319: if (container != null) {
320: container.setValue(searchableAttribute.getValue());
321: if (searchableAttribute.getValues() != null) {
322: container.setValues(searchableAttribute.getValues()
323: .toArray(
324: new String[searchableAttribute
325: .getValues().size()]));
326: }
327: }
328: }
329: }
330:
331: public String getDocTypeDisplayName() {
332: DocumentType docType = getDocumentType();
333: if (docType != null) {
334: return docType.getLabel();
335: }
336: return null;
337: }
338:
339: private DocumentType getDocumentType() {
340: if (criteria.getDocTypeFullName() != null
341: && !"".equals(criteria.getDocTypeFullName())) {
342: return ((DocumentTypeService) KEWServiceLocator
343: .getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE))
344: .findByName(criteria.getDocTypeFullName());
345: }
346: return null;
347: }
348:
349: public String getRouteLogPopup() {
350: return Utilities.getApplicationConstant(
351: EdenConstants.DOCUMENT_SEARCH_ROUTE_LOG_POPUP_KEY)
352: .trim();
353: }
354:
355: public String getDocumentPopup() {
356: return Utilities.getApplicationConstant(
357: EdenConstants.DOCUMENT_SEARCH_DOCUMENT_POPUP_KEY)
358: .trim();
359: }
360:
361: public void setInitiator(String initiator) {
362: criteria.setInitiator(initiator);
363: }
364:
365: public void setApprover(String approver) {
366: criteria.setApprover(approver);
367: }
368:
369: public void setViewer(String viewer) {
370: criteria.setViewer(viewer);
371: }
372:
373: public void setCriteria(DocSearchCriteriaVO criteria) {
374: // TODO JIRA KULOWF-254 - populate searchable attributes
375: this .criteria = criteria;
376: }
377:
378: /*
379: * the super user search methods used to live here but were moved to the crieteria so search
380: * context could be saved along with search data. I kept these methods here to minimize impact on jsp.
381: * Feel free to remove this call through methods and modify the jsp.
382: */
383: public String getSuperUserSearch() {
384: return criteria.getSuperUserSearch();
385: }
386:
387: public void setSuperUserSearch(String super UserSearch) {
388: this .criteria.setSuperUserSearch(super UserSearch);
389: }
390:
391: public void setSearchTarget(String searchTarget) {
392: this .searchTarget = searchTarget;
393: }
394:
395: public String getSearchTarget() {
396: return searchTarget;
397: }
398:
399: public void setSearchIdValue(String searchIdValue) {
400: this .searchIdValue = searchIdValue;
401: }
402:
403: public String getSearchIdValue() {
404: return searchIdValue;
405: }
406:
407: public void setSearchLabelValue(String searchLabelValue) {
408: this .searchLabelValue = searchLabelValue;
409: }
410:
411: public String getSearchLabelValue() {
412: return searchLabelValue;
413: }
414:
415: public void setBackIdPropName(String backIdPropName) {
416: this .backIdPropName = backIdPropName;
417: }
418:
419: public String getBackIdPropName() {
420: return backIdPropName;
421: }
422:
423: public void setBackLabelPropName(String backLabelPropName) {
424: this .backLabelPropName = backLabelPropName;
425: }
426:
427: public String getBackLabelPropName() {
428: return backLabelPropName;
429: }
430:
431: public void setBackURL(String backURL) {
432: this .backURL = backURL;
433: }
434:
435: public String getBackURL() {
436: return backURL;
437: }
438:
439: public void setSearchAction(String searchAction) {
440: this .searchAction = searchAction;
441: }
442:
443: public String getSearchAction() {
444: return searchAction;
445: }
446:
447: public void setAction(String action) {
448: this .action = action;
449: }
450:
451: public String getAction() {
452: return action;
453: }
454:
455: /*
456: * the IsAdvancedSearch methods used to live here but were moved to the crieteria so search
457: * context could be saved along with search data. I kept these methods here to minimize impact on jsp.
458: * Feel free to remove this call through methods and modify the jsp.
459: */
460: public String getIsAdvancedSearch() {
461: return criteria.getIsAdvancedSearch();
462: }
463:
464: public void setIsAdvancedSearch(String string) {
465: this .criteria.setIsAdvancedSearch(string);
466: }
467:
468: public String getReturnAction() {
469: return returnAction;
470: }
471:
472: public void setReturnAction(String returnAction) {
473: this .returnAction = returnAction;
474: }
475:
476: public void setFromDateCreated(String fromDateCreated) {
477: criteria.setFromDateCreated(fromDateCreated);
478: }
479:
480: public void setToDateCreated(String toDateCreated) {
481: criteria.setToDateCreated(toDateCreated);
482: }
483:
484: public String getFromDateCreated() {
485: return criteria.getFromDateCreated();
486: }
487:
488: public String getToDateCreated() {
489: return criteria.getToDateCreated();
490: }
491:
492: public void setFromDateLastModified(String fromDateLastModified) {
493: criteria.setFromDateLastModified(fromDateLastModified);
494: }
495:
496: public void setToDateLastModified(String toDateLastModified) {
497: criteria.setToDateLastModified(toDateLastModified);
498: }
499:
500: public String getFromDateLastModified() {
501: return criteria.getFromDateLastModified();
502: }
503:
504: public String getToDateLastModified() {
505: return criteria.getToDateLastModified();
506: }
507:
508: public void setFromDateApproved(String fromDateApproved) {
509: criteria.setFromDateApproved(fromDateApproved);
510: }
511:
512: public void setToDateApproved(String toDateApproved) {
513: criteria.setToDateApproved(toDateApproved);
514: }
515:
516: public String getFromDateApproved() {
517: return criteria.getFromDateApproved();
518: }
519:
520: public String getToDateApproved() {
521: return criteria.getToDateApproved();
522: }
523:
524: public void setFromDateFinalized(String fromDateFinalized) {
525: criteria.setFromDateFinalized(fromDateFinalized);
526: }
527:
528: public void setToDateFinalized(String toDateFinalized) {
529: criteria.setToDateFinalized(toDateFinalized);
530: }
531:
532: public String getFromDateFinalized() {
533: return criteria.getFromDateFinalized();
534: }
535:
536: public String getToDateFinalized() {
537: return criteria.getToDateFinalized();
538: }
539:
540: public String getNamedSearch() {
541: return namedSearch;
542: }
543:
544: public void setNamedSearch(String namedSearch) {
545: this .namedSearch = namedSearch;
546: }
547:
548: public String getLookupableImplServiceName() {
549: return lookupableImplServiceName;
550: }
551:
552: public void setLookupableImplServiceName(
553: String lookupableImplServiceName) {
554: this .lookupableImplServiceName = lookupableImplServiceName;
555: }
556:
557: /**
558: * @param conversionFields
559: * The conversionFields to set.
560: */
561: public void setConversionFields(String conversionFields) {
562: this .conversionFields = conversionFields;
563: }
564:
565: /**
566: * @return Returns the conversionFields.
567: */
568: public String getConversionFields() {
569: return conversionFields;
570: }
571:
572: public String getMethodToCall() {
573: return methodToCall;
574: }
575:
576: public void setMethodToCall(String methodToCall) {
577: this .methodToCall = methodToCall;
578: }
579:
580: public String getQuickFinderLookupable() {
581: return quickFinderLookupable;
582: }
583:
584: public void setQuickFinderLookupable(String quickFinderLookupable) {
585: this .quickFinderLookupable = quickFinderLookupable;
586: }
587:
588: public String getLookupType() {
589: return lookupType;
590: }
591:
592: public void setLookupType(String lookupType) {
593: this .lookupType = lookupType;
594: }
595:
596: /**
597: * @param searchableAttributeRows
598: * The searchableAttributeRows to set.
599: */
600: public void setSearchableAttributeRows(List searchableAttributeRows) {
601: this .searchableAttributeRows = searchableAttributeRows;
602: }
603:
604: /**
605: * @return Returns the searchableAttributeRows.
606: */
607: public List getSearchableAttributeRows() {
608: return searchableAttributeRows;
609: }
610:
611: public void addSearchableAttributeRow(Row row) {
612: searchableAttributeRows.add(row);
613: }
614:
615: public Row getSearchableAttributeRow(int index) {
616: while (getSearchableAttributeRows().size() <= index) {
617: Row row = new Row(new ArrayList());
618: getSearchableAttributeRows().add(row);
619: }
620: return (Row) getSearchableAttributeRows().get(index);
621: }
622:
623: public void setSearchableAttributeRow(int index, Row row) {
624: searchableAttributeRows.set(index, row);
625: }
626:
627: /**
628: * @param searchableAttributeColumns
629: * The searchableAttributeColumns to set.
630: */
631: public void setSearchableAttributeColumns(
632: List searchableAttributeColumns) {
633: this .searchableAttributeColumns = searchableAttributeColumns;
634: }
635:
636: /**
637: * @return Returns the searchableAttributeColumns.
638: */
639: public List getSearchableAttributeColumns() {
640: return searchableAttributeColumns;
641: }
642:
643: public void addSearchableAttributeColumn(Column column) {
644: searchableAttributeColumns.add(column);
645: }
646:
647: public Column getSearchableAttributeColumn(int index) {
648: while (getSearchableAttributeColumns().size() <= index) {
649: Column column = new Column("", "", "");
650: getSearchableAttributeColumns().add(column);
651: }
652: return (Column) getSearchableAttributeColumns().get(index);
653: }
654:
655: public void setSearchableAttributeColumn(int index, Column column) {
656: searchableAttributeColumns.set(index, column);
657: }
658:
659: /**
660: * @param propertyFields
661: * The propertyFields to set.
662: */
663: public void setPropertyFields(List propertyFields) {
664: this .propertyFields = propertyFields;
665: }
666:
667: /**
668: * @return Returns the propertyFields.
669: */
670: public List getPropertyFields() {
671: return propertyFields;
672: }
673:
674: public void addPropertyField(
675: SearchAttributeFormContainer attributeContainer) {
676: propertyFields.add(attributeContainer);
677: }
678:
679: public SearchAttributeFormContainer getPropertyField(int index) {
680: while (getPropertyFields().size() <= index) {
681: SearchAttributeFormContainer attributeContainer = new SearchAttributeFormContainer();
682: addPropertyField(attributeContainer);
683: }
684: return (SearchAttributeFormContainer) getPropertyFields().get(
685: index);
686: }
687:
688: public SearchAttributeFormContainer getPropertyField(String key) {
689: if (StringUtils.isBlank(key)) {
690: return null;
691: }
692: for (Iterator iter = propertyFields.iterator(); iter.hasNext();) {
693: SearchAttributeFormContainer container = (SearchAttributeFormContainer) iter
694: .next();
695: if (key.equals(container.getKey())) {
696: return container;
697: }
698: }
699: return null;
700: }
701:
702: public void setPropertyField(int index,
703: SearchAttributeFormContainer attributeContainer) {
704: propertyFields.set(index, attributeContainer);
705: }
706: }
|