/*
* 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.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.MatrixConcatFunction;
import org.jaxen.function.ext.UpperFunction;
import org.jaxen.function.xslt.DocumentFunction;
/**
* Represents an xpath statement that resolves against a
* NodeService
*
* @author Andy Hind
*/
public class NodeServiceXPath extends BaseXPath
{
private static final long serialVersionUID = 3834032441789592882L;
private static String JCR_URI = "http://www.jcp.org/jcr/1.0";
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.
*
* 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