mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
20884: Merged V3.3 to V3.3-BUG-FIX 20883: ALF-3604: Fix PersonTest 20881: Merged PATCHES/V3.2.r to V3.3 20880: ALF-3264: Fix up handling of default namespace. Workaround to JXPATH-61 20878: Merged V2.2 to V3.3 20474: Fix for ALF-1362 - encode group identifiers when used inside embedded param tags 20621: Fix for reopened ALF-1362 - UnknownAuthorityException when viewing/editing/deleting a user group with html entities in it's name 20874: Merged HEAD to V3.3 20873: ALF-3604: Correct case-sensitivity issues in LDAP sync - User names are now brought in line with the case of the LDAP directory during sync (in case the UID attribute is case sensitive) - User names are now compared according to Alfresco's case sensitivity setting - Group name comparisions are still case sensitive - Added unit test to ensure correct behaviour 20868: Merged PATCHES/V3.2.r to V3.3 20832: ALF-3264: XForms 'schema evolution': Remove nodes from XForms instance document with XPaths that don't occur in prototype document 20867: Merged PATCHES/V3.2.r to V3.3 (RECORD ONLY) 20833: Incremented version label 20688: Incremented version label 20687: Merged V3.3 to PATCHES/V3.2.r 20398: Fixed ALF-2890: Upgrade removes content if transaction retries are triggered - Setting ContentData that was derived outside of the current transaction opened up a window for the post-rollback code to delete the underlying binary. The binaries are only registered for writers fetched via the ContentService now; the low-level DAO no longer does management because it can't assume that a new content URL indicates a new underlying binary. - The contentUrlConverter was creating new URLs and thus the low-level DAO cleaned up live content when retrying collisions took place. The cleanup is no longer on the stack for the patch. - Removes the ALF-558 changes around ContentData.reference() 20590: Fixed ALF-3189: Oracle/DB2/SQLServer/PostgreSQL are missing indexes to support many FK constraints - Reverses rev 17421 - Added patchy bits to post-create script and declared patch - Patch only applies to *new* installations from 3.2.0 onwards (schema 3007 to 3400) 20686: ALF-3259: Merged HEAD to PATCHES/V3.2.r 19784: Fix for CIFS/CheckInOut.exe save of working copy breaks lock on original file. ALF-2028. 20866: Merged PATCHES/V3.2.1 to V3.3 (RECORD ONLY) 20840: Incremented version label 20839: ALF-3691: Merged V3.3-BUG-FIX to PATCHES/V3.2.1 20307: VersionStore - minor fixes if running deprecated V1 - warn in startup log - do not execute migration cleanup 20367: ALF-2829: Avoid reading entire result set into memory in FixNameCrcValuesPatch 20368: Work-around for ALF-2366: patch.updateDmPermissions takes too long to complete - this patch may now be deferred until 3.4 using the sample context (DM will use old permissions and AVM new as it did in 2.2.x) - this is only supported upgrading direct to 3.2.1.x 20370: Version Migrator (ALF-1000) - use common batch processor to enable multiple workers 20373: Version Migrator (ALF-1000) - resolve runtime conflict (w/ r20334) 20387: Version Migrator (ALF-1000) - approx x3 boost (policies ignore version2 store) 20431: Version Migrator (ALF-1000) - migrate 1st batch independently 20738:ALF-3617: Merged V3.3-BUG-FIX to PATCHES/V3.2.1 20438: ALF-479: Merged DEV/BELARUS/V3.2-2010_01_11 to DEV/V3.3-BUG-FIX 18448: ETHREEOH-4044: External Authentication Subsystem does not perform user mapping for WebDAV requests The changes listed in the bug comments have been made (and corrected). 20728: Incremented version label 20727: ALF-3617: Merged HEAD to PATCHES/V3.2.1 20616: ALF-2265: Share 'Uber Filter' part 2 - WebScriptNTLMAuthenticationFilter detached from its superclass and renamed to WebScriptSSOAuthenticationFilter - Now the filter simply chains to the downstream authentication filter rather than call its superclass - This means the same filter can be used for Kerberos-protected webscripts as well as NTLM - Wired globalAuthenticationFilter behind webscriptAuthenticationFilter in the filter chain in web.xml - Configured webscriptAuthenticationFilter for Kerberos subsystem 20612: Incremented version label 20610: Merged V3.3 to PATCHES/V3.2.1 20590: Fixed ALF-3189: Oracle/DB2/SQLServer/PostgreSQL are missing indexes to support many FK constraints - Reverses rev 17421 - Added patchy bits to post-create script and declared patch - Patch only applies to *new* installations from 3.2.0 onwards (schema 3007 to 3501) 20403: Merged V3.3 to PATCHES/V3.2.1 20398: Fixed ALF-2890: Upgrade removes content if transaction retries are triggered - Setting ContentData that was derived outside of the current transaction opened up a window for the post-rollback code to delete the underlying binary. The binaries are only registered for writers fetched via the ContentService now; the low-level DAO no longer does management because it can't assume that a new content URL indicates a new underlying binary. - The contentUrlConverter was creating new URLs and thus the low-level DAO cleaned up live content when retrying collisions took place. The cleanup is no longer on the stack for the patch. - Removes the ALF-558 changes around ContentData.reference() 20391: Incremented version label 20390: ALF-2966: Merged DEV/V3.3-BUG-FIX to PATCHES/V3.2.1 20388: Merged BRANCHES/DEV/BELARUS/HEAD-2010_04_28 to BRANCHES/DEV/V3.3-BUG-FIX: 20372: ALF-897: It is impossible to create content when default value selected in ContentHeadlineBackground field for intranet_rssi_landing_template web-form (also fixes ALF-2798 & ALF-791) 20371: ALF-2861: Merged V3.2 to PATCHES/V3.2.1 20028: Reverted (and fixed line endings) of log4j.properties 20027: Merged BRANCHES/V3.1 to BRANCHES/V3.2: 19983: Changes for ALF-2545: Cannot upgrade from 2.1.2a (b 209) to the 3.1.2 (.a3 458) on Oracle 20008: ALF-2351: Oracle upgrade scripts need enhancements from 2.2SP7 20362: ALF-2883: Merged HEAD to V3.2.1 19750: Fix for ALF-2310: alfresco-mmt-3.3dev.jar shows NoClassDefFoundError: org/safehaus/uuid/UUIDGenerator 20359: Merged PATCHES/V3.2.0 to PATCHES/V3.2.1 20349: Merged V3.3 to PATCHES/V3.2.0 20346: ALF-2839: Node pre-loading generates needless resultset rows - Added missing Criteria.list() call 20280: Fixed ALF-2839: Node pre-loading generates needless resultset rows - Split Criteria query to retrieve properties and aspects separately 20272: Backports to help fix ALF-2839: Node pre-loading generates needless resultset rows Merged BRANCHES/V3.2 to PATCHES/V3.2.0: 18490: Added cache for alf_content_data Merged BRANCHES/DEV/V3.3-BUG-FIX to PATCHES/V3.2.0: 20231: Fixed ALF-2784: Degradation of performance between 3.1.1 and 3.2x (observed in JSF) 20266: Test reproduction of ALF-2839 failure: Node pre-loading generates needless resultset rows 20358: Increment version label 20343: Incremented version label 20342: Merged V3.3 to PATCHES/V3.2.1 20322: Fixed ALF-1998: contentStoreCleanerJob leads to foreign key exception - Possible concurrent modification of alf_content_url.orphan_time led to false orphan detection - Fixed queries to check for dereferencing AND use the indexed orphan_time column - More robust use of EagerContentStoreCleaner: On eager cleanup, ensure that URLs are deleted - Added optimistic lock checks on updates and deletes of alf_content_url 20864: Merged PATCHES/V3.2.0 to V3.3 (RECORD ONLY) 20750: Merged V3.3 to PATCHES/V3.2.0 20590: Fixed ALF-3189: Oracle/DB2/SQLServer/PostgreSQL are missing indexes to support many FK constraints - Reverses rev 17421 - Added patchy bits to post-create script and declared patch - Patch only applies to *new* installations from 3.2.0 onwards (schema 3007 to 3400) 20748: Incremented version label 20745: ALF-3639: Merged V3.2 to PATCHES/V3.2.0 18363: WCM clustering - ETHREEOH-3962 (duplicate root node entry) 20863: Merged PATCHES/V3.1.2 to V3.3 20830: ALF-934: Another go at making External Access Servlet reset JSF view state for the document it is requesting 20701: ALF-3203: Guarantee a deterministic initialization sequence for WebClientConfigBootstrap (PARTIAL - Needs Surf fix) 20861: Merged PATCHES/V3.2.1 to V3.3 (RECORD ONLY) 20831: Incremented version label 20702: Incremented version label 20681: ALF-3109: Merged V3.2 to PATCHES/V3.1.2 16933: Fix ETHREEOH-1788 - Bootstrap fails due to disabled-avm-indexing-context.xml 20680: ALF-3109: Merged V3.2 to PATCHES/V3.1.2 16714: WCM/AVM fixes - ETHREEOH-2697 - file system likely to get full with avm lucene directories for unindexed WCM store - ETHREEOH-1847 - re-starting cluster node may show non-staging WCM store indexes out-of-date (although not indexed) 20611: Incremented version label 20538: ALF-3117: Merged HEAD to PATCHES/V3.1.2 17099: Build Fix for failing permission test (missing flush in DAO) 20535: ALF-3141: Merged V3.2 to PATCHES/V3.1.2 17441: Build fix: Fix AVM permission inheritance to match DM and fix common permission dao component 20534: Incremented version label 20533: ALF-3117: Merged DEV/V3.3-BUG-FIX to PATCHES/V3.1.2 20368: Work-around for ALF-2366: patch.updateDmPermissions takes too long to complete - this patch may now be deferred until 3.4 using the sample context (DM will use old permissions and AVM new as it did in 2.2.x) - this is only supported upgrading direct to 3.3.1 20532: ALF-3117: Merged V3.2 to PATCHES/V3.1.2 17076: Improvements for ETHREEOH-2153: patch.updateDmPermissions takes too long to complete 20531: ALF-3141: Merged V3.2 to PATCHES/V3.1.2 17419: Fix for ETHREEOH-3296: Enterprise 3.X / Permissions Error When Cut & Paste on Sub-Folder 20516: Incremented version label 20515: ALF-3109: Merged V3.2 to PATCHES/V3.1.2 18363: WCM clustering - ETHREEOH-3962 (duplicate root node entry) 20860: Merged V3.1 to V3.3 19424: Fix bug in permission evaluation time reporting 20859: Merged V3.1 to V3.3 (RECORD ONLY) 20599: Incremented version label 20596: ALF-3184: Merged V3.3-BUGFIX to V3.1A 20307: VersionStore - minor fixes if running deprecated V1 - warn in startup log - do not execute migration cleanup 20370: Version Migrator (ALF-1000) - use common batch processor to enable multiple workers 20373: Version Migrator (ALF-1000) - resolve runtime conflict (w/ r20334) 20387: Version Migrator (ALF-1000) - approx x3 boost (policies ignore version2 store) 20431: Version Migrator (ALF-1000) - migrate 1st batch independently 20591: ALF-3184: Merged V3.2 to V3.1A (partial) 19507: ALF-955: deletion of dynamic custom model - ignore policies/behaviours for node archive store (reviewed w/ DH) 19553: Follow-on to r19507 (ALF-955) - fix testAutoRemovalOfVersionHistory 20577: ALF-3184: Ported BatchProcessor to V3.1A in preparation for VersionMigrator port 19426: Fix for eclipse build path: Part 2 19425: Fix for eclipse build path 19305: Merged V3.2 to V3.1 ('cause you never know!) 19304: Removed static (singleton) usage of CacheFactory 18996: MOB-388: Fixed copying of properties 18919: CopyServiceChildAssocsFix on 3.1 18566: Removed svn:mergeinfo 18428: Backport of r14260: fixed code typo which cased a ClassCastException with multiple pooled actors. 18424: Updated version label to 3.1.2.1 17861: Merge 2.2 to 3.1: 17803: Re-use open files for the same session/process id so that writes on each file handle go to the same file. ETWOTWO-1250. (Record-only) 17843: Re-use open files for the same session/process id so that writes on each file handle go to the same file. Port of ETWOTWO-1250. 17842: Missing file from previous checkin. 17839: Rewrite the rename file logic to handle MS Office file rename patterns. ETHREEOH-1951. 17359: Fix for CIFS/Kerberos/SPNEGO logon problem with Win2008/Win7 client. ETHREEOH-3225. 17193: ETHREEOH-3112: Issue for adding / deleting non-English files Appropriate encoding for non English symbols was added. Ported from V3.2. 17181: Fixed typo on --record-only 17130: Fix for cannot delete file via CIFS that has a thumbnail associated with it. ETHREEOH-3143 and ETHREEOH-3115. 20858: Merged V2.2 to V3.3 18568: (RECORD ONLY) Fix for CIFS SendTo->Compressed Folder 'not enough space' error. ETWOTWO-596. Ported latest v3 repo filesystem rename logic to v2, should fix a few other issues too. 17803: (RECORD ONLY) Re-use open files for the same session/process id so that writes on each file handle go to the same file. ETWOTWO-1250. 20857: Merged V2.2 to V3.3 20504: Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 19346: ALF-1358: Deleting space with "execute a script" rule fails - The invocation of the RuleServiceImpl.getRule() was added on the ruleNodeRef to get updated associations of the last one. (???) 20476: Fix for ALF-1863: Advanced Search does not work with custom type of type d:int with a constraint of type LIST 20475: Merged DEV/TEMPORARY to V2.2 20375: ALF-1830: Manage Task UI for Pooled Tasks: don't show Reject/Accept if user hasn't taken ownership 20472: (RECORD ONLY) ALF-1841: Merged DEV/BELARUS/V2.2-2009_12_01 to V2.2 (with corrections) 17865: ETWOTWO-935: Regression: readOnly settings do not work in 2.2 causing bootstrap to fail The check on current mode is read only was added into AbstractLuceneIndexerAndSearcherFactory and AlfrescoJobExecutorThread classes. 20068: Merged BRANCHES/DEV/BELARUS/V2.2-2010_02_03 to BRANCHES/V2.2: 19326: ALF-1932: ALF-1358 Deleting space with "execute a script" rule fails: Unit Test move to RuleServiceImplTest. 19670: Fix for ALF-1788: Renamed Category not usable in Query - renaming a category in the admin console now also renames the association and changes the PATH by which the category is known. 19093: Fix ALF-1791 - added unit test 19055: Fix compile error introduced during pervious merge 19048: Merge DEV/BELARUS/V2.2-2010_02_03 to V2.2 19014 : ALF-883: Rule is not triggered for a item which is restored from the bin 19045: Merge DEV/V2.1SP7 to V2.2 12225 : ETWOONE-74 (Authentication tickets expire after set time, but would be more useful to have them expire after an inactivity timeout.) 18958: Merged BELARUS/V2.2-2010_02_03 18850 Fixed ALF-1358: Deleting space with "execute a script" rule fails - Merged the fix only. The unit test belongs to the RuleService. 18918: (RECORD ONLY) Fixed backward compatibility of CopyServiceChildAssocsFix module 18759: (RECORD ONLY) Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 18553: ResultSet closing was added to methods This was fixed separately in V3.2; port forward selectively 18561: (RECORD ONLY) Merged DEV to V2.2 18552: Fix ETWOTWO-1389: Issues with ACL upgrade script for Oracle (DH: Removed commented-out SQL statements) 16304: (RECORD ONLY) ETWOONE-335: Parallel Review does not store Priority and Due Date set at task creation 1. Appropriate changes have been made in parallelreview_group_processdefinition.xml and parallelreview_processdefinition.xml files. 2. Redeploy flag is kept with false value by default in the workflow-context.xml.sample file. 3. A sorting of the list of workflow definitions by name has been already applied in all branches according to ETWOTWO-302 issue fix. 20855: Fix for ALF-3690. Unable to FTP files into Share site documentLibrary folder. This fix corrects what it essentially a typo. The dictionaryService was injected twice into the CreateNodeRuleTrigger bean, rather than the dictionaryService and the ruleService. 20853: Merged V2.2 to V3.3 (RECORD ONLY) 20459: Build fix - don't try to delete the guest user in PersonTest 20411: Merged BRANCHES/V3.1 to BRANCHES/V2.2: (for ALF-2628) 14863: (RECORD ONLY) Fixed ETHREEOH-2223: Oracle version-specific schema update failure in upgrading from 2.1A build to 20383: Merged V3.2 to V2.2 (Fixes duplicate ALF-1359) 16731: ETHREEOH-2411: Error message appears when trying to create advanced workflow with long description 19303: Updated version to 2.2.7 17811: Updated version to 2.2.6 17433: Merged V3.1 to V2.2 15894: Fix ETHREEOH-2416 and ALFCOM-3300: Duplicate name exceptions not being trapped correctly Fixes ETWOTWO-1261 15869: Port of desktop action client side EXE fixes from v3.x. ETWOTWO-1374. 20849: (RECORD ONLY) Merged V3.3-BUG-FIX to V3.3 20847: Fixes Recent Documents and My Tasks localisation issues: ALF-2021 & adds an FTL friendly medium length date format property 20828: Missed svn:mergeinfo git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20885 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
1087 lines
43 KiB
Java
1087 lines
43 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.web.bean.search;
|
|
|
|
import java.text.MessageFormat;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import javax.faces.component.UISelectBoolean;
|
|
import javax.faces.context.FacesContext;
|
|
import javax.faces.event.ActionEvent;
|
|
import javax.faces.model.DataModel;
|
|
import javax.faces.model.SelectItem;
|
|
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
|
import org.alfresco.service.ServiceRegistry;
|
|
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
|
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
|
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
|
import org.alfresco.service.cmr.repository.ContentReader;
|
|
import org.alfresco.service.cmr.repository.ContentService;
|
|
import org.alfresco.service.cmr.repository.MimetypeService;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.security.AccessStatus;
|
|
import org.alfresco.service.cmr.security.PermissionService;
|
|
import org.alfresco.service.namespace.NamespaceService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.service.namespace.RegexQNamePattern;
|
|
import org.alfresco.util.CachingDateFormat;
|
|
import org.alfresco.util.ISO9075;
|
|
import org.alfresco.web.app.Application;
|
|
import org.alfresco.web.bean.dialog.BaseDialogBean;
|
|
import org.alfresco.web.bean.repository.MapNode;
|
|
import org.alfresco.web.bean.repository.Node;
|
|
import org.alfresco.web.bean.repository.Repository;
|
|
import org.alfresco.web.bean.repository.User;
|
|
import org.alfresco.web.bean.search.SearchContext.RangeProperties;
|
|
import org.alfresco.web.config.AdvancedSearchConfigElement;
|
|
import org.alfresco.web.config.AdvancedSearchConfigElement.CustomProperty;
|
|
import org.alfresco.web.data.IDataContainer;
|
|
import org.alfresco.web.data.QuickSort;
|
|
import org.alfresco.web.ui.common.Utils;
|
|
import org.alfresco.web.ui.common.component.UIModeList;
|
|
import org.alfresco.web.ui.common.component.UIPanel.ExpandedEvent;
|
|
import org.alfresco.web.ui.repo.component.UIAjaxCategoryPicker;
|
|
import org.alfresco.web.ui.repo.component.UISearchCustomProperties;
|
|
|
|
/**
|
|
* Provides the form state and action event handling for the Advanced Search UI.
|
|
* <p>
|
|
* Integrates with the web-client ConfigService to retrieve configuration of custom
|
|
* meta-data searching fields. Custom fields can be configured to appear in the UI
|
|
* and they are they automatically added to the search query by this bean.
|
|
*
|
|
* @author Kevin Roast
|
|
*/
|
|
public class AdvancedSearchDialog extends BaseDialogBean
|
|
{
|
|
private static final long serialVersionUID = 3658148969240122732L;
|
|
|
|
/** PermissionService */
|
|
transient private PermissionService permissionService;
|
|
|
|
/**
|
|
* Default constructor
|
|
*/
|
|
public void init(java.util.Map<String, String> parameters)
|
|
{
|
|
super.init(parameters);
|
|
properties.getPanels().put(PANEL_CATEGORIES, false);
|
|
properties.getPanels().put(PANEL_ATTRS, false);
|
|
properties.getPanels().put(PANEL_CUSTOM, false);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Bean property getters and setters
|
|
|
|
public void setPermissionService(PermissionService permissionService)
|
|
{
|
|
this.permissionService = permissionService;
|
|
}
|
|
|
|
protected PermissionService getPermissionService()
|
|
{
|
|
if (permissionService == null)
|
|
{
|
|
permissionService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getPermissionService();
|
|
}
|
|
return permissionService;
|
|
}
|
|
|
|
public void setProperties(SearchProperties properties)
|
|
{
|
|
this.properties = properties;
|
|
}
|
|
|
|
/**
|
|
* @return Returns the allow Edit mode.
|
|
*/
|
|
public boolean isAllowEdit()
|
|
{
|
|
boolean allow = (properties.getSavedSearch() != null && NO_SELECTION.equals(properties.getSavedSearch()) == false);
|
|
if (allow)
|
|
{
|
|
NodeRef savedSearchRef = new NodeRef(Repository.getStoreRef(), properties.getSavedSearch());
|
|
allow = (getPermissionService().hasPermission(savedSearchRef,
|
|
PermissionService.WRITE) == AccessStatus.ALLOWED);
|
|
}
|
|
return allow;
|
|
}
|
|
|
|
/**
|
|
* @param allowEdit The allow Edit mode to set.
|
|
*/
|
|
public void setAllowEdit(boolean allowEdit)
|
|
{
|
|
// dummy method for Bean interface compliance
|
|
}
|
|
|
|
/**
|
|
* Returns the properties for current categories JSF DataModel
|
|
*
|
|
* @return JSF DataModel representing the current categories to search against
|
|
*/
|
|
public DataModel getCategoriesDataModel()
|
|
{
|
|
// only set the wrapped data once otherwise the rowindex is reset
|
|
if (properties.getCategoriesDataModel().getWrappedData() == null)
|
|
{
|
|
properties.getCategoriesDataModel().setWrappedData(properties.getCategories());
|
|
}
|
|
|
|
return properties.getCategoriesDataModel();
|
|
}
|
|
|
|
/**
|
|
* @return Returns a list of content object types to allow the user to select from
|
|
*/
|
|
public List<SelectItem> getContentTypes()
|
|
{
|
|
if ((properties.getContentTypes() == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
|
|
{
|
|
FacesContext context = FacesContext.getCurrentInstance();
|
|
|
|
DictionaryService dictionaryService = Repository.getServiceRegistry(context).getDictionaryService();
|
|
|
|
// add the well known cm:content object type by default
|
|
properties.setContentTypes(new ArrayList<SelectItem>(5));
|
|
properties.getContentTypes().add(new SelectItem(ContentModel.TYPE_CONTENT.toString(),
|
|
dictionaryService.getType(ContentModel.TYPE_CONTENT).getTitle()));
|
|
|
|
// add any configured content sub-types to the list
|
|
List<String> types = getSearchConfig().getContentTypes();
|
|
if (types != null)
|
|
{
|
|
for (String type : types)
|
|
{
|
|
QName idQName = Repository.resolveToQName(type);
|
|
if (idQName != null)
|
|
{
|
|
TypeDefinition typeDef = dictionaryService.getType(idQName);
|
|
|
|
if (typeDef != null && dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_CONTENT))
|
|
{
|
|
// try and get label from the dictionary
|
|
String label = typeDef.getTitle();
|
|
|
|
// else just use the localname
|
|
if (label == null)
|
|
{
|
|
label = idQName.getLocalName();
|
|
}
|
|
|
|
properties.getContentTypes().add(new SelectItem(idQName.toString(), label));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return properties.getContentTypes();
|
|
}
|
|
|
|
/**
|
|
* @return Returns a list of folder object types to allow the user to select from
|
|
*/
|
|
public List<SelectItem> getFolderTypes()
|
|
{
|
|
if ((properties.getFolderTypes() == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
|
|
{
|
|
FacesContext context = FacesContext.getCurrentInstance();
|
|
|
|
DictionaryService dictionaryService = Repository.getServiceRegistry(context).getDictionaryService();
|
|
|
|
// add the well known cm:folder object type by default
|
|
properties.setFolderTypes(new ArrayList<SelectItem>(5));
|
|
properties.getFolderTypes().add(new SelectItem(ContentModel.TYPE_FOLDER.toString(),
|
|
dictionaryService.getType(ContentModel.TYPE_FOLDER).getTitle()));
|
|
|
|
// add any configured folder sub-types to the list
|
|
List<String> types = getSearchConfig().getFolderTypes();
|
|
if (types != null)
|
|
{
|
|
for (String type : types)
|
|
{
|
|
QName idQName = Repository.resolveToQName(type);
|
|
if (idQName != null)
|
|
{
|
|
TypeDefinition typeDef = dictionaryService.getType(idQName);
|
|
|
|
if (typeDef != null && dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_FOLDER))
|
|
{
|
|
// try and get label from the dictionary
|
|
String label = typeDef.getTitle();
|
|
|
|
// else just use the localname
|
|
if (label == null)
|
|
{
|
|
label = idQName.getLocalName();
|
|
}
|
|
|
|
properties.getFolderTypes().add(new SelectItem(idQName.toString(), label));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return properties.getFolderTypes();
|
|
}
|
|
|
|
/**
|
|
* @return Returns a list of content formats to allow the user to select from
|
|
*/
|
|
public List<SelectItem> getContentFormats()
|
|
{
|
|
if ((properties.getContentFormats() == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
|
|
{
|
|
properties.setContentFormats(new ArrayList<SelectItem>(80));
|
|
ServiceRegistry registry = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
|
|
MimetypeService mimetypeService = registry.getMimetypeService();
|
|
|
|
// get the mime type display names
|
|
Map<String, String> mimeTypes = mimetypeService.getDisplaysByMimetype();
|
|
for (String mimeType : mimeTypes.keySet())
|
|
{
|
|
properties.getContentFormats().add(new SelectItem(mimeType, mimeTypes.get(mimeType)));
|
|
}
|
|
|
|
// make sure the list is sorted by the values
|
|
QuickSort sorter = new QuickSort(properties.getContentFormats(), "label", true, IDataContainer.SORT_CASEINSENSITIVE);
|
|
sorter.sort();
|
|
|
|
// add the "All Formats" constant marker at the top of the list (default selection)
|
|
properties.getContentFormats().add(0, new SelectItem("", Application.getMessage(FacesContext.getCurrentInstance(), MSG_ALL_FORMATS)));
|
|
}
|
|
|
|
return properties.getContentFormats();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Action event handlers
|
|
|
|
/**
|
|
* Handler to clear the advanced search screen form details
|
|
*/
|
|
public void reset(ActionEvent event)
|
|
{
|
|
resetFields();
|
|
properties.setSavedSearch(null);
|
|
}
|
|
|
|
private void resetFields()
|
|
{
|
|
properties.setText("");
|
|
properties.setMode(MODE_ALL);
|
|
properties.setLookin(LOOKIN_ALL);
|
|
properties.setContentType(null);
|
|
properties.setContentFormat(null);
|
|
properties.setFolderType(null);
|
|
properties.setLocation(null);
|
|
properties.setLocationChildren(true);
|
|
properties.setCategories(new ArrayList<Node>(2));
|
|
properties.setCategoriesDataModel(null);
|
|
properties.setTitle(null);
|
|
properties.setDescription(null);
|
|
properties.setAuthor(null);
|
|
properties.setCreatedDateFrom(null);
|
|
properties.setCreatedDateTo(null);
|
|
properties.setModifiedDateFrom(null);
|
|
properties.setModifiedDateTo(null);
|
|
properties.setCreatedDateChecked(false);
|
|
properties.setModifiedDateChecked(false);
|
|
properties.getCustomProperties().clear();
|
|
}
|
|
|
|
/**
|
|
* Handler to perform a search based on the current criteria
|
|
*/
|
|
public String search()
|
|
{
|
|
// construct the Search Context and set on the navigation bean
|
|
// then simply navigating to the browse screen will cause it pickup the Search Context
|
|
SearchContext search = new SearchContext();
|
|
|
|
// set the full-text/name field value
|
|
search.setText(properties.getText());
|
|
|
|
// set whether to force AND operation on text terms
|
|
search.setForceAndTerms(Application.getClientConfig(FacesContext.getCurrentInstance()).getForceAndTerms());
|
|
|
|
if (properties.getMode().equals(MODE_ALL))
|
|
{
|
|
search.setMode(SearchContext.SEARCH_ALL);
|
|
}
|
|
else if (properties.getMode().equals(MODE_FILES_TEXT))
|
|
{
|
|
search.setMode(SearchContext.SEARCH_FILE_NAMES_CONTENTS);
|
|
}
|
|
else if (properties.getMode().equals(MODE_FILES))
|
|
{
|
|
search.setMode(SearchContext.SEARCH_FILE_NAMES);
|
|
}
|
|
else if (properties.getMode().equals(MODE_FOLDERS))
|
|
{
|
|
search.setMode(SearchContext.SEARCH_SPACE_NAMES);
|
|
}
|
|
|
|
// additional attributes search
|
|
if (properties.getDescription() != null && properties.getDescription().length() != 0)
|
|
{
|
|
search.addAttributeQuery(ContentModel.PROP_DESCRIPTION, properties.getDescription());
|
|
}
|
|
if (properties.getTitle() != null && properties.getTitle().length() != 0)
|
|
{
|
|
search.addAttributeQuery(ContentModel.PROP_TITLE, properties.getTitle());
|
|
}
|
|
if (properties.getAuthor() != null && properties.getAuthor().length() != 0)
|
|
{
|
|
search.addAttributeQuery(ContentModel.PROP_AUTHOR, properties.getAuthor());
|
|
}
|
|
if (properties.getContentFormat() != null && properties.getContentFormat().length() != 0)
|
|
{
|
|
search.setMimeType(properties.getContentFormat());
|
|
}
|
|
if (properties.isCreatedDateChecked())
|
|
{
|
|
SimpleDateFormat df = CachingDateFormat.getDateFormat();
|
|
String strCreatedDate = df.format(properties.getCreatedDateFrom());
|
|
String strCreatedDateTo = df.format(properties.getCreatedDateTo());
|
|
search.addRangeQuery(ContentModel.PROP_CREATED, strCreatedDate, strCreatedDateTo, true);
|
|
}
|
|
if (properties.isModifiedDateChecked())
|
|
{
|
|
SimpleDateFormat df = CachingDateFormat.getDateFormat();
|
|
String strModifiedDate = df.format(properties.getModifiedDateFrom());
|
|
String strModifiedDateTo = df.format(properties.getModifiedDateTo());
|
|
search.addRangeQuery(ContentModel.PROP_MODIFIED, strModifiedDate, strModifiedDateTo, true);
|
|
}
|
|
|
|
// in case of dynamic config, only lookup once
|
|
Map<String, DataTypeDefinition> customPropertyLookup = getCustomPropertyLookup();
|
|
|
|
// walk each of the custom properties add add them as additional attributes
|
|
for (String qname : properties.getCustomProperties().keySet())
|
|
{
|
|
Object value = properties.getCustomProperties().get(qname);
|
|
DataTypeDefinition typeDef = customPropertyLookup.get(qname);
|
|
if (typeDef != null)
|
|
{
|
|
QName typeName = typeDef.getName();
|
|
if (DataTypeDefinition.DATE.equals(typeName) || DataTypeDefinition.DATETIME.equals(typeName))
|
|
{
|
|
// only apply date to search if the user has checked the enable checkbox
|
|
if (value != null && Boolean.valueOf(value.toString()) == true)
|
|
{
|
|
SimpleDateFormat df = CachingDateFormat.getDateFormat();
|
|
String strDateFrom = df.format(properties.getCustomProperties().get(
|
|
UISearchCustomProperties.PREFIX_DATE_FROM + qname));
|
|
String strDateTo = df.format(properties.getCustomProperties().get(
|
|
UISearchCustomProperties.PREFIX_DATE_TO + qname));
|
|
search.addRangeQuery(QName.createQName(qname), strDateFrom, strDateTo, true);
|
|
}
|
|
}
|
|
else if (DataTypeDefinition.BOOLEAN.equals(typeName))
|
|
{
|
|
if (((Boolean)value) == true)
|
|
{
|
|
search.addFixedValueQuery(QName.createQName(qname), value.toString());
|
|
}
|
|
}
|
|
else if (DataTypeDefinition.NODE_REF.equals(typeName) || DataTypeDefinition.CATEGORY.equals(typeName))
|
|
{
|
|
if (value != null)
|
|
{
|
|
search.addFixedValueQuery(QName.createQName(qname), value.toString());
|
|
}
|
|
}
|
|
else if (value != null)
|
|
{
|
|
// is the value from a list?
|
|
String strVal = value.toString();
|
|
Object item = properties.getCustomProperties().get(
|
|
UISearchCustomProperties.PREFIX_LOV_ITEM + qname);
|
|
if (item != null)
|
|
{
|
|
// ListOfValues custom property - use a fixed value query if set
|
|
if (((Boolean)value) == true)
|
|
{
|
|
search.addFixedValueQuery(QName.createQName(qname), item.toString());
|
|
}
|
|
}
|
|
else if (strVal != null && strVal.length() != 0)
|
|
{
|
|
if (DataTypeDefinition.INT.equals(typeName) || DataTypeDefinition.LONG.equals(typeName) ||
|
|
DataTypeDefinition.FLOAT.equals(typeName) || DataTypeDefinition.DOUBLE.equals(typeName))
|
|
{
|
|
search.addFixedValueQuery(QName.createQName(qname), strVal);
|
|
}
|
|
else
|
|
{
|
|
// by default use toString() value - this is for text fields and unknown types
|
|
search.addAttributeQuery(QName.createQName(qname), strVal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// location path search
|
|
if (properties.getLookin().equals(LOOKIN_OTHER) && properties.getLocation() != null)
|
|
{
|
|
search.setLocation(SearchContext.getPathFromSpaceRef(properties.getLocation(), properties.isLocationChildren()));
|
|
}
|
|
|
|
// category path search
|
|
if (properties.getCategories().size() != 0)
|
|
{
|
|
String[] paths = new String[properties.getCategories().size()];
|
|
for (int i=0; i<paths.length; i++)
|
|
{
|
|
Node category = properties.getCategories().get(i);
|
|
boolean includeChildren = (Boolean)category.getProperties().get(INCLUDE_CHILDREN);
|
|
paths[i] = SearchContext.getPathFromSpaceRef(category.getNodeRef(), includeChildren);
|
|
}
|
|
search.setCategories(paths);
|
|
}
|
|
|
|
// content type restriction
|
|
if (properties.getContentType() != null)
|
|
{
|
|
search.setContentType(properties.getContentType());
|
|
}
|
|
|
|
// folder type restriction
|
|
if (properties.getFolderType() != null)
|
|
{
|
|
search.setFolderType(properties.getFolderType());
|
|
}
|
|
|
|
// set the Search Context onto the top-level navigator bean
|
|
// this causes the browse screen to switch into search results view
|
|
this.navigator.setSearchContext(search);
|
|
|
|
return OUTCOME_BROWSE;
|
|
}
|
|
|
|
/**
|
|
* Action handler called to initiate the saved search screen for Create
|
|
*/
|
|
public String saveNewSearch()
|
|
{
|
|
properties.setSearchDescription(null);
|
|
properties.setSearchName(null);
|
|
properties.setSearchSaveGlobal(false);
|
|
|
|
return "dialog:saveSearch";
|
|
}
|
|
|
|
/**
|
|
* Action handler called to initiate the saved search screen for Edit
|
|
*/
|
|
public String saveEditSearch()
|
|
{
|
|
properties.setSearchDescription(null);
|
|
properties.setSearchName(null);
|
|
properties.setEditSearchName(null);
|
|
|
|
// load previously selected search for overwrite
|
|
try
|
|
{
|
|
NodeRef searchRef = new NodeRef(Repository.getStoreRef(), properties.getSavedSearch());
|
|
Node searchNode = new Node(searchRef);
|
|
if (getNodeService().exists(searchRef) && searchNode.hasPermission(PermissionService.WRITE))
|
|
{
|
|
Node node = new Node(searchRef);
|
|
properties.setSearchName(node.getName());
|
|
properties.setEditSearchName(properties.getSearchName());
|
|
properties.setSearchDescription((String)node.getProperties().get(ContentModel.PROP_DESCRIPTION));
|
|
}
|
|
else
|
|
{
|
|
// unable to overwrite existing saved search
|
|
properties.setSavedSearch(null);
|
|
}
|
|
}
|
|
catch (Throwable err)
|
|
{
|
|
// unable to overwrite existing saved search for some other reason
|
|
properties.setSavedSearch(null);
|
|
}
|
|
|
|
return "dialog:editSearch";
|
|
}
|
|
|
|
/**
|
|
* @return list of saved searches as SelectItem objects
|
|
*/
|
|
public List<SelectItem> getSavedSearches()
|
|
{
|
|
List<SelectItem> savedSearches = properties.getCachedSavedSearches().get();
|
|
if (savedSearches == null)
|
|
{
|
|
FacesContext fc = FacesContext.getCurrentInstance();
|
|
ServiceRegistry services = Repository.getServiceRegistry(fc);
|
|
|
|
// get the searches list from the current user or global searches location
|
|
NodeRef searchesRef = null;
|
|
if (SAVED_SEARCHES_USER.equals(properties.getSavedSearchMode()) == true)
|
|
{
|
|
searchesRef = getUserSearchesRef();
|
|
}
|
|
else if (SAVED_SEARCHES_GLOBAL.equals(properties.getSavedSearchMode()) == true)
|
|
{
|
|
searchesRef = getGlobalSearchesRef();
|
|
}
|
|
|
|
// read the content nodes under the folder
|
|
if (searchesRef != null)
|
|
{
|
|
DictionaryService dd = services.getDictionaryService();
|
|
|
|
List<ChildAssociationRef> childRefs = getNodeService().getChildAssocs(
|
|
searchesRef,
|
|
ContentModel.ASSOC_CONTAINS,
|
|
RegexQNamePattern.MATCH_ALL);
|
|
|
|
savedSearches = new ArrayList<SelectItem>(childRefs.size() + 1);
|
|
if (childRefs.size() != 0)
|
|
{
|
|
for (ChildAssociationRef ref : childRefs)
|
|
{
|
|
Node childNode = new Node(ref.getChildRef());
|
|
if (dd.isSubClass(childNode.getType(), ContentModel.TYPE_CONTENT))
|
|
{
|
|
savedSearches.add(new SelectItem(childNode.getId(), childNode.getName()));
|
|
}
|
|
}
|
|
|
|
// make sure the list is sorted by the label
|
|
QuickSort sorter = new QuickSort(savedSearches, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
|
|
sorter.sort();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// handle missing/access denied folder case
|
|
savedSearches = new ArrayList<SelectItem>(1);
|
|
}
|
|
|
|
// add an entry (at the start) to instruct the user to select a saved search
|
|
savedSearches.add(0, new SelectItem(NO_SELECTION,
|
|
Application.getMessage(FacesContext.getCurrentInstance(), MSG_SELECT_SAVED_SEARCH)));
|
|
|
|
// store in the cache (will auto-expire)
|
|
properties.getCachedSavedSearches().put(savedSearches);
|
|
}
|
|
|
|
return savedSearches;
|
|
}
|
|
|
|
/**
|
|
* Change the current saved searches list mode based on user selection
|
|
*/
|
|
public void savedSearchModeChanged(ActionEvent event)
|
|
{
|
|
UIModeList savedModeList = (UIModeList)event.getComponent();
|
|
|
|
// get the saved searches list mode
|
|
String viewMode = savedModeList.getValue().toString();
|
|
|
|
// persist
|
|
properties.setSavedSearchMode(viewMode);
|
|
|
|
// clear existing caches and values
|
|
// the values will be re-queried when the client requests the saved searches list
|
|
properties.getCachedSavedSearches().clear();
|
|
properties.setSavedSearch(null);
|
|
}
|
|
|
|
/**
|
|
* Action handler called when a saved search is selected by the user
|
|
*/
|
|
public void selectSearch(ActionEvent event)
|
|
{
|
|
if (NO_SELECTION.equals(properties.getSavedSearch()) == false)
|
|
{
|
|
// read an XML serialized version of the SearchContext object
|
|
NodeRef searchSearchRef = new NodeRef(Repository.getStoreRef(), properties.getSavedSearch());
|
|
ServiceRegistry services = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
|
|
ContentService cs = services.getContentService();
|
|
try
|
|
{
|
|
if (services.getNodeService().exists(searchSearchRef))
|
|
{
|
|
ContentReader reader = cs.getReader(searchSearchRef, ContentModel.PROP_CONTENT);
|
|
SearchContext search = new SearchContext().fromXML(reader.getContentString());
|
|
|
|
// if we get here we read the serialized object successfully
|
|
// now setup the UI to match the new SearchContext object
|
|
initialiseFromContext(search);
|
|
}
|
|
}
|
|
catch (Throwable err)
|
|
{
|
|
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
|
FacesContext.getCurrentInstance(), MSG_ERROR_RESTORE_SEARCH), err.getMessage()), err);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialise the Advanced Search UI screen from a SearchContext
|
|
*
|
|
* @param search the SearchContext to retrieve state from
|
|
*/
|
|
private void initialiseFromContext(SearchContext search)
|
|
{
|
|
resetFields();
|
|
|
|
properties.setText(search.getText());
|
|
|
|
switch (search.getMode())
|
|
{
|
|
case SearchContext.SEARCH_ALL:
|
|
properties.setMode(MODE_ALL);
|
|
break;
|
|
case SearchContext.SEARCH_FILE_NAMES_CONTENTS:
|
|
properties.setMode(MODE_FILES_TEXT);
|
|
break;
|
|
case SearchContext.SEARCH_FILE_NAMES:
|
|
properties.setMode(MODE_FILES);
|
|
break;
|
|
case SearchContext.SEARCH_SPACE_NAMES:
|
|
properties.setMode(MODE_FOLDERS);
|
|
break;
|
|
}
|
|
properties.getPanels().put(PANEL_RESTRICT, true);
|
|
|
|
if (search.getLocation() != null)
|
|
{
|
|
properties.setLocationChildren(search.getLocation().endsWith("//*"));
|
|
properties.setLocation(findNodeRefFromPath(search.getLocation()));
|
|
properties.setLookin(LOOKIN_OTHER);
|
|
properties.getPanels().put(PANEL_LOCATION, true);
|
|
}
|
|
|
|
String[] categories = search.getCategories();
|
|
if (categories != null && categories.length != 0)
|
|
{
|
|
for (String category : categories)
|
|
{
|
|
NodeRef categoryRef = findNodeRefFromPath(category);
|
|
if (categoryRef != null)
|
|
{
|
|
Node categoryNode = new MapNode(categoryRef);
|
|
// add a value bound propery used to indicate if searching across children is selected
|
|
categoryNode.getProperties().put(INCLUDE_CHILDREN, category.endsWith("//*"));
|
|
properties.getCategories().add(categoryNode);
|
|
}
|
|
}
|
|
properties.getPanels().put(PANEL_CATEGORIES, true);
|
|
}
|
|
|
|
properties.setContentType(search.getContentType());
|
|
properties.setContentFormat(search.getMimeType());
|
|
properties.setFolderType(search.getFolderType());
|
|
|
|
properties.setDescription(search.getAttributeQuery(ContentModel.PROP_DESCRIPTION));
|
|
properties.setTitle(search.getAttributeQuery(ContentModel.PROP_TITLE));
|
|
properties.setAuthor(search.getAttributeQuery(ContentModel.PROP_AUTHOR));
|
|
if (properties.getContentType() != null || properties.getContentFormat() != null ||
|
|
properties.getDescription() != null || properties.getTitle() != null ||
|
|
properties.getAuthor() != null)
|
|
{
|
|
properties.getPanels().put(PANEL_ATTRS, true);
|
|
}
|
|
|
|
RangeProperties createdDate = search.getRangeProperty(ContentModel.PROP_CREATED);
|
|
if (createdDate != null)
|
|
{
|
|
properties.setCreatedDateFrom(Utils.parseXMLDateFormat(createdDate.lower));
|
|
properties.setCreatedDateTo(Utils.parseXMLDateFormat(createdDate.upper));
|
|
properties.setCreatedDateChecked(true);
|
|
properties.getPanels().put(PANEL_ATTRS, true);
|
|
}
|
|
RangeProperties modifiedDate = search.getRangeProperty(ContentModel.PROP_MODIFIED);
|
|
if (modifiedDate != null)
|
|
{
|
|
properties.setModifiedDateFrom(Utils.parseXMLDateFormat(modifiedDate.lower));
|
|
properties.setModifiedDateTo(Utils.parseXMLDateFormat(modifiedDate.upper));
|
|
properties.setModifiedDateChecked(true);
|
|
properties.getPanels().put(PANEL_ATTRS, true);
|
|
}
|
|
|
|
// in case of dynamic config, only lookup once
|
|
Map<String, DataTypeDefinition> customPropertyLookup = getCustomPropertyLookup();
|
|
|
|
// custom fields - calculate which are required to set through the custom properties lookup table
|
|
for (String qname : customPropertyLookup.keySet())
|
|
{
|
|
DataTypeDefinition typeDef = customPropertyLookup.get(qname);
|
|
if (typeDef != null)
|
|
{
|
|
QName typeName = typeDef.getName();
|
|
if (DataTypeDefinition.DATE.equals(typeName) || DataTypeDefinition.DATETIME.equals(typeName))
|
|
{
|
|
RangeProperties dateProps = search.getRangeProperty(QName.createQName(qname));
|
|
if (dateProps != null)
|
|
{
|
|
properties.getCustomProperties().put(UISearchCustomProperties.PREFIX_DATE_FROM + qname,
|
|
Utils.parseXMLDateFormat(dateProps.lower));
|
|
properties.getCustomProperties().put(UISearchCustomProperties.PREFIX_DATE_TO + qname,
|
|
Utils.parseXMLDateFormat(dateProps.upper));
|
|
properties.getCustomProperties().put(qname, true);
|
|
properties.getPanels().put(PANEL_CUSTOM, true);
|
|
}
|
|
}
|
|
else if (DataTypeDefinition.BOOLEAN.equals(typeName))
|
|
{
|
|
String strBool = search.getFixedValueQuery(QName.createQName(qname));
|
|
if (strBool != null)
|
|
{
|
|
properties.getCustomProperties().put(qname, Boolean.parseBoolean(strBool));
|
|
properties.getPanels().put(PANEL_CUSTOM, true);
|
|
}
|
|
}
|
|
else if (DataTypeDefinition.NODE_REF.equals(typeName) || DataTypeDefinition.CATEGORY.equals(typeName))
|
|
{
|
|
String strNodeRef = search.getFixedValueQuery(QName.createQName(qname));
|
|
if (strNodeRef != null)
|
|
{
|
|
properties.getCustomProperties().put(qname, new NodeRef(strNodeRef));
|
|
properties.getPanels().put(PANEL_CUSTOM, true);
|
|
}
|
|
}
|
|
else if (DataTypeDefinition.INT.equals(typeName) || DataTypeDefinition.LONG.equals(typeName) ||
|
|
DataTypeDefinition.FLOAT.equals(typeName) || DataTypeDefinition.DOUBLE.equals(typeName))
|
|
{
|
|
// currently numbers are rendered as text in UISearchCustomProperties component
|
|
// this code will need updating if that changes!
|
|
properties.getCustomProperties().put(qname, search.getFixedValueQuery(QName.createQName(qname)));
|
|
properties.getPanels().put(PANEL_CUSTOM, true);
|
|
}
|
|
else
|
|
{
|
|
// a default datatype may indicate either an attribute query, or if a Fixed Value
|
|
// is present then it's a LOV constraint with a value selected
|
|
Object value = search.getFixedValueQuery(QName.createQName(qname));
|
|
if (value != null)
|
|
{
|
|
properties.getCustomProperties().put(UISearchCustomProperties.PREFIX_LOV_ITEM + qname, value);
|
|
properties.getCustomProperties().put(qname, Boolean.TRUE);
|
|
}
|
|
else
|
|
{
|
|
properties.getCustomProperties().put(qname, search.getAttributeQuery(QName.createQName(qname)));
|
|
}
|
|
properties.getPanels().put(PANEL_CUSTOM, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return NodeRef to the last Node referenced on the end of the specified xpath value
|
|
*
|
|
* @param xpath XPath - note that any /* or //* will be removed to find trailing node
|
|
*
|
|
* @return NodeRef if found null otherwise
|
|
*/
|
|
private NodeRef findNodeRefFromPath(String xpath)
|
|
{
|
|
if (xpath.endsWith("//*"))
|
|
{
|
|
xpath = xpath.substring(0, xpath.lastIndexOf("//*"));
|
|
}
|
|
else if (xpath.endsWith("/*"))
|
|
{
|
|
xpath = xpath.substring(0, xpath.lastIndexOf("/*"));
|
|
}
|
|
NodeRef rootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId(FacesContext.getCurrentInstance()));
|
|
List<NodeRef> results = null;
|
|
try
|
|
{
|
|
results = getSearchService().selectNodes(
|
|
rootRef,
|
|
xpath,
|
|
null,
|
|
getNamespaceService(),
|
|
false);
|
|
}
|
|
catch (AccessDeniedException err)
|
|
{
|
|
// ignore and return null
|
|
}
|
|
|
|
return (results != null && results.size() == 1) ? results.get(0) : null;
|
|
}
|
|
|
|
/**
|
|
* @return the cached reference to the shared Saved Searches folder
|
|
*/
|
|
protected NodeRef getUserSearchesRef()
|
|
{
|
|
if (properties.getUserSearchesRef() == null)
|
|
{
|
|
NodeRef globalRef = getGlobalSearchesRef();
|
|
if (globalRef != null)
|
|
{
|
|
FacesContext fc = FacesContext.getCurrentInstance();
|
|
User user = Application.getCurrentUser(fc);
|
|
String userName = ISO9075.encode(user.getUserName());
|
|
String xpath = NamespaceService.APP_MODEL_PREFIX + ":" + QName.createValidLocalName(userName);
|
|
|
|
List<NodeRef> results = null;
|
|
try
|
|
{
|
|
results = getSearchService().selectNodes(
|
|
globalRef,
|
|
xpath,
|
|
null,
|
|
getNamespaceService(),
|
|
false);
|
|
}
|
|
catch (AccessDeniedException err)
|
|
{
|
|
// ignore and return null
|
|
}
|
|
|
|
if (results != null)
|
|
{
|
|
if (results.size() == 1)
|
|
{
|
|
properties.setUserSearchesRef(results.get(0));
|
|
}
|
|
else if (results.size() == 0 && new Node(globalRef).hasPermission(PermissionService.ADD_CHILDREN))
|
|
{
|
|
// attempt to create folder for this user for first time
|
|
// create the preferences Node for this user
|
|
ChildAssociationRef childRef = getNodeService().createNode(
|
|
globalRef,
|
|
ContentModel.ASSOC_CONTAINS,
|
|
QName.createQName(NamespaceService.APP_MODEL_1_0_URI, QName.createValidLocalName(user.getUserName())),
|
|
ContentModel.TYPE_FOLDER,
|
|
null);
|
|
|
|
properties.setUserSearchesRef(childRef.getChildRef());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return properties.getUserSearchesRef();
|
|
}
|
|
|
|
/**
|
|
* @return the cached reference to the global Saved Searches folder
|
|
*/
|
|
protected NodeRef getGlobalSearchesRef()
|
|
{
|
|
if (properties.getGlobalSearchesRef() == null)
|
|
{
|
|
FacesContext fc = FacesContext.getCurrentInstance();
|
|
String xpath = Application.getRootPath(fc) + "/" +
|
|
Application.getGlossaryFolderName(fc) + "/" +
|
|
Application.getSavedSearchesFolderName(fc);
|
|
|
|
List<NodeRef> results = null;
|
|
try
|
|
{
|
|
results = getSearchService().selectNodes(
|
|
getNodeService().getRootNode(Repository.getStoreRef()),
|
|
xpath,
|
|
null,
|
|
getNamespaceService(),
|
|
false);
|
|
}
|
|
catch (AccessDeniedException err)
|
|
{
|
|
// ignore and return null
|
|
}
|
|
|
|
if (results != null && results.size() == 1)
|
|
{
|
|
properties.setGlobalSearchesRef(results.get(0));
|
|
}
|
|
}
|
|
|
|
return properties.getGlobalSearchesRef();
|
|
}
|
|
|
|
/**
|
|
* Action handler called when the Add button is pressed to add the current Category selection
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public void addCategory(ActionEvent event)
|
|
{
|
|
UIAjaxCategoryPicker selector = (UIAjaxCategoryPicker)event.getComponent().findComponent("catSelector");
|
|
UISelectBoolean chkChildren = (UISelectBoolean)event.getComponent().findComponent("chkCatChildren");
|
|
|
|
List<NodeRef> categoryRefs = (List<NodeRef>)selector.getValue();
|
|
if (categoryRefs != null)
|
|
{
|
|
for (NodeRef categoryRef : categoryRefs)
|
|
{
|
|
Node categoryNode = new MapNode(categoryRef);
|
|
// add a value bound propery used to indicate if searching across children is selected
|
|
categoryNode.getProperties().put(INCLUDE_CHILDREN, chkChildren.isSelected());
|
|
properties.getCategories().add(categoryNode);
|
|
}
|
|
// clear selector value after the list has been populated
|
|
selector.setValue(null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Action handler called when the Remove button is pressed to remove a category
|
|
*/
|
|
public void removeCategory(ActionEvent event)
|
|
{
|
|
Node node = (Node) properties.getCategoriesDataModel().getRowData();
|
|
if (node != null)
|
|
{
|
|
properties.getCategories().remove(node);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return ClientConfigElement
|
|
*/
|
|
private AdvancedSearchConfigElement getSearchConfig()
|
|
{
|
|
if (properties.getSearchConfigElement() == null)
|
|
{
|
|
properties.setSearchConfigElement((AdvancedSearchConfigElement)Application.getConfigService(
|
|
FacesContext.getCurrentInstance()).getConfig("Advanced Search").
|
|
getConfigElement(AdvancedSearchConfigElement.CONFIG_ELEMENT_ID));
|
|
}
|
|
|
|
return properties.getSearchConfigElement();
|
|
}
|
|
|
|
/**
|
|
* Helper map to lookup custom property QName strings against a DataTypeDefinition
|
|
*
|
|
* @return custom property lookup Map
|
|
*/
|
|
private Map<String, DataTypeDefinition> getCustomPropertyLookup()
|
|
{
|
|
if ((properties.getCustomPropertyLookup() == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
|
|
{
|
|
properties.setCustomPropertyLookup(new HashMap<String, DataTypeDefinition>(7, 1.0f));
|
|
List<CustomProperty> customProps = getSearchConfig().getCustomProperties();
|
|
if (customProps != null)
|
|
{
|
|
DictionaryService dd = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getDictionaryService();
|
|
for (CustomProperty customProp : customProps)
|
|
{
|
|
PropertyDefinition propDef = null;
|
|
QName propQName = Repository.resolveToQName(customProp.Property);
|
|
if (customProp.Type != null)
|
|
{
|
|
QName type = Repository.resolveToQName(customProp.Type);
|
|
TypeDefinition typeDef = dd.getType(type);
|
|
propDef = typeDef.getProperties().get(propQName);
|
|
}
|
|
else if (customProp.Aspect != null)
|
|
{
|
|
QName aspect = Repository.resolveToQName(customProp.Aspect);
|
|
AspectDefinition aspectDef = dd.getAspect(aspect);
|
|
propDef = aspectDef.getProperties().get(propQName);
|
|
}
|
|
|
|
if (propQName != null && propDef != null)
|
|
{
|
|
properties.getCustomPropertyLookup().put(propQName.toString(), propDef.getDataType());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return properties.getCustomPropertyLookup();
|
|
}
|
|
|
|
/**
|
|
* Save the state of the progressive panel that was expanded/collapsed
|
|
*/
|
|
public void expandPanel(ActionEvent event)
|
|
{
|
|
if (event instanceof ExpandedEvent)
|
|
{
|
|
properties.getPanels().put(event.getComponent().getId(), ((ExpandedEvent) event).State);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String getFinishButtonLabel()
|
|
{
|
|
return Application.getMessage(FacesContext.getCurrentInstance(), MSG_SAVE);
|
|
}
|
|
|
|
@Override
|
|
protected String finishImpl(FacesContext context, String outcome) throws Exception
|
|
{
|
|
return null;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Private data
|
|
|
|
protected SearchProperties properties;
|
|
|
|
private static final String MSG_ALL_FORMATS = "all_formats";
|
|
private static final String MSG_ERROR_RESTORE_SEARCH = "error_restore_search";
|
|
private static final String MSG_SELECT_SAVED_SEARCH = "select_saved_search";
|
|
private static final String MSG_SAVE = "save";
|
|
|
|
private static final String OUTCOME_BROWSE = "browse";
|
|
|
|
private static final String PANEL_CUSTOM = "custom-panel";
|
|
private static final String PANEL_ATTRS = "attrs-panel";
|
|
private static final String PANEL_CATEGORIES = "categories-panel";
|
|
private static final String PANEL_RESTRICT = "restrict-panel";
|
|
private static final String PANEL_LOCATION = "location-panel";
|
|
|
|
private static final String INCLUDE_CHILDREN = "includeChildren";
|
|
|
|
private static final String MODE_ALL = "all";
|
|
private static final String MODE_FILES_TEXT = "files_text";
|
|
private static final String MODE_FILES = "files";
|
|
private static final String MODE_FOLDERS = "folders";
|
|
|
|
private static final String LOOKIN_ALL = "all";
|
|
private static final String LOOKIN_OTHER = "other";
|
|
|
|
private static final String SAVED_SEARCHES_USER = "user";
|
|
private static final String SAVED_SEARCHES_GLOBAL = "global";
|
|
|
|
private static final String NO_SELECTION = "NONE";
|
|
}
|