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"
059: */
060: public class SerializedMarshaler extends DefaultHttpConsumerMarshaler {
061:
062: private static Log log = LogFactory
063: .getLog(SerializedMarshaler.class);
064:
065: public MessageExchange createExchange(HttpServletRequest request,
066: ComponentContext context) throws Exception {
067: MessageExchange me = context.getDeliveryChannel()
068: .createExchangeFactory()
069: .createExchange(getDefaultMep());
070: NormalizedMessage in = me.createMessage();
071: in.setContent(marshal(request.getInputStream()));
072: me.setMessage(in, "in");
073: return me;
074: }
075:
076: public void sendOut(MessageExchange exchange,
077: NormalizedMessage outMsg, HttpServletRequest request,
078: HttpServletResponse response) throws Exception {
079: if (outMsg.getContent() != null) {
080: unmarshal(response.getOutputStream(), outMsg.getContent());
081: }
082: }
083:
084: /**
085: * Marshal the byte content of the input stream to an XML source. This method is marshaling the contents of the
086: * Spring <a
087: * href="http://www.springframework.org/docs/api/org/springframework/remoting/support/RemoteInvocation.html">RemoteInvocation</a>
088: * object. Below is an example of what this method emits:
089: *
090: * <pre>
091: * <?xml version="1.0" encoding="UTF-8"?><org.springframework.remoting.support.RemoteInvocation>
092: * <methodName>login</methodName>
093: * <parameterTypes>
094: * <java-class>java.lang.String</java-class>
095: * <java-class>java.lang.String</java-class>
096: * </parameterTypes>
097: * <arguments>
098: * <string>foo</string>
099: * <string>bar</string>
100: * </arguments>
101: * </org.springframework.remoting.support.RemoteInvocation>
102: * </pre>
103: *
104: * @param is -
105: * input stream to read the object from
106: * @return xml source
107: * @throws IOException
108: * @throws ClassNotFoundException
109: */
110: private Source marshal(InputStream is) throws IOException,
111: ClassNotFoundException {
112: Object obj = new ObjectInputStream(is).readObject();
113: Writer w = new StringWriter();
114: XStream xstream = new XStream(new DomDriver());
115: xstream.toXML(obj, w);
116: String request = w.toString();
117:
118: if (log.isDebugEnabled()) {
119: log.debug("Remote invocation request: " + request);
120: }
121:
122: return new StringSource(request);
123: }
124:
125: /**
126: * Unmarshal the XML content to the specified output stream. This method is unmarshaling XML into the Spring
127: * <a href="http://www.springframework.org/docs/api/org/springframework/remoting/support/RemoteInvocationResult.html">
128: * RemoteInvocationResult</a> object. Below is an example of the XML expected by this method:
129: *
130: * <pre>
131: * <?xml version="1.0" encoding="UTF-8"?>
132: * <org.springframework.remoting.support.RemoteInvocationResult>
133: * <value class="com.example.foo.bar.Baz">
134: * <firstName>myfirstname</firstName>
135: * <lastName>mylastname</lastName>
136: * <phone>12312312</phone>
137: * </value>
138: * </org.springframework.remoting.support.RemoteInvocationResult>
139: * </pre>
140: *
141: * @param os -
142: * output stream to unmarshal to
143: * @param content -
144: * XML source
145: * @throws TransformerException
146: * @throws IOException
147: */
148: private void unmarshal(OutputStream os, Source content)
149: throws TransformerException, IOException {
150: SourceTransformer transform = new SourceTransformer();
151: XStream xstream = new XStream(new DomDriver());
152: String result = transform.toString(content);
153:
154: if (log.isDebugEnabled()) {
155: log.debug("Remote invocation result: " + result);
156: }
157:
158: Object obj = xstream.fromXML(result);
159: ObjectOutputStream oos = new ObjectOutputStream(os);
160: oos.writeObject(obj);
161: }
162: }
|