diff --git a/source/java/org/alfresco/repo/template/BasePathResultsMap.java b/source/java/org/alfresco/repo/template/BasePathResultsMap.java index 31d0f3dfc7..74e0d98bc1 100644 --- a/source/java/org/alfresco/repo/template/BasePathResultsMap.java +++ b/source/java/org/alfresco/repo/template/BasePathResultsMap.java @@ -17,7 +17,7 @@ package org.alfresco.repo.template; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collections; import java.util.List; import org.alfresco.service.ServiceRegistry; @@ -32,11 +32,9 @@ import org.apache.commons.logging.LogFactory; * * @author Kevin Roast */ -public abstract class BasePathResultsMap extends HashMap implements Cloneable +public abstract class BasePathResultsMap extends BaseTemplateMap { protected static Log logger = LogFactory.getLog(BasePathResultsMap.class); - protected TemplateNode parent; - protected ServiceRegistry services = null; /** * Constructor @@ -46,16 +44,17 @@ public abstract class BasePathResultsMap extends HashMap implements Cloneable */ public BasePathResultsMap(TemplateNode parent, ServiceRegistry services) { - super(1, 1.0f); - this.services = services; - this.parent = parent; + super(parent, services); } /** - * @see java.util.Map#get(java.lang.Object) + * Return a list or a single Node from executing an xpath against the parent Node. + * + * @param xpath XPath to execute + * @param firstOnly True to return the first result only + * + * @return List */ - public abstract Object get(Object key); - protected List getChildrenByXPath(String xpath, boolean firstOnly) { List result = null; @@ -92,6 +91,6 @@ public abstract class BasePathResultsMap extends HashMap implements Cloneable } } - return result != null ? result : new ArrayList(0); + return result != null ? result : (List)Collections.emptyList(); } } diff --git a/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java b/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java new file mode 100644 index 0000000000..bd07d6bb05 --- /dev/null +++ b/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.template; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.TemplateNode; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchService; + +/** + * Class providing the base Search Query services to execute a search returning a list of + * TemplateNode objects from a Lucene search string. + * + * @author Kevin Roast + */ +public abstract class BaseSearchResultsMap extends BaseTemplateMap +{ + /** + * Constructor + * + * @param parent The parent TemplateNode to execute searches from + * @param services The ServiceRegistry to use + */ + public BaseSearchResultsMap(TemplateNode parent, ServiceRegistry services) + { + super(parent, services); + } + + /** + * Perform a SearchService query with the given Lucene search string + */ + protected List query(String search) + { + List nodes = null; + + // check if a full Lucene search string has been supplied or extracted from XML + if (search != null && search.length() != 0) + { + // perform the search against the repo + ResultSet results = null; + try + { + results = this.services.getSearchService().query( + this.parent.getNodeRef().getStoreRef(), + SearchService.LANGUAGE_LUCENE, + search); + + if (results.length() != 0) + { + nodes = new ArrayList(results.length()); + for (ResultSetRow row: results) + { + NodeRef nodeRef = row.getNodeRef(); + nodes.add(new TemplateNode(nodeRef, services, this.parent.getImageResolver())); + } + } + } + catch (Throwable err) + { + throw new AlfrescoRuntimeException("Failed to execute search: " + search, err); + } + finally + { + if (results != null) + { + results.close(); + } + } + } + + return nodes != null ? nodes : (List)Collections.emptyList(); + } +} diff --git a/source/java/org/alfresco/repo/template/BaseTemplateMap.java b/source/java/org/alfresco/repo/template/BaseTemplateMap.java new file mode 100644 index 0000000000..a9c9d28c79 --- /dev/null +++ b/source/java/org/alfresco/repo/template/BaseTemplateMap.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.template; + +import java.util.HashMap; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.TemplateNode; + +/** + * An abstract Map class that can be used process the parent Node as part of the get() + * Map interface implementation. + * + * @author Kevin Roast + */ +public abstract class BaseTemplateMap extends HashMap implements Cloneable +{ + protected TemplateNode parent; + protected ServiceRegistry services = null; + + /** + * Constructor + * + * @param parent The parent TemplateNode to execute searches from + * @param services The ServiceRegistry to use + */ + public BaseTemplateMap(TemplateNode parent, ServiceRegistry services) + { + super(1, 1.0f); + this.services = services; + this.parent = parent; + } + + /** + * @see java.util.Map#get(java.lang.Object) + */ + public abstract Object get(Object key); +} diff --git a/source/java/org/alfresco/repo/template/LuceneSearchResultsMap.java b/source/java/org/alfresco/repo/template/LuceneSearchResultsMap.java new file mode 100644 index 0000000000..df2cf881e2 --- /dev/null +++ b/source/java/org/alfresco/repo/template/LuceneSearchResultsMap.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.template; + +import java.io.StringReader; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.TemplateNode; +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +/** + * Provides functionality to execute a Lucene search string and return TemplateNode objects. + * + * @author Kevin Roast + */ +public class LuceneSearchResultsMap extends BaseSearchResultsMap +{ + /** + * Constructor + * + * @param parent The parent TemplateNode to execute searches from + * @param services The ServiceRegistry to use + */ + public LuceneSearchResultsMap(TemplateNode parent, ServiceRegistry services) + { + super(parent, services); + } + + /** + * @see org.alfresco.repo.template.BaseTemplateMap#get(java.lang.Object) + */ + public Object get(Object key) + { + // execute the search + return query(key.toString()); + } +} diff --git a/source/java/org/alfresco/repo/template/NamePathResultsMap.java b/source/java/org/alfresco/repo/template/NamePathResultsMap.java index 896d670638..3cf8a77267 100644 --- a/source/java/org/alfresco/repo/template/NamePathResultsMap.java +++ b/source/java/org/alfresco/repo/template/NamePathResultsMap.java @@ -28,7 +28,7 @@ import org.alfresco.service.cmr.repository.TemplateNode; * * @author Kevin Roast */ -public final class NamePathResultsMap extends BasePathResultsMap implements Cloneable +public final class NamePathResultsMap extends BasePathResultsMap { /** * Constructor diff --git a/source/java/org/alfresco/repo/template/SavedSearchResultsMap.java b/source/java/org/alfresco/repo/template/SavedSearchResultsMap.java new file mode 100644 index 0000000000..c2cdd6b10e --- /dev/null +++ b/source/java/org/alfresco/repo/template/SavedSearchResultsMap.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.template; + +import java.io.StringReader; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.TemplateNode; +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +/** + * Provides functionality to load a saved search and execute it to return TemplateNode objects. + * + * @author Kevin Roast + */ +public class SavedSearchResultsMap extends BaseSearchResultsMap +{ + private static final String ELEMENT_QUERY = "query"; + + /** + * Constructor + * + * @param parent The parent TemplateNode to execute searches from + * @param services The ServiceRegistry to use + */ + public SavedSearchResultsMap(TemplateNode parent, ServiceRegistry services) + { + super(parent, services); + } + + /** + * @see org.alfresco.repo.template.BaseTemplateMap#get(java.lang.Object) + */ + public Object get(Object key) + { + String search = null; + + if (key != null && key.toString().length() != 0) + { + // read the Saved Search XML on the specified node - and get the Lucene search from it + try + { + NodeRef ref = new NodeRef(key.toString()); + + ContentReader content = services.getContentService().getReader(ref, ContentModel.PROP_CONTENT); + if (content != null && content.exists()) + { + // get the root element + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(content.getContentString())); + Element rootElement = document.getRootElement(); + + Element queryElement = rootElement.element(ELEMENT_QUERY); + if (queryElement != null) + { + search = queryElement.getText(); + } + } + } + catch (Throwable err) + { + throw new AlfrescoRuntimeException("Failed to find or load saved Search: " + key, err); + } + } + + // execute the search + return query(search); + } +} diff --git a/source/java/org/alfresco/repo/template/XPathResultsMap.java b/source/java/org/alfresco/repo/template/XPathResultsMap.java index 9ececbd310..dcc6a23b47 100644 --- a/source/java/org/alfresco/repo/template/XPathResultsMap.java +++ b/source/java/org/alfresco/repo/template/XPathResultsMap.java @@ -25,7 +25,7 @@ import org.alfresco.service.cmr.repository.TemplateNode; * * @author Kevin Roast */ -public final class XPathResultsMap extends BasePathResultsMap implements Cloneable +public final class XPathResultsMap extends BasePathResultsMap { /** * Constructor diff --git a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java index 82c159affc..fd2f2c4ec4 100644 --- a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java +++ b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java @@ -26,10 +26,11 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.template.LuceneSearchResultsMap; import org.alfresco.repo.template.NamePathResultsMap; +import org.alfresco.repo.template.SavedSearchResultsMap; import org.alfresco.repo.template.XPathResultsMap; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -39,6 +40,7 @@ import org.alfresco.service.namespace.QNameMap; import org.alfresco.service.namespace.RegexQNamePattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.util.StringUtils; import org.xml.sax.InputSource; import freemarker.ext.dom.NodeModel; @@ -211,6 +213,24 @@ public final class TemplateNode implements Serializable return new XPathResultsMap(this, this.services); } + /** + * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Saved Search + * object. The Saved Search is executed and the resulting nodes supplied as a sequence. + */ + public Map getChildrenBySavedSearch() + { + return new SavedSearchResultsMap(this, this.services); + } + + /** + * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Lucene search + * string. The Saved Search is executed and the resulting nodes supplied as a sequence. + */ + public Map getChildrenByLuceneSearch() + { + return new LuceneSearchResultsMap(this, this.services); + } + /** * @return The associations for this Node. As a Map of assoc name to a List of TemplateNodes. */ @@ -493,7 +513,7 @@ public final class TemplateNode implements Serializable nodeRef.getStoreRef().getProtocol(), nodeRef.getStoreRef().getIdentifier(), nodeRef.getId(), - URLEncoder.encode(getName(), "US-ASCII") } ); + StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } ); } catch (UnsupportedEncodingException err) { @@ -602,8 +622,8 @@ public final class TemplateNode implements Serializable nodeRef.getStoreRef().getProtocol(), nodeRef.getStoreRef().getIdentifier(), nodeRef.getId(), - URLEncoder.encode(getName(), "US-ASCII"), - URLEncoder.encode(property.toString(), "US-ASCII") } ); + StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20"), + StringUtils.replace(URLEncoder.encode(property.toString(), "UTF-8"), "+", "%20") } ); } catch (UnsupportedEncodingException err) {