/*
* Copyright (C) 2005 Alfresco, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
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