Wed, 27 Apr 2016 01:27:09 +0800
Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/jaxws/
changeset: 657:d47a47f961ee
tag: jdk8u25-b17
1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.xml.internal.ws.encoding;
28 import com.sun.xml.internal.ws.api.SOAPVersion;
29 import com.sun.xml.internal.ws.api.WSFeatureList;
30 import com.sun.xml.internal.ws.api.message.Packet;
31 import com.sun.xml.internal.ws.api.pipe.Codec;
32 import com.sun.xml.internal.ws.api.pipe.ContentType;
33 import com.sun.xml.internal.ws.client.ContentNegotiation;
34 import com.sun.xml.internal.ws.encoding.xml.XMLCodec;
35 import com.sun.xml.internal.ws.encoding.xml.XMLMessage;
36 import com.sun.xml.internal.ws.encoding.xml.XMLMessage.MessageDataSource;
37 import com.sun.xml.internal.ws.encoding.xml.XMLMessage.UnknownContent;
38 import com.sun.xml.internal.ws.encoding.xml.XMLMessage.XMLMultiPart;
39 import com.sun.xml.internal.ws.resources.StreamingMessages;
40 import com.sun.xml.internal.ws.util.ByteArrayBuffer;
42 import javax.activation.DataSource;
43 import javax.xml.ws.WebServiceException;
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.io.OutputStream;
48 import java.lang.reflect.Method;
49 import java.nio.channels.WritableByteChannel;
50 import java.util.StringTokenizer;
52 /**
53 * XML (infoset) over HTTP binding {@link Codec}.
54 * <p>
55 * TODO: Support FI for multipart/related
56 * Support FI for MessageDataSource
57 *
58 * @author Jitendra Kotamraju
59 */
60 public final class XMLHTTPBindingCodec extends MimeCodec {
61 /**
62 * Base HTTP Accept request-header.
63 */
64 private static final String BASE_ACCEPT_VALUE =
65 "*";
67 /**
68 * Fast Infoset MIME type.
69 */
70 private static final String APPLICATION_FAST_INFOSET_MIME_TYPE =
71 "application/fastinfoset";
73 /**
74 * True if the Fast Infoset codec should be used
75 */
76 private boolean useFastInfosetForEncoding;
78 /**
79 * The XML codec
80 */
81 private final Codec xmlCodec;
83 /**
84 * The FI codec
85 */
86 private final Codec fiCodec;
88 /**
89 * The Accept header for XML encodings
90 */
91 private static final String xmlAccept = null;
93 /**
94 * The Accept header for Fast Infoset and XML encodings
95 */
96 private static final String fiXmlAccept = APPLICATION_FAST_INFOSET_MIME_TYPE + ", " + BASE_ACCEPT_VALUE;
98 private ContentTypeImpl setAcceptHeader(Packet p, ContentType c) {
99 ContentTypeImpl ctImpl = (ContentTypeImpl)c;
100 if (p.contentNegotiation == ContentNegotiation.optimistic
101 || p.contentNegotiation == ContentNegotiation.pessimistic) {
102 ctImpl.setAcceptHeader(fiXmlAccept);
103 } else {
104 ctImpl.setAcceptHeader(xmlAccept);
105 }
106 p.setContentType(ctImpl);
107 return ctImpl;
108 }
110 public XMLHTTPBindingCodec(WSFeatureList f) {
111 super(SOAPVersion.SOAP_11, f);
113 xmlCodec = new XMLCodec(f);
115 fiCodec = getFICodec();
116 }
118 @Override
119 public String getMimeType() {
120 return null;
121 }
123 @Override
124 public ContentType getStaticContentType(Packet packet) {
125 ContentType ct;
126 if (packet.getInternalMessage() instanceof MessageDataSource) {
127 final MessageDataSource mds = (MessageDataSource)packet.getInternalMessage();
128 if (mds.hasUnconsumedDataSource()) {
129 ct = getStaticContentType(mds);
130 return (ct != null)
131 ? setAcceptHeader(packet, ct) //_adaptingContentType.set(packet, ct)
132 : null;
133 }
134 }
136 ct = super.getStaticContentType(packet);
137 return (ct != null)
138 ? setAcceptHeader(packet, ct) //_adaptingContentType.set(packet, ct)
139 : null;
140 }
142 @Override
143 public ContentType encode(Packet packet, OutputStream out) throws IOException {
144 if (packet.getInternalMessage() instanceof MessageDataSource) {
145 final MessageDataSource mds = (MessageDataSource)packet.getInternalMessage();
146 if (mds.hasUnconsumedDataSource())
147 return setAcceptHeader(packet, encode(mds, out));
148 }
150 return setAcceptHeader(packet, super.encode(packet, out));
151 }
153 @Override
154 public ContentType encode(Packet packet, WritableByteChannel buffer) {
155 throw new UnsupportedOperationException();
156 }
158 @Override
159 public void decode(InputStream in, String contentType, Packet packet) throws IOException {
160 /**
161 * Reset the encoding state when on the server side for each
162 * decode/encode step.
163 */
164 if (packet.contentNegotiation == null)
165 useFastInfosetForEncoding = false;
167 if (contentType == null) {
168 xmlCodec.decode(in, contentType, packet);
169 } else if (isMultipartRelated(contentType)) {
170 packet.setMessage(new XMLMultiPart(contentType, in, features));
171 } else if(isFastInfoset(contentType)) {
172 if (fiCodec == null) {
173 throw new RuntimeException(StreamingMessages.FASTINFOSET_NO_IMPLEMENTATION());
174 }
176 useFastInfosetForEncoding = true;
177 fiCodec.decode(in, contentType, packet);
178 } else if (isXml(contentType)) {
179 xmlCodec.decode(in, contentType, packet);
180 } else {
181 packet.setMessage(new UnknownContent(contentType, in));
182 }
184 if (!useFastInfosetForEncoding) {
185 useFastInfosetForEncoding = isFastInfosetAcceptable(packet.acceptableMimeTypes);
186 }
187 }
189 @Override
190 protected void decode(MimeMultipartParser mpp, Packet packet) throws IOException {
191 // This method will never be invoked
192 }
194 @Override
195 public MimeCodec copy() {
196 return new XMLHTTPBindingCodec(features);
197 }
199 private boolean isMultipartRelated(String contentType) {
200 return compareStrings(contentType, MimeCodec.MULTIPART_RELATED_MIME_TYPE);
201 }
203 private boolean isXml(String contentType) {
204 return compareStrings(contentType, XMLCodec.XML_APPLICATION_MIME_TYPE)
205 || compareStrings(contentType, XMLCodec.XML_TEXT_MIME_TYPE)
206 || (compareStrings(contentType, "application/")&&(contentType.toLowerCase().indexOf("+xml") != -1));
207 }
209 private boolean isFastInfoset(String contentType) {
210 return compareStrings(contentType, APPLICATION_FAST_INFOSET_MIME_TYPE);
211 }
213 private boolean compareStrings(String a, String b) {
214 return a.length() >= b.length() &&
215 b.equalsIgnoreCase(
216 a.substring(0,
217 b.length()));
218 }
220 private boolean isFastInfosetAcceptable(String accept) {
221 if (accept == null) return false;
223 StringTokenizer st = new StringTokenizer(accept, ",");
224 while (st.hasMoreTokens()) {
225 final String token = st.nextToken().trim();
226 if (token.equalsIgnoreCase(APPLICATION_FAST_INFOSET_MIME_TYPE)) {
227 return true;
228 }
229 }
230 return false;
231 }
233 private ContentType getStaticContentType(MessageDataSource mds) {
234 final String contentType = mds.getDataSource().getContentType();
235 final boolean isFastInfoset = XMLMessage.isFastInfoset(contentType);
237 if (!requiresTransformationOfDataSource(isFastInfoset,
238 useFastInfosetForEncoding)) {
239 return new ContentTypeImpl(contentType);
240 } else {
241 return null;
242 }
243 }
245 private ContentType encode(MessageDataSource mds, OutputStream out) {
246 try {
247 final boolean isFastInfoset = XMLMessage.isFastInfoset(
248 mds.getDataSource().getContentType());
249 DataSource ds = transformDataSource(mds.getDataSource(),
250 isFastInfoset, useFastInfosetForEncoding, features);
252 InputStream is = ds.getInputStream();
253 byte[] buf = new byte[1024];
254 int count;
255 while((count=is.read(buf)) != -1) {
256 out.write(buf, 0, count);
257 }
258 return new ContentTypeImpl(ds.getContentType());
259 } catch(IOException ioe) {
260 throw new WebServiceException(ioe);
261 }
262 }
264 @Override
265 protected Codec getMimeRootCodec(Packet p) {
266 /**
267 * The following logic is only for outbound packets
268 * to be encoded by client.
269 * On the server the p.contentNegotiation == null.
270 */
271 if (p.contentNegotiation == ContentNegotiation.none) {
272 // The client may have changed the negotiation property from
273 // pessismistic to none between invocations
274 useFastInfosetForEncoding = false;
275 } else if (p.contentNegotiation == ContentNegotiation.optimistic) {
276 // Always encode using Fast Infoset if in optimisitic mode
277 useFastInfosetForEncoding = true;
278 }
280 return (useFastInfosetForEncoding && fiCodec != null)? fiCodec : xmlCodec;
281 }
283 public static boolean requiresTransformationOfDataSource(
284 boolean isFastInfoset, boolean useFastInfoset) {
285 return (isFastInfoset && !useFastInfoset) || (!isFastInfoset && useFastInfoset);
286 }
288 public static DataSource transformDataSource(DataSource in,
289 boolean isFastInfoset, boolean useFastInfoset, WSFeatureList f) {
290 try {
291 if (isFastInfoset && !useFastInfoset) {
292 // Convert from Fast Infoset to XML
293 Codec codec = new XMLHTTPBindingCodec(f);
294 Packet p = new Packet();
295 codec.decode(in.getInputStream(), in.getContentType(), p);
297 p.getMessage().getAttachments();
298 codec.getStaticContentType(p);
300 ByteArrayBuffer bos = new ByteArrayBuffer();
301 ContentType ct = codec.encode(p, bos);
302 return XMLMessage.createDataSource(ct.getContentType(), bos.newInputStream());
303 } else if (!isFastInfoset && useFastInfoset) {
304 // Convert from XML to Fast Infoset
305 Codec codec = new XMLHTTPBindingCodec(f);
306 Packet p = new Packet();
307 codec.decode(in.getInputStream(), in.getContentType(), p);
309 p.contentNegotiation = ContentNegotiation.optimistic;
310 p.getMessage().getAttachments();
311 codec.getStaticContentType(p);
313 ByteArrayBuffer bos = new ByteArrayBuffer();
314 com.sun.xml.internal.ws.api.pipe.ContentType ct = codec.encode(p, bos);
315 return XMLMessage.createDataSource(ct.getContentType(), bos.newInputStream());
316 }
317 } catch(Exception ex) {
318 throw new WebServiceException(ex);
319 }
321 return in;
322 }
324 /**
325 * Obtain an FI SOAP codec instance using reflection.
326 */
327 private static Codec getFICodec() {
328 try {
329 Class c = Class.forName("com.sun.xml.internal.ws.encoding.fastinfoset.FastInfosetCodec");
330 Method m = c.getMethod("create");
331 return (Codec)m.invoke(null);
332 } catch (Exception e) {
333 return null;
334 }
335 }
336 }