/**
* Copyright 2011 meltmedia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.xchain.framework.jxpath;
import org.apache.commons.jxpath.PackageFunctions;
import org.apache.commons.jxpath.FunctionLibrary;
import org.apache.commons.jxpath.Functions;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
import org.apache.commons.jxpath.JXPathException;
import org.xchain.framework.jxpath.GenericsWisePackageFunctions;
import org.xchain.framework.lifecycle.Lifecycle;
/**
* An implementation of JXPathContext that installs an instance of scoped QName variables into the
* context.
*
* @author Christian Trimble
* @author Devon Tackett
* @author John Trimble
*/
public class ScopedJXPathContextImpl
extends JXPathContextReferenceImpl
{
private static final PackageFunctions GENERIC_FUNCTIONS = new GenericsWisePackageFunctions("", null);
private Scope scope;
public ScopedJXPathContextImpl(JXPathContext parentContext, Object contextBean, Scope scope)
{
super(parentContext, contextBean);
this.scope = scope;
// Create the variables with a reference to a possible parent context.
setVariables(createQNameVariables(parentContext));
// If present, use the namespaceResolver from the parentContext.
if (parentContext != null)
namespaceResolver = ((JXPathContextReferenceImpl)parentContext).getNamespaceResolver();
setFunctions(createFunctions(parentContext));
setLenient(true);
}
/**
* Creates a new ScopedJXPathContextImpl.
*/
public ScopedJXPathContextImpl( JXPathContext parentContext, Object contextBean, Pointer contextPointer, Scope scope)
{
super( parentContext, contextBean, contextPointer );
this.scope = scope;
// Create the variables with a reference to a possible parent context.
setVariables(createQNameVariables(parentContext));
// If present, use the namespaceResolver from the parentContext.
if (parentContext != null)
namespaceResolver = ((JXPathContextReferenceImpl)parentContext).getNamespaceResolver();
setFunctions(createFunctions(parentContext));
setLenient(true);
}
public JXPathContext getRelativeContext(Pointer pointer)
{
Object contextBean = pointer.getNode();
if (contextBean == null) {
throw new JXPathException("Cannot create a relative context for a non-existent node: "+pointer);
}
return new ScopedJXPathContextImpl(this, contextBean, pointer, scope);
}
/**
* Creates the proper qName variables for this parent context. If the given parentContext is
* a LocalJXPathContext then the QNameVariables will be shared with the parentContext. If the
* given parentContext is not a LocalJXPathContext then the QNameVariables will be able to reference
* variables in the parent context but values in the create QNameVariables will not be available to
* the parent context.
*
* @param parentContext The parent context to build from.
*
* @return The ScopedQNameVariables for this JXPathContext.
*/
private ScopedQNameVariables createQNameVariables( JXPathContext parentContext )
{
ScopedQNameVariables variables = null;
if (parentContext != null) {
// Create a new instance of the ScopedQNameVariables with a reference to the parent context's variables.
variables = new ScopedQNameVariablesImpl(this, ((ScopedQNameVariables)parentContext.getVariables()), scope);
} else {
// Create a new instance of the ScopedQNameVariables with no reference to the parent context.
variables = new ScopedQNameVariablesImpl(this, null, scope);
}
return variables;
}
private Functions createFunctions( JXPathContext parent )
{
if( parent == null && Lifecycle.getLifecycleContext() != null ) {
FunctionLibrary library = new NamespaceResolvingFunctionLibrary(namespaceResolver);
library.addFunctions(Lifecycle.getLifecycleContext().getFunctionLibrary());
return library;
}
else if( parent != null ) {
return parent.getFunctions();
}
else {
return getFunctions();
}
}
/**
* <p>This method corrects casting behavior for the Java 5 Enum type.</p>
*
* @param expression the expression to evaluate.
* @param type the type of object to return.
* @return the value returned after evaluating the expression.
*/
/*
public Object getValue( String jxpath, Class type )
{
if( Enum.class.isAssignableFrom(type) ) {
Object value = super.getValue( jxpath, Object.class );
if( value == null ) {
return null;
}
else if( type.isAssignableFrom(value.getClass()) ) {
return value;
}
else {
return Enum.valueOf( type, value.toString() );
}
}
else {
return super.getValue( jxpath, type );
}
}
*/
/**
* Release all components generated in this context.
*/
public void releaseComponents() {
ScopedQNameVariablesImpl vars = (ScopedQNameVariablesImpl)getVariables();
vars.releaseComponents();
}
public Scope getScope() {
return scope;
}
/**
* Overridden to insure an instance of <code>GenericsWisePackageFunctions</code> is returned by
* default, when a Functions instance hasn't been set explicitly, instead of a
* <code>PackageFunctions</code> instance.
*/
@Override
public Functions getFunctions() {
if( this.functions != null )
return this.functions;
return ScopedJXPathContextImpl.GENERIC_FUNCTIONS;
}
}