/******************************************************************************* * Imixs Workflow * Copyright (C) 2001, 2011 Imixs Software Solutions GmbH, * http://www.imixs.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You can receive a copy of the GNU General Public * License at http://www.gnu.org/licenses/gpl.html * * Project: * http://www.imixs.org * http://java.net/projects/imixs-workflow * * Contributors: * Imixs Software Solutions GmbH - initial API and implementation * Ralph Soika - Software Developer *******************************************************************************/ package org.imixs.marty.view; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.enterprise.context.SessionScoped; import javax.enterprise.event.Observes; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.faces.event.AjaxBehaviorEvent; import javax.inject.Inject; import javax.inject.Named; import org.imixs.marty.config.SetupController; import org.imixs.marty.workflow.WorkflowEvent; import org.imixs.workflow.ItemCollection; import org.imixs.workflow.engine.lucene.LuceneSearchService; import org.imixs.workflow.exceptions.QueryException; /** * The Marty SearchController extends the Imixs ViewController and provides * custom filter and search queries to request a individual WorkList result. The * ItemCollection search filter defines custom filter criteria for a customized * search result. * * To customize the result an alternative CDI IQueryBuilder bean an be injected. * * * The SearchController has a set of predefined filter properties: * * <ul> * <li>txtProcessRef = holds a reference to a core process entity</li> * <li>txtSpaceRef = holds a list of project references</li> * </ul> * * @See QueryBuilder, IQueryBuilder * @author rsoika * @version 2.2.0 */ @Named("searchController") @SessionScoped public class SearchController extends org.imixs.workflow.faces.workitem.ViewController implements Serializable { private static final long serialVersionUID = 1L; private static Logger logger = Logger.getLogger(SearchController.class.getName()); private ItemCollection searchFilter = null; @Inject SetupController setupController; /** * This method set the sort order and sort criteria * **/ @PostConstruct public void init() { this.setSortBy(setupController.getSortBy()); this.setSortReverse(setupController.getSortReverse()); } /** * Resets the search filter and the current result. * * @param event */ @Override public void doReset(ActionEvent event) { searchFilter = new ItemCollection(); searchFilter.replaceItemValue("type", "workitem"); super.doReset(event); } @Override public void doReset() { searchFilter = new ItemCollection(); searchFilter.replaceItemValue("type", "workitem"); super.doReset(); } /** * resets the current result and set the page pointer to 0. The searchFilter * will not be reset. * * @return */ public void doResetSearchResult() { super.doReset(); } /** * Refresh the result and reset the filter "$processid". * * This method is called by the SelectBox for WorkflowGroup to reset old * $processID * * Reset paging to 0 * * @param event */ public void doRefreshWorkflowGroup(AjaxBehaviorEvent event) { getSearchFilter().removeItem("$processid"); doResetSearchResult(); } /** * Resets the search filter but not the search phrase (txtSearch) The method * reset the current result. * * @param event */ public void doResetFilter(ActionEvent event) { String searchPhrase = searchFilter.getItemValueString("txtSearch"); searchFilter = new ItemCollection(); searchFilter.replaceItemValue("type", "workitem"); super.doReset(event); // restore search phrase searchFilter.replaceItemValue("txtSearch", searchPhrase); } /** * Triggers a lucene search based on a search phrase. The search phrase is * stored in the search filter property 'txtSearch' which is evaluated by * the IQueryBuilder. * * @param phrase * - search phrase * @param action * - jsf navigation action */ public String search(String phrase, String action) { searchFilter.replaceItemValue("txtSearch", phrase); return action; } /** * WorkflowEvent listener listens to WORKITEM events and reset the result * list after changing a workitem. * * @param workflowEvent **/ public void onWorkflowEvent(@Observes WorkflowEvent workflowEvent) { if (workflowEvent == null || workflowEvent.getWorkitem() == null) { return; } // skip if not a workItem... if (!workflowEvent.getWorkitem().getItemValueString("type").startsWith("workitem")) return; if (WorkflowEvent.WORKITEM_AFTER_PROCESS == workflowEvent.getEventType()) { doRefresh(); } } public ItemCollection getSearchFilter() { if (searchFilter == null) searchFilter = new ItemCollection(); return searchFilter; } public void setSearchFilter(ItemCollection searchFilter) { this.searchFilter = searchFilter; } /** * Returns a Lucene search query based on the define searchFilter parameter * set * * Depending on the view type the method restricts the result set by * namcreator or namowner * * @param searchFilter * - ItemCollection with filter criteria * @param view * - WorkList View type - @see WorklistController * * @return - a lucene search query */ @SuppressWarnings("unchecked") @Override public String getQuery() { // read the filter parameters and removes duplicates List<Integer> processIDs = searchFilter.getItemValue("$ProcessID"); List<String> processRefList = searchFilter.getItemValue("txtProcessRef"); List<String> spacesRefList = searchFilter.getItemValue("txtSpaceRef"); List<String> workflowGroups = searchFilter.getItemValue("txtWorkflowGroup"); // trim lists while (processIDs.contains("")) processIDs.remove(""); while (processRefList.contains("")) processRefList.remove(""); while (spacesRefList.contains("")) spacesRefList.remove(""); while (workflowGroups.contains("")) workflowGroups.remove(""); while (processRefList.contains("-")) processRefList.remove("-"); while (spacesRefList.contains("-")) spacesRefList.remove("-"); List<String> typeList = searchFilter.getItemValue("Type"); if (typeList.isEmpty() || "".equals(typeList.get(0))) { //typeList = Arrays.asList(new String[] { "workitem", "workitemarchive" }); // default restrict to workitem typeList = Arrays.asList(new String[] { "workitem"}); } String sSearchTerm = ""; // convert type list into comma separated list String sTypeQuery = ""; Iterator<String> iterator = typeList.iterator(); while (iterator.hasNext()) { sTypeQuery += "type:\"" + iterator.next() + "\""; if (iterator.hasNext()) sTypeQuery += " OR "; } sSearchTerm += "(" + sTypeQuery + ") AND"; // test if dms_search==true if ("true".equals(searchFilter.getItemValueString("dms_search"))) { sSearchTerm += " (dms_count:[1 TO 99]) AND"; } // test if result should be restricted to creator? String sCreator = searchFilter.getItemValueString("namCreator"); // test if result should be restricted to owner? String sOwner = searchFilter.getItemValueString("namOwner"); Date datFrom = searchFilter.getItemValueDate("datFrom"); Date datTo = searchFilter.getItemValueDate("datTo"); // process ref if (!processRefList.isEmpty()) { sSearchTerm += " ("; iterator = processRefList.iterator(); while (iterator.hasNext()) { sSearchTerm += "$uniqueidref:\"" + iterator.next() + "\""; if (iterator.hasNext()) sSearchTerm += " OR "; } sSearchTerm += " ) AND"; } // Space ref if (!spacesRefList.isEmpty()) { sSearchTerm += " ("; iterator = spacesRefList.iterator(); while (iterator.hasNext()) { sSearchTerm += "$uniqueidref:\"" + iterator.next() + "\""; if (iterator.hasNext()) sSearchTerm += " OR "; } sSearchTerm += " ) AND"; } // Workflow Group... if (!workflowGroups.isEmpty()) { sSearchTerm += " ("; iterator = workflowGroups.iterator(); while (iterator.hasNext()) { sSearchTerm += "txtworkflowgroup:\"" + iterator.next() + "\""; if (iterator.hasNext()) sSearchTerm += " OR "; } sSearchTerm += " ) AND"; } // serach date range? String sDateFrom = "191401070000"; // because * did not work here String sDateTo = "211401070000"; SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm"); if (datFrom != null) { Calendar cal = Calendar.getInstance(); cal.setTime(datFrom); sDateFrom = dateformat.format(cal.getTime()); } if (datTo != null) { Calendar cal = Calendar.getInstance(); cal.setTime(datTo); cal.add(Calendar.DATE, 1); sDateTo = dateformat.format(cal.getTime()); } if (datFrom != null || datTo != null) { // expected format $created:[20020101 TO 20030101] sSearchTerm += " ($created:[" + sDateFrom + " TO " + sDateTo + "]) AND"; } // creator if (!"".equals(sCreator)) { sSearchTerm += " (namcreator:\"" + sCreator.toLowerCase() + "\") AND"; } // owner if (!"".equals(sCreator)) { sSearchTerm += " (namowner:\"" + sOwner.toLowerCase() + "\") AND"; } if (!processIDs.isEmpty()) { sSearchTerm += " ("; Iterator<Integer> iteratorID = processIDs.iterator(); while (iteratorID.hasNext()) { sSearchTerm += "$processid:\"" + iteratorID.next() + "\""; if (iteratorID.hasNext()) sSearchTerm += " OR "; } sSearchTerm += " ) AND"; } // Search phrase.... String searchphrase = searchFilter.getItemValueString("txtSearch"); // escape search phrase try { searchphrase = LuceneSearchService.normalizeSearchTerm(searchphrase); } catch (QueryException e) { // add a new FacesMessage into the FacesContext FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, e.getLocalizedMessage(), null); FacesContext.getCurrentInstance().addMessage(null, facesMessage); return null; } if (searchphrase != null && !"".equals(searchphrase)) { // trim searchphrase = searchphrase.trim(); // lower case.... searchphrase = searchphrase.toLowerCase(); sSearchTerm += " (" + searchphrase + ") "; } else // cut last AND if (sSearchTerm.endsWith("AND")) sSearchTerm = sSearchTerm.substring(0, sSearchTerm.length() - 3); logger.fine("Query=" + sSearchTerm); return sSearchTerm; } }