001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.jaxws.interceptors;
019:
020: import java.awt.Component;
021: import java.awt.Graphics;
022: import java.awt.Image;
023: import java.awt.MediaTracker;
024: import java.awt.image.BufferedImage;
025: import java.io.ByteArrayOutputStream;
026: import java.io.IOException;
027: import java.io.StringWriter;
028: import java.lang.reflect.Method;
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.UUID;
034: import java.util.logging.Logger;
035:
036: import javax.activation.DataHandler;
037: import javax.activation.DataSource;
038: import javax.activation.URLDataSource;
039: import javax.imageio.ImageIO;
040: import javax.imageio.ImageWriter;
041: import javax.mail.util.ByteArrayDataSource;
042: import javax.xml.bind.JAXBContext;
043: import javax.xml.stream.XMLStreamException;
044: import javax.xml.stream.XMLStreamReader;
045: import javax.xml.stream.XMLStreamWriter;
046: import javax.xml.transform.Source;
047: import javax.xml.transform.stream.StreamSource;
048:
049: import com.sun.xml.bind.v2.runtime.JAXBContextImpl;
050: import com.sun.xml.bind.v2.util.DataSourceSource;
051:
052: import org.apache.cxf.attachment.AttachmentImpl;
053: import org.apache.cxf.binding.soap.SoapMessage;
054: import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
055: import org.apache.cxf.binding.soap.model.SoapBodyInfo;
056: import org.apache.cxf.common.logging.LogUtils;
057: import org.apache.cxf.databinding.DataBinding;
058: import org.apache.cxf.helpers.CastUtils;
059: import org.apache.cxf.helpers.IOUtils;
060: import org.apache.cxf.interceptor.AttachmentOutInterceptor;
061: import org.apache.cxf.interceptor.Fault;
062: import org.apache.cxf.jaxb.JAXBDataBinding;
063: import org.apache.cxf.message.Attachment;
064: import org.apache.cxf.message.Exchange;
065: import org.apache.cxf.message.Message;
066: import org.apache.cxf.phase.Phase;
067: import org.apache.cxf.service.Service;
068: import org.apache.cxf.service.model.BindingMessageInfo;
069: import org.apache.cxf.service.model.BindingOperationInfo;
070: import org.apache.cxf.service.model.MessagePartInfo;
071: import org.apache.cxf.staxutils.StaxUtils;
072:
073: public class SwAOutInterceptor extends AbstractSoapInterceptor {
074: private static final Logger LOG = LogUtils
075: .getL7dLogger(SwAOutInterceptor.class);
076: private static final boolean HAS_SWA_REF_METHOD;
077: static {
078: Class<?> cls = JAXBContextImpl.class;
079: Method m = null;
080: try {
081: m = cls.getMethod("hasSwaRef", new Class[0]);
082: } catch (Exception e) {
083: //ignore
084: }
085: HAS_SWA_REF_METHOD = m != null;
086: }
087:
088: AttachmentOutInterceptor attachOut = new AttachmentOutInterceptor();
089:
090: public SwAOutInterceptor() {
091: super (Phase.PRE_LOGICAL);
092: addAfter(HolderOutInterceptor.class.getName());
093: addBefore(WrapperClassOutInterceptor.class.getName());
094: }
095:
096: public void handleMessage(SoapMessage message) throws Fault {
097: Exchange ex = message.getExchange();
098: BindingOperationInfo bop = ex.get(BindingOperationInfo.class);
099: if (bop == null) {
100: return;
101: }
102:
103: if (bop.isUnwrapped()) {
104: bop = bop.getWrappedOperation();
105: }
106:
107: boolean client = isRequestor(message);
108: BindingMessageInfo bmi = client ? bop.getInput() : bop
109: .getOutput();
110:
111: if (bmi == null) {
112: return;
113: }
114:
115: SoapBodyInfo sbi = bmi.getExtensor(SoapBodyInfo.class);
116:
117: if (sbi == null || sbi.getAttachments() == null
118: || sbi.getAttachments().size() == 0) {
119: Service s = ex.get(Service.class);
120: DataBinding db = s.getDataBinding();
121: if (db instanceof JAXBDataBinding
122: && hasSwaRef((JAXBDataBinding) db)) {
123: setupAttachmentOutput(message);
124: }
125: return;
126: }
127:
128: Collection<Attachment> atts = setupAttachmentOutput(message);
129:
130: List<Object> outObjects = CastUtils.cast(message
131: .getContent(List.class));
132:
133: for (MessagePartInfo mpi : sbi.getAttachments()) {
134: String partName = mpi.getConcreteName().getLocalPart();
135: String ct = (String) mpi.getProperty(Message.CONTENT_TYPE);
136:
137: String id = new StringBuilder().append(partName)
138: .append("=").append(UUID.randomUUID()).append(
139: "@apache.org").toString();
140:
141: // this assumes things are in order...
142: int idx = mpi.getIndex();
143: Object o = outObjects.get(idx);
144:
145: if (o == null) {
146: continue;
147: }
148: outObjects.set(idx, null);
149: DataHandler dh = null;
150:
151: // This code could probably be refactored out somewhere...
152: if (o instanceof Source) {
153:
154: dh = new DataHandler(createDataSource((Source) o, ct));
155:
156: } else if (o instanceof Image) {
157: // TODO: make this streamable. This is one of my pet
158: // peeves in JAXB RI as well, so if you fix this, submit the
159: // code to the JAXB RI as well (see RuntimeBuiltinLeafInfoImpl)! - DD
160: ByteArrayOutputStream bos = new ByteArrayOutputStream(
161: 2048);
162: Iterator<ImageWriter> writers = ImageIO
163: .getImageWritersByMIMEType(ct);
164: if (writers.hasNext()) {
165: ImageWriter writer = writers.next();
166:
167: try {
168: BufferedImage bimg = convertToBufferedImage((Image) o);
169: writer.setOutput(ImageIO
170: .createImageOutputStream(bos));
171: writer.write(bimg);
172: writer.dispose();
173: bos.close();
174: } catch (IOException e) {
175: throw new Fault(e);
176: }
177: } else {
178: throw new Fault(
179: new org.apache.cxf.common.i18n.Message(
180: "ATTACHMENT_NOT_SUPPORTED", LOG, ct));
181: }
182:
183: dh = new DataHandler(new ByteArrayDataSource(bos
184: .toByteArray(), ct));
185: } else if (o instanceof DataHandler) {
186: dh = (DataHandler) o;
187: ct = dh.getContentType();
188:
189: try {
190: if ("text/xml".equals(ct)
191: && dh.getContent() instanceof Source) {
192: dh = new DataHandler(createDataSource(
193: (Source) dh.getContent(), ct));
194: }
195: } catch (IOException e) {
196: //ignore, use same dh
197: }
198: } else if (dh == null) {
199: throw new Fault(new org.apache.cxf.common.i18n.Message(
200: "ATTACHMENT_NOT_SUPPORTED", LOG, o.getClass()));
201: } else if (dh.getDataSource() instanceof URLDataSource) {
202: URLDataSource ds = (URLDataSource) dh.getDataSource();
203: dh = new DataHandler(ds.getURL());
204: ct = ds.getContentType();
205: }
206:
207: AttachmentImpl att = new AttachmentImpl(id);
208: att.setDataHandler(dh);
209: att.setHeader("Content-Type", ct);
210: atts.add(att);
211: }
212: }
213:
214: private boolean hasSwaRef(JAXBDataBinding db) {
215: JAXBContext context = db.getContext();
216: if (HAS_SWA_REF_METHOD && context instanceof JAXBContextImpl) {
217: return ((JAXBContextImpl) context).hasSwaRef();
218: }
219:
220: return false;
221: }
222:
223: private DataSource createDataSource(Source o, String ct) {
224: DataSource ds = null;
225:
226: if (o instanceof DataSourceSource) {
227: ds = (DataSource) o;
228: } else if (o instanceof StreamSource) {
229: StreamSource src = (StreamSource) o;
230: try {
231: if (src.getInputStream() != null) {
232: ByteArrayOutputStream bos = new ByteArrayOutputStream(
233: 2048);
234: IOUtils.copy(src.getInputStream(), bos, 1024);
235: ds = new ByteArrayDataSource(bos.toByteArray(), ct);
236: } else {
237: ds = new ByteArrayDataSource(IOUtils.toString(src
238: .getReader()), ct);
239: }
240: } catch (IOException e) {
241: throw new Fault(e);
242: }
243: } else {
244: XMLStreamReader reader = StaxUtils
245: .createXMLStreamReader((Source) o);
246: StringWriter stringWriter = new StringWriter();
247: XMLStreamWriter writer = StaxUtils
248: .createXMLStreamWriter(stringWriter);
249: try {
250: StaxUtils.copy(reader, writer);
251: writer.flush();
252: ds = new ByteArrayDataSource(stringWriter.toString(),
253: ct);
254: } catch (XMLStreamException e1) {
255: throw new Fault(e1);
256: } catch (IOException e) {
257: throw new Fault(e);
258: }
259: }
260: return ds;
261: }
262:
263: private BufferedImage convertToBufferedImage(Image image)
264: throws IOException {
265: if (image instanceof BufferedImage) {
266: return (BufferedImage) image;
267: }
268:
269: // Wait until the image is completely loaded
270: MediaTracker tracker = new MediaTracker(new Component() {
271: });
272: tracker.addImage(image, 0);
273: try {
274: tracker.waitForAll();
275: } catch (InterruptedException e) {
276: throw new Fault(e);
277: }
278:
279: // Create a BufferedImage so we can write it out later
280: BufferedImage bufImage = new BufferedImage(
281: image.getWidth(null), image.getHeight(null),
282: BufferedImage.TYPE_INT_ARGB);
283:
284: Graphics g = bufImage.createGraphics();
285: g.drawImage(image, 0, 0, null);
286: return bufImage;
287: }
288:
289: private Collection<Attachment> setupAttachmentOutput(
290: SoapMessage message) {
291: // We have attachments, so add the interceptor
292: message.getInterceptorChain().add(attachOut);
293: // We should probably come up with another property for this
294: message.put(AttachmentOutInterceptor.WRITE_ATTACHMENTS,
295: Boolean.TRUE);
296:
297: Collection<Attachment> atts = message.getAttachments();
298: if (atts == null) {
299: atts = new ArrayList<Attachment>();
300: message.setAttachments(atts);
301: }
302: return atts;
303: }
304: }
|