001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.http.endpoints;
018
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.ObjectInputStream;
022 import java.io.ObjectOutputStream;
023 import java.io.OutputStream;
024 import java.io.StringWriter;
025 import java.io.Writer;
026
027 import javax.jbi.component.ComponentContext;
028 import javax.jbi.messaging.MessageExchange;
029 import javax.jbi.messaging.NormalizedMessage;
030 import javax.servlet.http.HttpServletRequest;
031 import javax.servlet.http.HttpServletResponse;
032 import javax.xml.transform.Source;
033 import javax.xml.transform.TransformerException;
034
035 import com.thoughtworks.xstream.XStream;
036 import com.thoughtworks.xstream.io.xml.DomDriver;
037
038 import org.apache.commons.logging.Log;
039 import org.apache.commons.logging.LogFactory;
040 import org.apache.servicemix.jbi.jaxp.SourceTransformer;
041 import org.apache.servicemix.jbi.jaxp.StringSource;
042
043 /**
044 * A marshaler that handles Java serialized content from the InputStream of the HttpServletRequest object and to the
045 * OutputStream of the HttpServletResponse object. This class is intended to handle requests initiated by the Spring <a
046 * href="http://www.springframework.org/docs/api/org/springframework/remoting/httpinvoker/package-summary.html">httpinvoker
047 * package</a> so the marshaled/unmarshaled XML invocation will be Spring <a
048 * href="http://www.springframework.org/docs/api/org/springframework/remoting/support/RemoteInvocation.html">RemoteInvocation</a>/
049 * <a href="http://www.springframework.org/docs/api/org/springframework/remoting/support/RemoteInvocationResult.html">
050 * RemoteInvocationResult</a> objects respectively.
051 *
052 * <p>
053 * This class makes no assumptions about how XML should be marshaled/unmarshaled. I.e., there is currently no way to
054 * customize the marshaled XML invocation. So this marshaler will need to pass the XML to a component that can transform
055 * it into some custom XML. The servicemix-saxon component can handle this very easily via XLST.
056 *
057 * @author bsnyder, aco
058 * @org.apache.xbean.XBean element="serializedMarshaler" description="a consumer-side marshaler for handling Java serialized content"
059 */
060 public class SerializedMarshaler extends DefaultHttpConsumerMarshaler {
061
062 private static Log log = LogFactory.getLog(SerializedMarshaler.class);
063
064 public MessageExchange createExchange(HttpServletRequest request, ComponentContext context) throws Exception {
065 MessageExchange me = context.getDeliveryChannel().createExchangeFactory().createExchange(getDefaultMep());
066 NormalizedMessage in = me.createMessage();
067 in.setContent(marshal(request.getInputStream()));
068 me.setMessage(in, "in");
069 return me;
070 }
071
072 public void sendOut(MessageExchange exchange, NormalizedMessage outMsg, HttpServletRequest request,
073 HttpServletResponse response) throws Exception {
074 if (outMsg.getContent() != null) {
075 unmarshal(response.getOutputStream(), outMsg.getContent());
076 }
077 }
078
079 /**
080 * Marshal the byte content of the input stream to an XML source. This method is marshaling the contents of the
081 * Spring <a
082 * href="http://www.springframework.org/docs/api/org/springframework/remoting/support/RemoteInvocation.html">RemoteInvocation</a>
083 * object. Below is an example of what this method emits:
084 *
085 * <pre>
086 * <?xml version="1.0" encoding="UTF-8"?><org.springframework.remoting.support.RemoteInvocation>
087 * <methodName>login</methodName>
088 * <parameterTypes>
089 * <java-class>java.lang.String</java-class>
090 * <java-class>java.lang.String</java-class>
091 * </parameterTypes>
092 * <arguments>
093 * <string>foo</string>
094 * <string>bar</string>
095 * </arguments>
096 * </org.springframework.remoting.support.RemoteInvocation>
097 * </pre>
098 *
099 * @param is -
100 * input stream to read the object from
101 * @return xml source
102 * @throws IOException
103 * @throws ClassNotFoundException
104 */
105 private Source marshal(InputStream is) throws IOException, ClassNotFoundException {
106 Object obj = new ObjectInputStream(is).readObject();
107 Writer w = new StringWriter();
108 XStream xstream = new XStream(new DomDriver());
109 xstream.toXML(obj, w);
110 String request = w.toString();
111
112 if (log.isDebugEnabled()) {
113 log.debug("Remote invocation request: " + request);
114 }
115
116 return new StringSource(request);
117 }
118
119 /**
120 * Unmarshal the XML content to the specified output stream. This method is unmarshaling XML into the Spring
121 * <a href="http://www.springframework.org/docs/api/org/springframework/remoting/support/RemoteInvocationResult.html">
122 * RemoteInvocationResult</a> object. Below is an example of the XML expected by this method:
123 *
124 * <pre>
125 * <?xml version="1.0" encoding="UTF-8"?>
126 * <org.springframework.remoting.support.RemoteInvocationResult>
127 * <value class="com.example.foo.bar.Baz">
128 * <firstName>myfirstname</firstName>
129 * <lastName>mylastname</lastName>
130 * <phone>12312312</phone>
131 * </value>
132 * </org.springframework.remoting.support.RemoteInvocationResult>
133 * </pre>
134 *
135 * @param os -
136 * output stream to unmarshal to
137 * @param content -
138 * XML source
139 * @throws TransformerException
140 * @throws IOException
141 */
142 private void unmarshal(OutputStream os, Source content) throws TransformerException, IOException {
143 SourceTransformer transform = new SourceTransformer();
144 XStream xstream = new XStream(new DomDriver());
145 String result = transform.toString(content);
146
147 if (log.isDebugEnabled()) {
148 log.debug("Remote invocation result: " + result);
149 }
150
151 Object obj = xstream.fromXML(result);
152 ObjectOutputStream oos = new ObjectOutputStream(os);
153 oos.writeObject(obj);
154 }
155 }