mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-22 15:12:38 +00:00 
			
		
		
		
	125606 rmunteanu: Merged 5.1.1 (5.1.1) to 5.1.N (5.1.2)
      125515 slanglois: MNT-16155 Update source headers - add new Copyrights for Java and JSP source files + automatic check in the build
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@125788 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
		
	
		
			
				
	
	
		
			697 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			697 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| /*
 | |
|  * #%L
 | |
|  * Alfresco Repository
 | |
|  * %%
 | |
|  * Copyright (C) 2005 - 2016 Alfresco Software Limited
 | |
|  * %%
 | |
|  * This file is part of the Alfresco software. 
 | |
|  * If the software was purchased under a paid Alfresco license, the terms of 
 | |
|  * the paid license agreement will prevail.  Otherwise, the software is 
 | |
|  * provided under the following open source license terms:
 | |
|  * 
 | |
|  * 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/>.
 | |
|  * #L%
 | |
|  */
 | |
| package org.alfresco.repo.search;
 | |
| 
 | |
| import java.util.ArrayList;
 | |
| import java.util.HashSet;
 | |
| import java.util.List;
 | |
| import java.util.Set;
 | |
| import java.util.StringTokenizer;
 | |
| 
 | |
| import org.alfresco.error.AlfrescoRuntimeException;
 | |
| import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
 | |
| import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | |
| import org.alfresco.service.cmr.repository.NodeRef;
 | |
| import org.alfresco.service.cmr.search.QueryParameterDefinition;
 | |
| import org.alfresco.service.cmr.search.SearchParameters;
 | |
| import org.alfresco.service.namespace.NamespacePrefixResolver;
 | |
| import org.alfresco.service.namespace.QName;
 | |
| import org.alfresco.service.namespace.QNamePattern;
 | |
| import org.alfresco.util.ISO9075;
 | |
| import org.apache.commons.logging.Log;
 | |
| import org.apache.commons.logging.LogFactory;
 | |
| import org.jaxen.BaseXPath;
 | |
| import org.jaxen.Context;
 | |
| import org.jaxen.Function;
 | |
| import org.jaxen.FunctionCallException;
 | |
| import org.jaxen.FunctionContext;
 | |
| import org.jaxen.JaxenException;
 | |
| import org.jaxen.Navigator;
 | |
| import org.jaxen.SimpleFunctionContext;
 | |
| import org.jaxen.SimpleVariableContext;
 | |
| import org.jaxen.function.BooleanFunction;
 | |
| import org.jaxen.function.CeilingFunction;
 | |
| import org.jaxen.function.ConcatFunction;
 | |
| import org.jaxen.function.ContainsFunction;
 | |
| import org.jaxen.function.CountFunction;
 | |
| import org.jaxen.function.FalseFunction;
 | |
| import org.jaxen.function.FloorFunction;
 | |
| import org.jaxen.function.IdFunction;
 | |
| import org.jaxen.function.LangFunction;
 | |
| import org.jaxen.function.LastFunction;
 | |
| import org.jaxen.function.LocalNameFunction;
 | |
| import org.jaxen.function.NameFunction;
 | |
| import org.jaxen.function.NamespaceUriFunction;
 | |
| import org.jaxen.function.NormalizeSpaceFunction;
 | |
| import org.jaxen.function.NotFunction;
 | |
| import org.jaxen.function.NumberFunction;
 | |
| import org.jaxen.function.PositionFunction;
 | |
| import org.jaxen.function.RoundFunction;
 | |
| import org.jaxen.function.StartsWithFunction;
 | |
| import org.jaxen.function.StringFunction;
 | |
| import org.jaxen.function.StringLengthFunction;
 | |
| import org.jaxen.function.SubstringAfterFunction;
 | |
| import org.jaxen.function.SubstringBeforeFunction;
 | |
| import org.jaxen.function.SubstringFunction;
 | |
| import org.jaxen.function.SumFunction;
 | |
| import org.jaxen.function.TranslateFunction;
 | |
| import org.jaxen.function.TrueFunction;
 | |
| import org.jaxen.function.ext.EndsWithFunction;
 | |
| import org.jaxen.function.ext.EvaluateFunction;
 | |
| import org.jaxen.function.ext.LowerFunction;
 | |
| import org.jaxen.function.ext.UpperFunction;
 | |
| import org.jaxen.function.xslt.DocumentFunction;
 | |
| 
 | |
| /**
 | |
|  * Represents an xpath statement that resolves against a
 | |
|  * <code>NodeService</code>
 | |
|  * 
 | |
|  * @author Andy Hind
 | |
|  */
 | |
| public class NodeServiceXPath extends BaseXPath
 | |
| {
 | |
|     private static final long serialVersionUID = 3834032441789592882L;
 | |
| 
 | |
|     private static Log logger = LogFactory.getLog(NodeServiceXPath.class);
 | |
| 
 | |
|     /**
 | |
|      * 
 | |
|      * @param xpath
 | |
|      *            the xpath statement
 | |
|      * @param documentNavigator
 | |
|      *            the navigator that will allow the xpath to be resolved
 | |
|      * @param paramDefs
 | |
|      *            parameters to resolve variables required by xpath
 | |
|      * @throws JaxenException
 | |
|      */
 | |
|     public NodeServiceXPath(String xpath, DocumentNavigator documentNavigator, QueryParameterDefinition[] paramDefs)
 | |
|             throws JaxenException
 | |
|     {
 | |
|         super(xpath, documentNavigator);
 | |
| 
 | |
|         if (logger.isDebugEnabled())
 | |
|         {
 | |
|             StringBuilder sb = new StringBuilder();
 | |
|             sb.append("Created XPath: \n")
 | |
|               .append("   XPath: ").append(xpath).append("\n")
 | |
|               .append("   Parameters: \n");
 | |
|             for (int i = 0; paramDefs != null && i < paramDefs.length; i++)
 | |
|             {
 | |
|                 sb.append("      Parameter: \n")
 | |
|                   .append("         name: ").append(paramDefs[i].getQName()).append("\n")
 | |
|                   .append("         value: ").append(paramDefs[i].getDefault()).append("\n");
 | |
|             }
 | |
|             logger.debug(sb.toString());
 | |
|         }
 | |
|         
 | |
|         // Add support for parameters
 | |
|         if (paramDefs != null)
 | |
|         {
 | |
|             SimpleVariableContext svc = (SimpleVariableContext) this.getVariableContext();
 | |
|             for (int i = 0; i < paramDefs.length; i++)
 | |
|             {
 | |
|                 if (!paramDefs[i].hasDefaultValue())
 | |
|                 {
 | |
|                     throw new AlfrescoRuntimeException("Parameter must have default value");
 | |
|                 }
 | |
|                 Object value = null;
 | |
|                 if (paramDefs[i].getDataTypeDefinition().getName().equals(DataTypeDefinition.BOOLEAN))
 | |
|                 {
 | |
|                     value = Boolean.valueOf(paramDefs[i].getDefault());
 | |
|                 }
 | |
|                 else if (paramDefs[i].getDataTypeDefinition().getName().equals(DataTypeDefinition.DOUBLE))
 | |
|                 {
 | |
|                     value = Double.valueOf(paramDefs[i].getDefault());
 | |
|                 }
 | |
|                 else if (paramDefs[i].getDataTypeDefinition().getName().equals(DataTypeDefinition.FLOAT))
 | |
|                 {
 | |
|                     value = Float.valueOf(paramDefs[i].getDefault());
 | |
|                 }
 | |
|                 else if (paramDefs[i].getDataTypeDefinition().getName().equals(DataTypeDefinition.INT))
 | |
|                 {
 | |
|                     value = Integer.valueOf(paramDefs[i].getDefault());
 | |
|                 }
 | |
|                 else if (paramDefs[i].getDataTypeDefinition().getName().equals(DataTypeDefinition.LONG))
 | |
|                 {
 | |
|                     value = Long.valueOf(paramDefs[i].getDefault());
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     value = paramDefs[i].getDefault();
 | |
|                 }
 | |
|                 svc.setVariableValue(paramDefs[i].getQName().getNamespaceURI(), paramDefs[i].getQName().getLocalName(),
 | |
|                         value);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         for (String prefix : documentNavigator.getNamespacePrefixResolver().getPrefixes())
 | |
|         {
 | |
|             addNamespace(prefix, documentNavigator.getNamespacePrefixResolver().getNamespaceURI(prefix));
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Jaxen has some magic with its IdentitySet, which means that we can get different results
 | |
|      * depending on whether we cache {@link ChildAssociationRef } instances or not.
 | |
|      * <p>
 | |
|      * So, duplicates are eliminated here before the results are returned.
 | |
|      */
 | |
|     @SuppressWarnings("unchecked")
 | |
|     @Override
 | |
|     public List selectNodes(Object arg0) throws JaxenException
 | |
|     {
 | |
|         if (logger.isDebugEnabled())
 | |
|         {
 | |
|             logger.debug("Selecting using XPath: \n" +
 | |
|                     "   XPath: " + this + "\n" +
 | |
|                     "   starting at: " + arg0);
 | |
|         }
 | |
|         
 | |
|         List<Object> resultsWithDuplicates = super.selectNodes(arg0);
 | |
|         
 | |
|         Set<Object> set = new HashSet<Object>(resultsWithDuplicates);
 | |
|         
 | |
|         // now return as a list again
 | |
|         List<Object> results = resultsWithDuplicates;
 | |
|         results.clear();
 | |
|         results.addAll(set);
 | |
|         
 | |
|         // done
 | |
|         return results;
 | |
|     }
 | |
| 
 | |
|     public static class FirstFunction implements Function
 | |
|     {
 | |
| 
 | |
|         public Object call(Context context, List args) throws FunctionCallException
 | |
|         {
 | |
|             if (args.size() == 0)
 | |
|             {
 | |
|                 return evaluate(context);
 | |
|             }
 | |
| 
 | |
|             throw new FunctionCallException("first() requires no arguments.");
 | |
|         }
 | |
| 
 | |
|         public static Double evaluate(Context context)
 | |
|         {
 | |
|             return new Double(1);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * A boolean function to determine if a node type is a subtype of another type
 | |
|      */
 | |
|     static class SubTypeOf implements Function
 | |
|     {
 | |
|         public Object call(Context context, List args) throws FunctionCallException
 | |
|         {
 | |
|             if (args.size() != 1)
 | |
|             {
 | |
|                 throw new FunctionCallException("subtypeOf() requires one argument: subtypeOf(QName typeQName)");
 | |
|             }
 | |
|             return evaluate(context.getNodeSet(), args.get(0), context.getNavigator());
 | |
|         }
 | |
| 
 | |
|         public Object evaluate(List nodes, Object qnameObj, Navigator nav)
 | |
|         {
 | |
|             if (nodes.size() != 1)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
|             // resolve the qname of the type we are checking for
 | |
|             String qnameStr = StringFunction.evaluate(qnameObj, nav);
 | |
|             if (qnameStr.equals("*"))
 | |
|             {
 | |
|                 return true;
 | |
|             }
 | |
|             QName typeQName;
 | |
| 
 | |
|             if (qnameStr.startsWith("{"))
 | |
|             {
 | |
|                 typeQName = QName.createQName(qnameStr);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 typeQName = QName.createQName(qnameStr, ((DocumentNavigator) nav).getNamespacePrefixResolver());
 | |
|             }
 | |
|             // resolve the noderef
 | |
|             NodeRef nodeRef = null;
 | |
|             if (nav.isElement(nodes.get(0)))
 | |
|             {
 | |
|                 nodeRef = ((ChildAssociationRef) nodes.get(0)).getChildRef();
 | |
|             }
 | |
|             else if (nav.isAttribute(nodes.get(0)))
 | |
|             {
 | |
|                 nodeRef = ((DocumentNavigator.Property) nodes.get(0)).parent;
 | |
|             }
 | |
| 
 | |
|             DocumentNavigator dNav = (DocumentNavigator) nav;
 | |
|             boolean result = dNav.isSubtypeOf(nodeRef, typeQName);
 | |
|             return result;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * A boolean function to determine if a node has a given aspect
 | |
|      */
 | |
|     static class HasAspect implements Function
 | |
|     {
 | |
|         public Object call(Context context, List args) throws FunctionCallException
 | |
|         {
 | |
|             if (args.size() != 1)
 | |
|             {
 | |
|                 throw new FunctionCallException("hasAspect() requires one argument: hasAspect(QName typeQName)");
 | |
|             }
 | |
|             return evaluate(context.getNodeSet(), args.get(0), context.getNavigator());
 | |
|         }
 | |
| 
 | |
|         public Object evaluate(List nodes, Object qnameObj, Navigator nav)
 | |
|         {
 | |
|             if (nodes.size() != 1)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
|             // resolve the qname of the type we are checking for
 | |
|             String qnameStr = StringFunction.evaluate(qnameObj, nav);
 | |
|             if (qnameStr.equals("*"))
 | |
|             {
 | |
|                 return true;
 | |
|             }
 | |
|             QName typeQName;
 | |
| 
 | |
|             if (qnameStr.startsWith("{"))
 | |
|             {
 | |
|                 typeQName = QName.createQName(qnameStr);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 typeQName = QName.createQName(qnameStr, ((DocumentNavigator) nav).getNamespacePrefixResolver());
 | |
|             }
 | |
|             // resolve the noderef
 | |
|             NodeRef nodeRef = null;
 | |
|             if (nav.isElement(nodes.get(0)))
 | |
|             {
 | |
|                 nodeRef = ((ChildAssociationRef) nodes.get(0)).getChildRef();
 | |
|             }
 | |
|             else if (nav.isAttribute(nodes.get(0)))
 | |
|             {
 | |
|                 nodeRef = ((DocumentNavigator.Property) nodes.get(0)).parent;
 | |
|             }
 | |
| 
 | |
|             DocumentNavigator dNav = (DocumentNavigator) nav;
 | |
|             boolean result = dNav.hasAspect(nodeRef, typeQName);
 | |
|             return result;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static class Deref implements Function
 | |
|     {
 | |
| 
 | |
|         public Object call(Context context, List args) throws FunctionCallException
 | |
|         {
 | |
|             if (args.size() == 2)
 | |
|             {
 | |
|                 return evaluate(args.get(0), args.get(1), context.getNavigator());
 | |
|             }
 | |
| 
 | |
|             throw new FunctionCallException("deref() requires two arguments.");
 | |
|         }
 | |
| 
 | |
|         public Object evaluate(Object attributeName, Object pattern, Navigator nav)
 | |
|         {
 | |
|             List<Object> answer = new ArrayList<Object>();
 | |
|             String attributeValue = StringFunction.evaluate(attributeName, nav);
 | |
|             String patternValue = StringFunction.evaluate(pattern, nav);
 | |
| 
 | |
|             // TODO: Ignore the pattern for now
 | |
|             // Should do a type pattern test
 | |
|             if ((attributeValue != null) && (attributeValue.length() > 0))
 | |
|             {
 | |
|                 DocumentNavigator dNav = (DocumentNavigator) nav;
 | |
|                 NodeRef nodeRef = new NodeRef(attributeValue);
 | |
|                 if (patternValue.equals("*"))
 | |
|                 {
 | |
|                     answer.add(dNav.getNode(nodeRef));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     QNamePattern qNamePattern = new JCRPatternMatch(patternValue, dNav.getNamespacePrefixResolver());
 | |
|                     answer.addAll(dNav.getNode(nodeRef, qNamePattern));
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|             return answer;
 | |
| 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * A boolean function to determine if a node property matches a pattern
 | |
|      * and/or the node text matches the pattern.
 | |
|      * <p>
 | |
|      * The default is JSR170 compliant. The optional boolean allows searching
 | |
|      * only against the property value itself.
 | |
|      * <p>
 | |
|      * The search is always case-insensitive.
 | |
|      * 
 | |
|      * @author Derek Hulley
 | |
|      */
 | |
|     static class Like implements Function
 | |
|     {
 | |
|         public Object call(Context context, List args) throws FunctionCallException
 | |
|         {
 | |
|             if (args.size() < 2 || args.size() > 3)
 | |
|             {
 | |
|                 throw new FunctionCallException("like() usage: like(@attr, 'pattern' [, includeFTS]) \n"
 | |
|                         + " - includeFTS can be 'true' or 'false' \n"
 | |
|                         + " - search is case-insensitive");
 | |
|             }
 | |
|             // default includeFTS to true
 | |
|             return evaluate(context.getNodeSet(), args.get(0), args.get(1), args.size() == 2 ? Boolean.toString(true)
 | |
|                     : args.get(2), context.getNavigator());
 | |
|         }
 | |
| 
 | |
|         public Object evaluate(List nodes, Object obj, Object patternObj, Object includeFtsObj, Navigator nav)
 | |
|         {
 | |
|             Object attribute = null;
 | |
|             if (obj instanceof List)
 | |
|             {
 | |
|                 List list = (List) obj;
 | |
|                 if (list.isEmpty())
 | |
|                 {
 | |
|                     return false;
 | |
|                 }
 | |
|                 // do not recurse: only first list should unwrap
 | |
|                 attribute = list.get(0);
 | |
|             }
 | |
|             if ((attribute == null) || !nav.isAttribute(attribute))
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
|             if (nodes.size() != 1)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
|             if (!nav.isElement(nodes.get(0)))
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
|             ChildAssociationRef car = (ChildAssociationRef) nodes.get(0);
 | |
|             String pattern = StringFunction.evaluate(patternObj, nav);
 | |
|             boolean includeFts = BooleanFunction.evaluate(includeFtsObj, nav);
 | |
|             QName qname = QName.createQName(nav.getAttributeNamespaceUri(attribute), ISO9075.decode(nav
 | |
|                     .getAttributeName(attribute)));
 | |
| 
 | |
|             DocumentNavigator dNav = (DocumentNavigator) nav;
 | |
|             // JSR 170 includes full text matches
 | |
|             return dNav.like(car.getChildRef(), qname, pattern, includeFts);
 | |
| 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static class Contains implements Function
 | |
|     {
 | |
| 
 | |
|         public Object call(Context context, List args) throws FunctionCallException
 | |
|         {
 | |
|             if (args.size() != 1)
 | |
|             {
 | |
|                 throw new FunctionCallException("contains() usage: contains('pattern')");
 | |
|             }
 | |
|             return evaluate(context.getNodeSet(), args.get(0), context.getNavigator());
 | |
|         }
 | |
| 
 | |
|         public Object evaluate(List nodes, Object pattern, Navigator nav)
 | |
|         {
 | |
|             if (nodes.size() != 1)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
|             QName qname = null;
 | |
|             NodeRef nodeRef = null;
 | |
|             if (nav.isElement(nodes.get(0)))
 | |
|             {
 | |
|                 qname = null; // should use all attributes and full text index
 | |
|                 nodeRef = ((ChildAssociationRef) nodes.get(0)).getChildRef();
 | |
|             }
 | |
|             else if (nav.isAttribute(nodes.get(0)))
 | |
|             {
 | |
|                 qname = QName.createQName(
 | |
|                         nav.getAttributeNamespaceUri(nodes.get(0)),
 | |
|                         ISO9075.decode(nav.getAttributeName(nodes.get(0))));
 | |
|                 nodeRef = ((DocumentNavigator.Property) nodes.get(0)).parent;
 | |
|             }
 | |
| 
 | |
|             String patternValue = StringFunction.evaluate(pattern, nav);
 | |
|             DocumentNavigator dNav = (DocumentNavigator) nav;
 | |
| 
 | |
|             return dNav.contains(nodeRef, qname, patternValue, SearchParameters.OR);
 | |
| 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static class Score implements Function
 | |
|     {
 | |
|         private Double one = new Double(1);
 | |
| 
 | |
|         public Object call(Context context, List args) throws FunctionCallException
 | |
|         {
 | |
|             return evaluate(context.getNodeSet(), context.getNavigator());
 | |
|         }
 | |
| 
 | |
|         public Object evaluate(List nodes, Navigator nav)
 | |
|         {
 | |
|             return one;
 | |
| 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     protected FunctionContext createFunctionContext()
 | |
|     {
 | |
|         return XPathFunctionContext.getInstance();
 | |
|     }
 | |
| 
 | |
|     public static class XPathFunctionContext extends SimpleFunctionContext
 | |
|     {
 | |
|         /**
 | |
|          * Singleton implementation.
 | |
|          */
 | |
|         private static class Singleton
 | |
|         {
 | |
|             /**
 | |
|              * Singleton instance.
 | |
|              */
 | |
|             private static XPathFunctionContext instance = new XPathFunctionContext();
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Retrieve the singleton instance.
 | |
|          * 
 | |
|          * @return the singleton instance
 | |
|          */
 | |
|         public static FunctionContext getInstance()
 | |
|         {
 | |
|             return Singleton.instance;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Construct.
 | |
|          * 
 | |
|          * <p>
 | |
|          * Construct with all core XPath functions registered.
 | |
|          * </p>
 | |
|          */
 | |
|         public XPathFunctionContext()
 | |
|         {
 | |
|             // XXX could this be a HotSpot????
 | |
|             registerFunction("", // namespace URI
 | |
|                     "boolean", new BooleanFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "ceiling", new CeilingFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "concat", new ConcatFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "contains", new ContainsFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "count", new CountFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "document", new DocumentFunction());
 | |
|             
 | |
|             registerFunction("", // namespace URI
 | |
|                     "ends-with", new EndsWithFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "false", new FalseFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "floor", new FloorFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "id", new IdFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "lang", new LangFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "last", new LastFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "local-name", new LocalNameFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "name", new NameFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "namespace-uri", new NamespaceUriFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "normalize-space", new NormalizeSpaceFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "not", new NotFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "number", new NumberFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "position", new PositionFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "round", new RoundFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "starts-with", new StartsWithFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "string", new StringFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "string-length", new StringLengthFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "substring-after", new SubstringAfterFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "substring-before", new SubstringBeforeFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "substring", new SubstringFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "sum", new SumFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "true", new TrueFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "translate", new TranslateFunction());
 | |
| 
 | |
|             // register extension functions
 | |
|             // extension functions should go into a namespace, but which one?
 | |
|             // for now, keep them in default namespace to not break any code
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "evaluate", new EvaluateFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "lower-case", new LowerFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "upper-case", new UpperFunction());
 | |
| 
 | |
|             registerFunction("", // namespace URI
 | |
|                     "ends-with", new EndsWithFunction());
 | |
| 
 | |
|             registerFunction("", "subtypeOf", new SubTypeOf());
 | |
|             registerFunction("", "hasAspect", new HasAspect());
 | |
|             registerFunction("", "deref", new Deref());
 | |
|             registerFunction("", "like", new Like());
 | |
|             registerFunction("", "contains", new Contains());
 | |
| 
 | |
|             registerFunction("", "first", new FirstFunction());
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public static class JCRPatternMatch implements QNamePattern
 | |
|     {
 | |
|         private List<String> searches = new ArrayList<String>();
 | |
| 
 | |
|         private NamespacePrefixResolver resolver;
 | |
| 
 | |
|         /**
 | |
|          * Construct
 | |
|          * 
 | |
|          * @param pattern
 | |
|          *            JCR Pattern
 | |
|          * @param resolver
 | |
|          *            Namespace Prefix Resolver
 | |
|          */
 | |
|         public JCRPatternMatch(String pattern, NamespacePrefixResolver resolver)
 | |
|         {
 | |
|             // TODO: Check for valid pattern
 | |
| 
 | |
|             // Convert to regular expression
 | |
|             String regexPattern = pattern.replaceAll("\\*", ".*");
 | |
| 
 | |
|             // Split into independent search strings
 | |
|             StringTokenizer tokenizer = new StringTokenizer(regexPattern, "|", false);
 | |
|             while (tokenizer.hasMoreTokens())
 | |
|             {
 | |
|                 String disjunct = tokenizer.nextToken().trim();
 | |
|                 this.searches.add(disjunct);
 | |
|             }
 | |
| 
 | |
|             this.resolver = resolver;
 | |
|         }
 | |
| 
 | |
|         /*
 | |
|          * (non-Javadoc)
 | |
|          * 
 | |
|          * @see org.alfresco.service.namespace.QNamePattern#isMatch(org.alfresco.service.namespace.QName)
 | |
|          */
 | |
|         public boolean isMatch(QName qname)
 | |
|         {
 | |
|             String prefixedName = qname.toPrefixString(resolver);
 | |
|             for (String search : searches)
 | |
|             {
 | |
|                 if (prefixedName.matches(search))
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
| }
 |