/*
* Copyright 2002-2017 the original author or authors.
*
* 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.springframework.integration.xml.transformer;
import java.io.File;
import java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.springframework.integration.transformer.AbstractPayloadTransformer;
import org.springframework.integration.transformer.Transformer;
import org.springframework.integration.xml.source.DomSourceFactory;
import org.springframework.integration.xml.source.SourceFactory;
import org.springframework.messaging.MessagingException;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.xml.transform.StringSource;
/**
* An implementation of {@link Transformer} that delegates to an OXM
* {@link Unmarshaller}. Expects the payload to be of type {@link Document},
* {@link String}, {@link File}, {@link Source} or to have an instance of
* {@link SourceFactory} that can convert to a {@link Source}. If
* {@link #alwaysUseSourceFactory} is set to true, then the {@link SourceFactory}
* will be used to create the {@link Source} regardless of payload type.
* <p>
* The {@link #alwaysUseSourceFactory} is ignored if payload is
* {@link org.springframework.ws.mime.MimeMessage}.
* <p>
* The Unmarshaller may return a Message, but if the return value is not
* already a Message instance, a new Message will be created with that
* return value as its payload.
*
* @author Jonas Partner
* @author Artem Bilan
*/
public class UnmarshallingTransformer extends AbstractPayloadTransformer<Object, Object> {
private final Unmarshaller unmarshaller;
private volatile SourceFactory sourceFactory = new DomSourceFactory();
private volatile boolean alwaysUseSourceFactory = false;
private MimeMessageUnmarshallerHelper mimeMessageUnmarshallerHelper;
public UnmarshallingTransformer(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
if (ClassUtils.isPresent("org.springframework.ws.mime.MimeMessage", ClassUtils.getDefaultClassLoader())) {
this.mimeMessageUnmarshallerHelper = new MimeMessageUnmarshallerHelper(unmarshaller);
}
}
/**
* Provide the SourceFactory to be used. Must not be null.
* @param sourceFactory The source factory.
*/
public void setSourceFactory(SourceFactory sourceFactory) {
Assert.notNull(sourceFactory, "sourceFactory must not be null");
this.sourceFactory = sourceFactory;
}
/**
* If true always delegate to the {@link SourceFactory}.
* @param alwaysUseSourceFactory true to always use the source factory.
*/
public void setAlwaysUseSourceFactory(boolean alwaysUseSourceFactory) {
this.alwaysUseSourceFactory = alwaysUseSourceFactory;
}
@Override
public String getComponentType() {
return "xml:unmarshalling-transformer";
}
@Override
public Object transformPayload(Object payload) {
Source source = null;
try {
if (this.mimeMessageUnmarshallerHelper != null) {
Object result = this.mimeMessageUnmarshallerHelper.maybeUnmarshalMimeMessage(payload);
if (result != null) {
return result;
}
}
if (this.alwaysUseSourceFactory) {
source = this.sourceFactory.createSource(payload);
}
else if (payload instanceof String) {
source = new StringSource((String) payload);
}
else if (payload instanceof File) {
source = new StreamSource((File) payload);
}
else if (payload instanceof Document) {
source = new DOMSource((Document) payload);
}
else if (payload instanceof Source) {
source = (Source) payload;
}
else {
source = this.sourceFactory.createSource(payload);
}
if (source == null) {
throw new MessagingException(
"failed to transform message, payload not assignable from " + Source.class.getName()
+ "and no conversion possible");
}
return this.unmarshaller.unmarshal(source);
}
catch (IOException e) {
throw new MessagingException("failed to unmarshal payload", e);
}
}
private static class MimeMessageUnmarshallerHelper {
private Unmarshaller delegate;
MimeMessageUnmarshallerHelper(Unmarshaller unmarshaller) {
this.delegate = unmarshaller;
}
public Object maybeUnmarshalMimeMessage(Object payload) throws IOException {
if (payload instanceof org.springframework.ws.mime.MimeMessage) {
return org.springframework.ws.support.MarshallingUtils.unmarshal(this.delegate,
(org.springframework.ws.mime.MimeMessage) payload);
}
else {
return null;
}
}
}
}