/**
* Copyright 2015 Nortal 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 com.nortal.jroad.client.service.consumer;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import javax.activation.DataHandler;
import org.apache.commons.lang.exception.NestableRuntimeException;
import org.apache.xmlbeans.XmlObject;
import org.springframework.stereotype.Service;
import org.springframework.ws.client.WebServiceIOException;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceMessageExtractor;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.client.SoapFaultClientException;
import com.nortal.jroad.client.exception.NonTechnicalFaultException;
import com.nortal.jroad.client.exception.XRoadServiceConsumptionException;
import com.nortal.jroad.client.service.callback.CustomCallback;
import com.nortal.jroad.client.service.callback.StandardXRoadConsumerCallback;
import com.nortal.jroad.client.service.callback.XRoadMessageCallback;
import com.nortal.jroad.client.service.configuration.XRoadServiceConfiguration;
import com.nortal.jroad.client.service.extractor.CustomExtractor;
import com.nortal.jroad.client.service.extractor.StandardXRoadConsumerMessageExtractor;
import com.nortal.jroad.client.util.WSConsumptionLoggingInterceptor;
import com.nortal.jroad.client.util.XmlBeansUtil;
import com.nortal.jroad.model.XRoadAttachment;
import com.nortal.jroad.model.XRoadMessage;
import com.nortal.jroad.model.XmlBeansXRoadMetadata;
import com.nortal.jroad.util.AttachmentUtil;
/**
* Standard {@link XRoadConsumer} implementation.
*
* @author Dmitri Danilkin
* @author Roman Tekhov
* @author Rando Mihkelsaar
* @author Lauri Lättemäe (lauri.lattemae@nortal.com) - protocol 4.0
*/
@Service("xRoadConsumer")
public class StandardXRoadConsumer extends WebServiceGatewaySupport implements XRoadConsumer {
private Map<String, XmlBeansXRoadMetadata> metadata;
public static final String ROOT_NS = "ns5";
@Override
protected void initGateway() throws Exception {
metadata = XmlBeansUtil.loadMetadata();
Collection<ClientInterceptor> interceptors = createInterceptors();
if (interceptors != null && !interceptors.isEmpty()) {
setInterceptors(interceptors.toArray(new ClientInterceptor[0]));
}
getWebServiceTemplate().setCheckConnectionForFault(false);
}
protected Collection<ClientInterceptor> createInterceptors() {
return Arrays.asList(new ClientInterceptor[] { new WSConsumptionLoggingInterceptor() });
}
@Override
public <I, O> XRoadMessage<O> sendRequest(XRoadMessage<I> input, XRoadServiceConfiguration xroadServiceConfiguration)
throws XRoadServiceConsumptionException {
return sendRealRequest(input, xroadServiceConfiguration, null, null);
}
@Override
public <I, O> XRoadMessage<O> sendRequest(XRoadMessage<I> input,
XRoadServiceConfiguration xroadServiceConfiguration,
CustomCallback callback,
CustomExtractor extractor)
throws XRoadServiceConsumptionException {
return sendRealRequest(input, xroadServiceConfiguration, callback, extractor);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private <I, O> XRoadMessage<O> sendRealRequest(XRoadMessage<I> input,
XRoadServiceConfiguration xroadServiceConfiguration,
CustomCallback callback,
CustomExtractor extractor)
throws XRoadServiceConsumptionException {
try {
// Add any swaref attachments...
// First find all Objects.
for (XmlObject attachmentObj : XmlBeansUtil.getAllObjects((XmlObject) input.getContent())) {
// Introspect all methods, and find the ones that were generated during instrumentation
for (Method method : XmlBeansUtil.getSwaRefGetters(attachmentObj)) {
// Get the datahandler for the attachment
DataHandler handler = (DataHandler) method.invoke(attachmentObj);
if (handler != null) {
String field = XmlBeansUtil.getFieldName(method);
// Check whether the user has set a custom CID, if not, generate a random one and set it
String cid = XmlBeansUtil.getCid(attachmentObj, field);
if (cid == null) {
cid = AttachmentUtil.getUniqueCid();
} else {
cid = cid.startsWith("cid:") ? cid.substring(4) : cid;
}
XmlBeansUtil.setCid(attachmentObj, field, "cid:" + cid);
// Add a new attachment to the list
input.getAttachments().add(new XRoadAttachment(cid, handler));
}
}
}
XmlBeansXRoadMetadata curdata = metadata.get(xroadServiceConfiguration.getWsdlDatabase().toLowerCase()
+ xroadServiceConfiguration.getMethod().toLowerCase());
if (curdata == null) {
throw new IllegalStateException(String.format("Could not find metadata for %s.%s! Most likely the method name has been specified incorrectly.",
xroadServiceConfiguration.getWsdlDatabase().toLowerCase(),
xroadServiceConfiguration.getMethod().toLowerCase()));
}
WebServiceMessageCallback originalCallback = getNewConsumerCallback(input, xroadServiceConfiguration, curdata);
WebServiceMessageExtractor originalExtractor = new StandardXRoadConsumerMessageExtractor(curdata);
if (callback != null) {
callback.setOriginalCallback(originalCallback);
}
WebServiceMessageCallback finalCallback = callback == null ? originalCallback : callback;
if (extractor != null) {
extractor.setOriginalExtractor(originalExtractor);
}
WebServiceMessageExtractor finalExtractor = extractor == null ? originalExtractor : extractor;
return (XRoadMessage<O>) getWebServiceTemplate().sendAndReceive(xroadServiceConfiguration.getSecurityServer(),
finalCallback,
finalExtractor);
} catch (Exception e) {
e.printStackTrace();
XRoadServiceConsumptionException consumptionException = resolveException(e, xroadServiceConfiguration);
if (consumptionException != null) {
throw consumptionException;
}
throw new NestableRuntimeException(e);
}
}
protected <I> StandardXRoadConsumerCallback getNewConsumerCallback(XRoadMessage<I> input,
XRoadServiceConfiguration xteeServiceConfiguration,
XmlBeansXRoadMetadata curdata) {
return new StandardXRoadConsumerCallback(input.getContent(),
getNewMessageCallback(input, xteeServiceConfiguration),
curdata);
}
protected <I> XRoadMessageCallback getNewMessageCallback(XRoadMessage<I> input,
XRoadServiceConfiguration xroadServiceConfiguration) {
return new XRoadMessageCallback(xroadServiceConfiguration, input.getAttachments());
}
private XRoadServiceConsumptionException resolveException(Exception e,
XRoadServiceConfiguration xroadServiceConfiguration) {
WebServiceIOException ioException = null;
SoapFaultClientException faultException = null;
if (e instanceof WebServiceIOException) {
ioException = (WebServiceIOException) e;
} else if (e instanceof SoapFaultClientException) {
faultException = (SoapFaultClientException) e;
}
if (ioException != null || faultException != null) {
String database = xroadServiceConfiguration.getDatabase();
String method = xroadServiceConfiguration.getMethod();
String version = xroadServiceConfiguration.getVersion();
if (ioException != null) {
if (ioException.getCause() instanceof NonTechnicalFaultException) {
return new XRoadServiceConsumptionException((NonTechnicalFaultException) ioException.getCause(),
database,
method,
version);
}
return new XRoadServiceConsumptionException(ioException, database, method, version);
}
if (faultException != null) {
return new XRoadServiceConsumptionException(faultException, database, method, version);
}
}
return null;
}
}