org.ow2.petals.binding.rest.config.RESTConsumesConfiguration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of petals-bc-rest Show documentation
Show all versions of petals-bc-rest Show documentation
petals-bc-rest Binding Component description
/**
* Copyright (c) 2007-2012 EBM WebSourcing, 2012-2020 Linagora
*
* This program/library 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 2.1 of the License, or (at your
* option) any later version.
*
* This program/library 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 this program/library; If not, see http://www.gnu.org/licenses/
* for the GNU Lesser General Public License version 2.1.
*/
package org.ow2.petals.binding.rest.config;
import static org.ow2.petals.binding.rest.RESTConstants.ConsumesParameter.SERVICE_BASE_PATH;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import org.glassfish.jersey.uri.UriTemplate;
import org.ow2.petals.binding.rest.config.incoming.IncomingPayloadGenerator;
import org.ow2.petals.binding.rest.config.incoming.OperationBuilder;
import org.ow2.petals.binding.rest.exchange.incoming.JBIMessage;
import org.ow2.petals.binding.rest.exchange.incoming.onjbiresponse.OnJBIResponse;
import org.ow2.petals.component.framework.api.configuration.AbstractConfigurationParameters;
import org.ow2.petals.component.framework.api.exception.PEtALSCDKException;
import org.ow2.petals.component.framework.jbidescriptor.generated.Consumes;
import org.ow2.petals.component.framework.su.ServiceUnitDataHandler;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.ebmwebsourcing.easycommons.lang.StringHelper;
import com.ebmwebsourcing.easycommons.properties.PropertiesException;
import com.ebmwebsourcing.easycommons.properties.PropertiesHelper;
import com.ebmwebsourcing.easycommons.xml.XMLHelper;
public class RESTConsumesConfiguration extends RESTSUConfiguration {
private static class JBIMessageTemplateMap {
private final Map> jbiMessages = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Logger logger;
/**
* The custom place holders read from the component property file to be able to configure service units.
*/
private final Properties componentPlaceholders;
public JBIMessageTemplateMap(final Properties componentPlaceholders, final Logger logger) {
this.componentPlaceholders = componentPlaceholders;
this.logger = logger;
}
public void put(final JBIMessageTemplate jbiMessage) {
final String httpMethod = jbiMessage.getHttpMethod();
final String path = jbiMessage.getPath();
Map jbiMessagesForHttpMethod = this.jbiMessages.get(httpMethod);
if (jbiMessagesForHttpMethod == null) {
jbiMessagesForHttpMethod = new HashMap<>();
}
try {
final UriTemplate pathTemplate = new UriTemplate(
PropertiesHelper.resolveString(path, this.componentPlaceholders));
if (jbiMessagesForHttpMethod.containsKey(pathTemplate)) {
throw new IllegalArgumentException(
"A JBI operation is already present for the specified HTTP Method and path");
} else {
jbiMessagesForHttpMethod.put(pathTemplate, jbiMessage);
}
this.lock.writeLock().lock();
try {
this.jbiMessages.put(httpMethod, jbiMessagesForHttpMethod);
} finally {
this.lock.writeLock().unlock();
}
} catch (final PropertiesException e) {
throw new IllegalArgumentException("An error occurs resolving placeholders", e);
}
}
/**
* @param httpMethod
* The HTTP method used on incoming HTTP request
* @param path
* The path of the incoming HTTP request
* @return
*/
public JBIMessage get(final String httpMethod, final String path) {
this.lock.readLock().lock();
try {
final Map jbiMessagesForHttpMethod = this.jbiMessages.get(httpMethod);
if (jbiMessagesForHttpMethod != null) {
for (final Entry e : jbiMessagesForHttpMethod.entrySet()) {
final UriTemplate pathTemplate = e.getKey();
final Map templateVariables = new HashMap<>();
if (pathTemplate.match(path, templateVariables)) {
final JBIMessageTemplate template = e.getValue();
final JBIMessage jbiMessage = new JBIMessage(template);
for (Entry templateVariable : templateVariables.entrySet()) {
jbiMessage.addURIParameter(templateVariable.getKey(), templateVariable.getValue());
}
// we only are interested in the first path found!
return jbiMessage;
}
}
}
return null;
} finally {
this.lock.readLock().unlock();
}
}
/**
* Listener to apply changes when placeholders are reloaded
*/
public void onPlaceHolderValuesReloaded() {
this.lock.writeLock().lock();
try {
// For each HTTP method, we must update the map of message templates. These maps are replaced by new
// ones containing updated URI templates
for (final Entry> httpMethodEntry : this.jbiMessages
.entrySet()) {
final Map updatedJbiMessagesForHttpMethod = new HashMap<>();
for (final Entry currentJbiMessageEntry : httpMethodEntry
.getValue().entrySet()) {
final JBIMessageTemplate currentJbiMessage = currentJbiMessageEntry.getValue();
try {
final UriTemplate newPathTemplate = new UriTemplate(PropertiesHelper
.resolveString(currentJbiMessage.getPath(), this.componentPlaceholders));
updatedJbiMessagesForHttpMethod.put(newPathTemplate, currentJbiMessage);
} catch (final PropertiesException e) {
this.logger.log(Level.WARNING,
"A problem occurs resolving the path template '%s' against placeholders. Path template not updated. Try to reload placeholders again.",
e);
updatedJbiMessagesForHttpMethod.put(currentJbiMessageEntry.getKey(), currentJbiMessage);
}
}
this.jbiMessages.put(httpMethodEntry.getKey(), updatedJbiMessagesForHttpMethod);
}
} finally {
this.lock.writeLock().unlock();
}
}
}
private final JBIMessageTemplateMap jbiMessages;
private final String serviceBasePath;
private final Consumes consumes;
private final AbstractConfigurationParameters extensions;
public RESTConsumesConfiguration(final ServiceUnitDataHandler suDataHandler, final Consumes consumes,
final XPath xpathBuilder, final Properties componentPlaceholders, final Logger logger)
throws PEtALSCDKException {
this.extensions = suDataHandler.getConfigurationExtensions(consumes);
this.serviceBasePath = this.checkMandatoryParameter(SERVICE_BASE_PATH);
final LogErrorListener xslLogErrorListener = new LogErrorListener(logger, suDataHandler.getName());
this.jbiMessages = processSUConsumesMapping(consumes, xpathBuilder, suDataHandler.getInstallRoot(),
xslLogErrorListener, componentPlaceholders, logger);
this.consumes = consumes;
}
public String getServiceBasePath() {
return this.serviceBasePath;
}
public Consumes getConsumes() {
return this.consumes;
}
public JBIMessage getJBIMessage(final HttpServletRequest request) {
// get the JBI operation from the method and the path
final String httpMethod = request.getMethod();
final String path = request.getPathInfo();
final JBIMessage jbiMessage = this.jbiMessages.get(httpMethod, path);
// add the request parameters
if (jbiMessage != null) {
final Map requestParameters = request.getParameterMap();
for (final Entry parameter : requestParameters.entrySet()) {
jbiMessage.addQueryParameter(parameter.getKey(),
org.ow2.petals.binding.rest.StringHelper.listToString(parameter.getValue()));
}
}
return jbiMessage;
}
protected final String checkMandatoryParameter(final String parameter) throws PEtALSCDKException {
final String parameterValue = this.extensions.get(parameter);
if (StringHelper.isNullOrEmpty(parameterValue)) {
RESTConfiguration.handleMissingMandatoryParameterError(parameter);
}
return parameterValue;
}
protected final boolean checkLinkedParameters(final List parameters) throws PEtALSCDKException {
boolean allParameterDefined = true;
boolean noneParameterDefined = true;
final Iterator parametersIterator = parameters.iterator();
StringBuilder parameterNameStr = null;
while (parametersIterator.hasNext()) {
final String parameterName = parametersIterator.next();
final String parameterValue = this.extensions.get(parameterName);
if (StringHelper.isNullOrEmpty(parameterValue)) {
allParameterDefined = false;
} else {
noneParameterDefined = false;
}
if (parameterNameStr == null) {
parameterNameStr = new StringBuilder(parameterName);
} else if (parametersIterator.hasNext()) {
parameterNameStr.append(", '" + parameterName + "'");
} else {
parameterNameStr.append(" and '" + parameterName + "'");
}
}
if (!allParameterDefined && !noneParameterDefined) {
throw new PEtALSCDKException(
String.format("The parameters '%s' must be defined together (or not defined)", parameterNameStr));
}
return allParameterDefined;
}
private static final JBIMessageTemplateMap processSUConsumesMapping(final Consumes consumes,
final XPath xpathBuilder, final String suRootPath, final ErrorListener logErrorListener,
final Properties componentPlaceholders, final Logger logger) throws PEtALSCDKException {
final JBIMessageTemplateMap jbiMessages = new JBIMessageTemplateMap(componentPlaceholders, logger);
try {
final NodeList operationNodes = getSUOperationMappingNodes(consumes.getAny());
int operationNb = operationNodes.getLength();
for (int i = 0; i < operationNb; i++) {
final Node operationNode = operationNodes.item(i);
final Element operationElt = (Element) operationNode;
final JBIMessageTemplate jbiMessage = OperationBuilder.build(operationElt, xpathBuilder, suRootPath,
logErrorListener, componentPlaceholders, logger);
jbiMessage.log(logger);
jbiMessage.verify();
jbiMessages.put(jbiMessage);
}
} catch (final IllegalArgumentException e) {
throw new PEtALSCDKException(e);
}
return jbiMessages;
}
public static class JBIMessageTemplate {
private final QName jbiOperation;
private final String httpMethod;
private final String path;
private final String xmlTemplate;
private final XMLInputFactory requestConverterFactory;
private final IncomingPayloadGenerator incomingPayloadGenerator;
private final OnJBIResponse onJBIResponse;
public JBIMessageTemplate(final QName jbiOperation, final String httpMethod, final String path,
final Node xmlTemplate, final XMLInputFactory requestConverterFactory,
final IncomingPayloadGenerator incomingPayloadGenerator, final OnJBIResponse onJBIResponse)
throws TransformerException {
this.jbiOperation = jbiOperation;
this.httpMethod = httpMethod;
this.path = path;
this.xmlTemplate = XMLHelper.createStringFromDOMNode(xmlTemplate);
this.requestConverterFactory = requestConverterFactory;
this.incomingPayloadGenerator = incomingPayloadGenerator;
this.onJBIResponse = onJBIResponse;
}
public QName getJbiOperation() {
return this.jbiOperation;
}
public String getHttpMethod() {
return this.httpMethod;
}
public String getPath() {
return this.path;
}
public String getXmlTemplate() {
return this.xmlTemplate;
}
public XMLInputFactory getRequestConverterFactory() {
return this.requestConverterFactory;
}
public IncomingPayloadGenerator getIncomingPayloadGenerator() {
return this.incomingPayloadGenerator;
}
public OnJBIResponse getOnJBIResponse() {
return this.onJBIResponse;
}
public void log(final Logger log) {
log.config("Rest resource:");
log.config("\t- HTTP method: " + this.httpMethod);
log.config("\t- HTTP path: " + this.path);
if (this.incomingPayloadGenerator != null) {
log.config("\t- Incoming payload generator: ");
this.incomingPayloadGenerator.log("\t\t");
} else {
log.config("\t- No incoming payload generator");
}
log.config("\t- On JBI response: ");
this.onJBIResponse.log("\t\t");
}
/**
* Check the configuration
*
* @throws PEtALSCDKException
* The configuration contains an error
*/
public void verify() throws PEtALSCDKException {
if (this.incomingPayloadGenerator != null) {
this.incomingPayloadGenerator.verify();
}
this.onJBIResponse.verify();
}
}
/**
* Update configuration according to new values define for component place holders.
*/
public void onPlaceHolderValuesReloaded() {
this.jbiMessages.onPlaceHolderValuesReloaded();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy