/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.synapse.util.xpath.ext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseException;
import org.apache.synapse.config.SynapsePropertiesLoader;
import org.apache.synapse.core.SynapseEnvironment;
import org.jaxen.Function;
import javax.xml.namespace.QName;
import java.util.*;
/**
* Utility class to support custom xpath context extensions
*/
public class XpathExtensionUtil {
/**
* The Synapse extension property for variable context extensions
*/
private static final String SYNAPSE_XPATH_VARIABLE_EXTENSIONS = "synapse.xpath.var.extensions";
/**
* The Synapse extension property for function context extensions
*/
private static final String SYNAPSE_XPATH_FUNCTION_EXTENSIONS = "synapse.xpath.func.extensions";
private static final Log log = LogFactory.getLog(XpathExtensionUtil.class);
/**
* Get all registered variable context extensions. Synapse will look for synapse.properties
* property synapse.xpath.var.extensions
*
* @return List of Synapse Xpath Variable Context Providers
*/
public static List<SynapseXpathVariableResolver> getRegisteredVariableExtensions() {
Properties synapseProps = SynapsePropertiesLoader.loadSynapseProperties();
String propValue = synapseProps.getProperty(SYNAPSE_XPATH_VARIABLE_EXTENSIONS);
List<SynapseXpathVariableResolver> extProviders = new
ArrayList<SynapseXpathVariableResolver>();
extractProviders(propValue, extProviders);
return extProviders;
}
/**
* Get all registered function context extensions. Synapse will look for synapse.properties
* property synapse.xpath.func.extensions
*
* @return List of Synapse Xpath Function Context Providers
*/
public static List<SynapseXpathFunctionContextProvider> getRegisteredFunctionExtensions() {
Properties synapseProps = SynapsePropertiesLoader.loadSynapseProperties();
String propValue = synapseProps.getProperty(SYNAPSE_XPATH_FUNCTION_EXTENSIONS);
List<SynapseXpathFunctionContextProvider> extProviders = new
ArrayList<SynapseXpathFunctionContextProvider>();
extractProviders(propValue, extProviders);
return extProviders;
}
/**
* Populate the set of registered Extension proiders for a given property
*
* @param propValue either variable/function provider property name
* @param extProviders a List that will be populated with the registered extensions
* @param <T> Variable/Function Context Provider Type
*/
private static <T> void extractProviders(String propValue, List<T> extProviders) {
if (propValue != null) {
String[] observerNames = propValue.split(",");
for (String observer : observerNames) {
try {
Class clazz = XpathExtensionUtil.class.getClassLoader().
loadClass(observer.trim());
T obj = (T) clazz.newInstance();
extProviders.add(obj);
} catch (Exception e) {
handleException("Error while initializing Synapse Xpath extension providers", e);
}
}
}
}
/**
* Returns a Function Context extension registered for given QName/namespaceURI+prefix+localName
* combination
*
* @param ctxt Synapse Message Context
* @param namespaceURI binding namespace in xpath expression
* @param prefix binding prefix string in xpath expression
* @param localName binding localname string in xpath expression
* @return jaxen Function object for corresponding extension
*/
public static Function getFunctionContext(MessageContext ctxt, String namespaceURI, String prefix,
String localName) {
SynapseEnvironment environment = ctxt.getEnvironment();
if (environment != null) {
Map<QName, SynapseXpathFunctionContextProvider> extensions =
environment.getXpathFunctionExtensions();
SynapseXpathFunctionContextProvider functionContextProvider =
getMatchingExtensionProvider(extensions, namespaceURI, prefix, localName);
if (functionContextProvider != null) {
return initAndReturnXpathFunction(functionContextProvider, ctxt);
}
}
return null;
}
/**
* Returns an object resolved by Variable Context extension registered for given
* QName/namespaceURI+prefix+localName combination
*
* @param ctxt Synapse Message Context
* @param namespaceURI binding namespace in xpath expression
* @param prefix binding prefix string in xpath expression
* @param localName binding localname string in xpath expression
* @return Object variable resolved by corresponding extension
*/
public static Object resolveVariableContext(MessageContext ctxt, String namespaceURI,
String prefix, String localName) {
SynapseEnvironment environment = ctxt.getEnvironment();
if (environment != null) {
Map<QName, SynapseXpathVariableResolver> extensions =
environment.getXpathVariableExtensions();
SynapseXpathVariableResolver variableResolver =
getMatchingExtensionProvider(extensions, namespaceURI, prefix, localName);
if (variableResolver != null) {
return resolveXpathVariable(variableResolver, ctxt);
}
}
return null;
}
/**
* returns the matching Extension provider for a given QName/namespaceURI+prefix+localName
* combination
*
* @param extensionMap registered extension Map for the corresponding extension provider
* @param namespaceURI binding namespace in xpath expression
* @param prefix binding prefix string in xpath expression
* @param localName binding localname string in xpath expression
* @param <T> Variable/Function Context Provider Type
* @return matching Extension provider. returns null if no extension is found for the given
* combination
*/
private static <T> T getMatchingExtensionProvider(Map<QName, T> extensionMap,
String namespaceURI,
String prefix, String localName) {
QName subject;
if (localName != null && prefix != null) {
subject = new QName(namespaceURI, localName, prefix);
} else if (localName != null) {
subject = new QName(namespaceURI, localName);
} else {
//can't resolve xpath extensions - invalid combination
return null;
}
Set<QName> qNames = extensionMap.keySet();
for (QName qName : qNames) {
//check for a match for the given combination for QName registered
if (subject.equals(qName)) {
return extensionMap.get(qName);
}
}
//no match found
return null;
}
/**
* try to resolve an xpath variable context using the extension given
*
* @param variableExt Extension provider for variable contexts
* @param ctxt Synapse Message Context
* @return resolved property/object
*/
private static Object resolveXpathVariable(SynapseXpathVariableResolver variableExt,
MessageContext ctxt) {
try {
return variableExt.resolve(ctxt);
} catch (Exception e) {
handleExceptionWarning("Error Invoking Xpath Variable Provider " +
variableExt.getClass().getName(), e);
}
return null;
}
/**
* Initializes an returns new Xpath Function
*
* @param funcExtProvider extension provider for a Function Context
* @param ctxt Synapse Message Context
* @return Xpath Function instance . returns null if error occurs
*/
private static Function initAndReturnXpathFunction(
SynapseXpathFunctionContextProvider funcExtProvider,
MessageContext ctxt) {
try {
return funcExtProvider.getInitializedExtFunction(ctxt);
} catch (Exception e) {
handleExceptionWarning("Error Initializing Xpath Function Provider " +
funcExtProvider.getClass().getName(), e);
}
return null;
}
private static void handleException(String msg, Exception e) {
log.warn(msg, e);
throw new SynapseException(msg, e);
}
private static void handleExceptionWarning(String msg, Exception e) {
log.warn(msg, e);
}
}