001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://jwsdp.dev.java.net/CDDLv1.0.html
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * HEADER in each file and include the License file at
014: * https://jwsdp.dev.java.net/CDDLv1.0.html If applicable,
015: * add the following below this CDDL HEADER, with the
016: * fields enclosed by brackets "[]" replaced with your
017: * own identifying information: Portions Copyright [yyyy]
018: * [name of copyright owner]
019: */
020: /*
021: * $Id: AttachmentPartImpl.java,v 1.2 2007/07/16 16:41:21 ofung Exp $
022: * $Revision: 1.2 $
023: * $Date: 2007/07/16 16:41:21 $
024: */
025:
026: /*
027: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
028: *
029: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
030: *
031: * The contents of this file are subject to the terms of either the GNU
032: * General Public License Version 2 only ("GPL") or the Common Development
033: * and Distribution License("CDDL") (collectively, the "License"). You
034: * may not use this file except in compliance with the License. You can obtain
035: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
036: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
037: * language governing permissions and limitations under the License.
038: *
039: * When distributing the software, include this License Header Notice in each
040: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
041: * Sun designates this particular file as subject to the "Classpath" exception
042: * as provided by Sun in the GPL Version 2 section of the License file that
043: * accompanied this code. If applicable, add the following below the License
044: * Header, with the fields enclosed by brackets [] replaced by your own
045: * identifying information: "Portions Copyrighted [year]
046: * [name of copyright owner]"
047: *
048: * Contributor(s):
049: *
050: * If you wish your version of this file to be governed by only the CDDL or
051: * only the GPL Version 2, indicate your decision by adding "[Contributor]
052: * elects to include this software in this distribution under the [CDDL or GPL
053: * Version 2] license." If you don't indicate a single choice of license, a
054: * recipient has the option to distribute your version of this file under
055: * either the CDDL, the GPL Version 2 or to extend the choice of license to
056: * its licensees as provided above. However, if you add GPL Version 2 code
057: * and therefore, elected the GPL Version 2 license, then the option applies
058: * only if the new code is made subject to such option by the copyright
059: * holder.
060: */
061: package com.sun.xml.messaging.saaj.soap;
062:
063: import com.sun.xml.messaging.saaj.SOAPExceptionImpl;
064:
065: import com.sun.xml.messaging.saaj.packaging.mime.util.ASCIIUtility;
066:
067: import com.sun.xml.messaging.saaj.packaging.mime.Header;
068: import com.sun.xml.messaging.saaj.packaging.mime.internet.MimePartDataSource;
069: import com.sun.xml.messaging.saaj.packaging.mime.internet.InternetHeaders;
070: import com.sun.xml.messaging.saaj.packaging.mime.internet.MimeBodyPart;
071: import com.sun.xml.messaging.saaj.packaging.mime.internet.MimeUtility;
072: import com.sun.xml.messaging.saaj.util.ByteOutputStream;
073: import com.sun.xml.messaging.saaj.util.LogDomainConstants;
074:
075: import javax.activation.CommandMap;
076: import javax.activation.DataHandler;
077: import javax.activation.MailcapCommandMap;
078: import javax.xml.soap.AttachmentPart;
079: import javax.xml.soap.MimeHeader;
080: import javax.xml.soap.MimeHeaders;
081: import javax.xml.soap.SOAPException;
082: import java.io.IOException;
083: import java.io.InputStream;
084: import java.io.ByteArrayOutputStream;
085: import java.io.ByteArrayInputStream;
086: import java.io.OutputStream;
087: import java.util.Iterator;
088: import java.util.List;
089: import java.util.logging.Level;
090: import java.util.logging.Logger;
091:
092: import javax.activation.*;
093: import javax.xml.soap.*;
094:
095: /**
096: * Implementation of attachments.
097: *
098: * @author Anil Vijendran (akv@eng.sun.com)
099: */
100: public class AttachmentPartImpl extends AttachmentPart {
101:
102: protected static Logger log = Logger.getLogger(
103: LogDomainConstants.SOAP_DOMAIN,
104: "com.sun.xml.messaging.saaj.soap.LocalStrings");
105:
106: static {
107: try {
108: CommandMap map = CommandMap.getDefaultCommandMap();
109: if (map instanceof MailcapCommandMap) {
110: MailcapCommandMap mailMap = (MailcapCommandMap) map;
111: String hndlrStr = ";;x-java-content-handler=";
112: mailMap
113: .addMailcap("text/xml"
114: + hndlrStr
115: + "com.sun.xml.messaging.saaj.soap.XmlDataContentHandler");
116: mailMap
117: .addMailcap("application/xml"
118: + hndlrStr
119: + "com.sun.xml.messaging.saaj.soap.XmlDataContentHandler");
120: mailMap
121: .addMailcap("application/fastinfoset"
122: + hndlrStr
123: + "com.sun.xml.messaging.saaj.soap.FastInfosetDataContentHandler");
124: mailMap
125: .addMailcap("image/jpeg"
126: + hndlrStr
127: + "com.sun.xml.messaging.saaj.soap.JpegDataContentHandler");
128: mailMap
129: .addMailcap("image/gif"
130: + hndlrStr
131: + "com.sun.xml.messaging.saaj.soap.GifDataContentHandler");
132: /*mailMap.addMailcap(
133: "multipart/*"
134: + hndlrStr
135: + "com.sun.xml.messaging.saaj.soap.MultipartDataContentHandler");*/
136: mailMap
137: .addMailcap("image/*"
138: + hndlrStr
139: + "com.sun.xml.messaging.saaj.soap.ImageDataContentHandler");
140: mailMap
141: .addMailcap("text/plain"
142: + hndlrStr
143: + "com.sun.xml.messaging.saaj.soap.StringDataContentHandler");
144: } else {
145: throw new SOAPExceptionImpl(
146: "Default CommandMap is not a MailcapCommandMap");
147: }
148: } catch (Throwable t) {
149: log.log(Level.SEVERE,
150: "SAAJ0508.soap.cannot.register.handlers", t);
151: if (t instanceof RuntimeException) {
152: throw (RuntimeException) t;
153: } else {
154: throw new RuntimeException(t.getLocalizedMessage());
155: }
156: }
157: };
158:
159: private final MimeHeaders headers;
160: private MimeBodyPart rawContent = null;
161: private DataHandler dataHandler = null;
162:
163: public AttachmentPartImpl() {
164: headers = new MimeHeaders();
165: }
166:
167: public int getSize() throws SOAPException {
168: byte[] bytes;
169:
170: if ((rawContent == null) && (dataHandler == null))
171: return 0;
172:
173: if (rawContent != null) {
174: try {
175: return rawContent.getSize();
176: } catch (Exception ex) {
177: log
178: .log(
179: Level.SEVERE,
180: "SAAJ0573.soap.attachment.getrawbytes.ioexception",
181: new String[] { ex.getLocalizedMessage() });
182: throw new SOAPExceptionImpl("Raw InputStream Error: "
183: + ex);
184: }
185: } else {
186: ByteOutputStream bout = new ByteOutputStream();
187: try {
188: dataHandler.writeTo(bout);
189: } catch (IOException ex) {
190: log.log(Level.SEVERE, "SAAJ0501.soap.data.handler.err",
191: new String[] { ex.getLocalizedMessage() });
192: throw new SOAPExceptionImpl("Data handler error: " + ex);
193: }
194: bytes = bout.getBytes();
195: if (bytes != null)
196: return bytes.length;
197: }
198: return -1;
199: }
200:
201: public void clearContent() {
202: dataHandler = null;
203: rawContent = null;
204: }
205:
206: public Object getContent() throws SOAPException {
207: try {
208: if (dataHandler != null) {
209: return getDataHandler().getContent();
210: } else if (rawContent != null) {
211: return rawContent.getContent();
212: } else {
213: log.severe("SAAJ0572.soap.no.content.for.attachment");
214: throw new SOAPExceptionImpl(
215: "No data handler/content associated with this attachment");
216: }
217: } catch (Exception ex) {
218: log
219: .log(
220: Level.SEVERE,
221: "SAAJ0575.soap.attachment.getcontent.exception",
222: ex);
223: throw new SOAPExceptionImpl(ex.getLocalizedMessage());
224: }
225: }
226:
227: public void setContent(Object object, String contentType)
228: throws IllegalArgumentException {
229: DataHandler dh = new DataHandler(object, contentType);
230:
231: setDataHandler(dh);
232: }
233:
234: public DataHandler getDataHandler() throws SOAPException {
235: if (dataHandler == null) {
236: if (rawContent != null) {
237: return new DataHandler(new MimePartDataSource(
238: rawContent));
239: }
240: log.severe("SAAJ0502.soap.no.handler.for.attachment");
241: throw new SOAPExceptionImpl(
242: "No data handler associated with this attachment");
243: }
244: return dataHandler;
245: }
246:
247: public void setDataHandler(DataHandler dataHandler)
248: throws IllegalArgumentException {
249: if (dataHandler == null) {
250: log.severe("SAAJ0503.soap.no.null.to.dataHandler");
251: throw new IllegalArgumentException(
252: "Null dataHandler argument to setDataHandler");
253: }
254: this .dataHandler = dataHandler;
255: rawContent = null;
256:
257: log.log(Level.FINE, "SAAJ0580.soap.set.Content-Type",
258: new String[] { dataHandler.getContentType() });
259: setMimeHeader("Content-Type", dataHandler.getContentType());
260: }
261:
262: public void removeAllMimeHeaders() {
263: headers.removeAllHeaders();
264: }
265:
266: public void removeMimeHeader(String header) {
267: headers.removeHeader(header);
268: }
269:
270: public String[] getMimeHeader(String name) {
271: return headers.getHeader(name);
272: }
273:
274: public void setMimeHeader(String name, String value) {
275: headers.setHeader(name, value);
276: }
277:
278: public void addMimeHeader(String name, String value) {
279: headers.addHeader(name, value);
280: }
281:
282: public Iterator getAllMimeHeaders() {
283: return headers.getAllHeaders();
284: }
285:
286: public Iterator getMatchingMimeHeaders(String[] names) {
287: return headers.getMatchingHeaders(names);
288: }
289:
290: public Iterator getNonMatchingMimeHeaders(String[] names) {
291: return headers.getNonMatchingHeaders(names);
292: }
293:
294: boolean hasAllHeaders(MimeHeaders hdrs) {
295: if (hdrs != null) {
296: Iterator i = hdrs.getAllHeaders();
297: while (i.hasNext()) {
298: MimeHeader hdr = (MimeHeader) i.next();
299: String[] values = headers.getHeader(hdr.getName());
300: boolean found = false;
301:
302: if (values != null) {
303: for (int j = 0; j < values.length; j++)
304: if (hdr.getValue().equalsIgnoreCase(values[j])) {
305: found = true;
306: break;
307: }
308: }
309:
310: if (!found) {
311: return false;
312: }
313: }
314: }
315: return true;
316: }
317:
318: MimeBodyPart getMimePart() throws SOAPException {
319: try {
320: if (rawContent != null) {
321: copyMimeHeaders(headers, rawContent);
322: return rawContent;
323: }
324:
325: MimeBodyPart envelope = new MimeBodyPart();
326:
327: envelope.setDataHandler(dataHandler);
328: copyMimeHeaders(headers, envelope);
329:
330: return envelope;
331: } catch (Exception ex) {
332: log.severe("SAAJ0504.soap.cannot.externalize.attachment");
333: throw new SOAPExceptionImpl(
334: "Unable to externalize attachment", ex);
335: }
336: }
337:
338: public static void copyMimeHeaders(MimeHeaders headers,
339: MimeBodyPart mbp) throws SOAPException {
340:
341: Iterator i = headers.getAllHeaders();
342:
343: while (i.hasNext())
344: try {
345: MimeHeader mh = (MimeHeader) i.next();
346:
347: mbp.setHeader(mh.getName(), mh.getValue());
348: } catch (Exception ex) {
349: log.severe("SAAJ0505.soap.cannot.copy.mime.hdr");
350: throw new SOAPExceptionImpl(
351: "Unable to copy MIME header", ex);
352: }
353: }
354:
355: public static void copyMimeHeaders(MimeBodyPart mbp,
356: AttachmentPartImpl ap) throws SOAPException {
357: try {
358: List hdr = mbp.getAllHeaders();
359: int sz = hdr.size();
360: for (int i = 0; i < sz; i++) {
361: Header h = (Header) hdr.get(i);
362: if (h.getName().equalsIgnoreCase("Content-Type"))
363: continue; // skip
364: ap.addMimeHeader(h.getName(), h.getValue());
365: }
366: } catch (Exception ex) {
367: log
368: .severe("SAAJ0506.soap.cannot.copy.mime.hdrs.into.attachment");
369: throw new SOAPExceptionImpl(
370: "Unable to copy MIME headers into attachment", ex);
371: }
372: }
373:
374: public void setBase64Content(InputStream content, String contentType)
375: throws SOAPException {
376: dataHandler = null;
377: try {
378: InputStream decoded = MimeUtility.decode(content, "base64");
379: InternetHeaders hdrs = new InternetHeaders();
380: hdrs.setHeader("Content-Type", contentType);
381: //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart
382: // Ctor with inputStream causes problems based on the InputStream
383: // has markSupported()==true
384: ByteOutputStream bos = new ByteOutputStream();
385: bos.write(decoded);
386: rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos
387: .getCount());
388: setMimeHeader("Content-Type", contentType);
389: } catch (Exception e) {
390: log
391: .log(
392: Level.SEVERE,
393: "SAAJ0578.soap.attachment.setbase64content.exception",
394: e);
395: throw new SOAPExceptionImpl(e.getLocalizedMessage());
396: }
397: }
398:
399: public InputStream getBase64Content() throws SOAPException {
400: InputStream stream;
401: if (rawContent != null) {
402: try {
403: stream = rawContent.getInputStream();
404: } catch (Exception e) {
405: log
406: .log(
407: Level.SEVERE,
408: "SAAJ0579.soap.attachment.getbase64content.exception",
409: e);
410: throw new SOAPExceptionImpl(e.getLocalizedMessage());
411: }
412: } else if (dataHandler != null) {
413: try {
414: stream = dataHandler.getInputStream();
415: } catch (IOException e) {
416: log
417: .severe("SAAJ0574.soap.attachment.datahandler.ioexception");
418: throw new SOAPExceptionImpl("DataHandler error" + e);
419: }
420: } else {
421: log.severe("SAAJ0572.soap.no.content.for.attachment");
422: throw new SOAPExceptionImpl(
423: "No data handler/content associated with this attachment");
424: }
425:
426: //TODO: Write a BASE64EncoderInputStream instead,
427: // this code below is inefficient
428: // where we are trying to read the whole attachment first
429: int len;
430: int size = 1024;
431: byte[] buf;
432: if (stream != null) {
433: try {
434: ByteArrayOutputStream bos = new ByteArrayOutputStream(
435: size);
436: //TODO: try and optimize this on the same lines as
437: // ByteOutputStream : to eliminate the temp buffer here
438: OutputStream ret = MimeUtility.encode(bos, "base64");
439: buf = new byte[size];
440: while ((len = stream.read(buf, 0, size)) != -1) {
441: ret.write(buf, 0, len);
442: }
443: ret.flush();
444: buf = bos.toByteArray();
445: return new ByteArrayInputStream(buf);
446: } catch (Exception e) {
447: // throw new SOAPException
448: log
449: .log(
450: Level.SEVERE,
451: "SAAJ0579.soap.attachment.getbase64content.exception",
452: e);
453: throw new SOAPExceptionImpl(e.getLocalizedMessage());
454: }
455: } else {
456: //throw new SOAPException
457: log.log(Level.SEVERE,
458: "SAAJ0572.soap.no.content.for.attachment");
459: throw new SOAPExceptionImpl(
460: "No data handler/content associated with this attachment");
461: }
462: }
463:
464: public void setRawContent(InputStream content, String contentType)
465: throws SOAPException {
466: dataHandler = null;
467: try {
468: InternetHeaders hdrs = new InternetHeaders();
469: hdrs.setHeader("Content-Type", contentType);
470: //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart
471: // Ctor with inputStream causes problems based on whether the InputStream has
472: // markSupported()==true or false
473: ByteOutputStream bos = new ByteOutputStream();
474: bos.write(content);
475: rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos
476: .getCount());
477: setMimeHeader("Content-Type", contentType);
478: } catch (Exception e) {
479: log.log(Level.SEVERE,
480: "SAAJ0576.soap.attachment.setrawcontent.exception",
481: e);
482: throw new SOAPExceptionImpl(e.getLocalizedMessage());
483: }
484: }
485:
486: /*
487: public void setRawContentBytes(byte[] content, String contentType)
488: throws SOAPException {
489: if (content == null) {
490: throw new SOAPExceptionImpl("Null content passed to setRawContentBytes");
491: }
492: dataHandler = null;
493: try {
494: InternetHeaders hdrs = new InternetHeaders();
495: hdrs.setHeader("Content-Type", contentType);
496: rawContent = new MimeBodyPart(hdrs, content, content.length);
497: setMimeHeader("Content-Type", contentType);
498: } catch (Exception e) {
499: log.log(Level.SEVERE, "SAAJ0576.soap.attachment.setrawcontent.exception", e);
500: throw new SOAPExceptionImpl(e.getLocalizedMessage());
501: }
502: } */
503:
504: public void setRawContentBytes(byte[] content, int off, int len,
505: String contentType) throws SOAPException {
506: if (content == null) {
507: throw new SOAPExceptionImpl(
508: "Null content passed to setRawContentBytes");
509: }
510: dataHandler = null;
511: try {
512: InternetHeaders hdrs = new InternetHeaders();
513: hdrs.setHeader("Content-Type", contentType);
514: rawContent = new MimeBodyPart(hdrs, content, off, len);
515: setMimeHeader("Content-Type", contentType);
516: } catch (Exception e) {
517: log.log(Level.SEVERE,
518: "SAAJ0576.soap.attachment.setrawcontent.exception",
519: e);
520: throw new SOAPExceptionImpl(e.getLocalizedMessage());
521: }
522: }
523:
524: public InputStream getRawContent() throws SOAPException {
525: if (rawContent != null) {
526: try {
527: return rawContent.getInputStream();
528: } catch (Exception e) {
529: log
530: .log(
531: Level.SEVERE,
532: "SAAJ0577.soap.attachment.getrawcontent.exception",
533: e);
534: throw new SOAPExceptionImpl(e.getLocalizedMessage());
535: }
536: } else if (dataHandler != null) {
537: try {
538: return dataHandler.getInputStream();
539: } catch (IOException e) {
540: log
541: .severe("SAAJ0574.soap.attachment.datahandler.ioexception");
542: throw new SOAPExceptionImpl("DataHandler error" + e);
543: }
544: } else {
545: log.severe("SAAJ0572.soap.no.content.for.attachment");
546: throw new SOAPExceptionImpl(
547: "No data handler/content associated with this attachment");
548: }
549: }
550:
551: //TODO: investigate size differences in mime.AttachImageTest
552: public byte[] getRawContentBytes() throws SOAPException {
553: InputStream ret;
554: if (rawContent != null) {
555: try {
556: ret = rawContent.getInputStream();
557: return ASCIIUtility.getBytes(ret);
558: } catch (Exception e) {
559: log
560: .log(
561: Level.SEVERE,
562: "SAAJ0577.soap.attachment.getrawcontent.exception",
563: e);
564: throw new SOAPExceptionImpl(e.getLocalizedMessage());
565: }
566: } else if (dataHandler != null) {
567: try {
568: ret = dataHandler.getInputStream();
569: return ASCIIUtility.getBytes(ret);
570: } catch (IOException e) {
571: log
572: .severe("SAAJ0574.soap.attachment.datahandler.ioexception");
573: throw new SOAPExceptionImpl("DataHandler error" + e);
574: }
575: } else {
576: log.severe("SAAJ0572.soap.no.content.for.attachment");
577: throw new SOAPExceptionImpl(
578: "No data handler/content associated with this attachment");
579: }
580: }
581:
582: // attachments are equal if they are the same reference
583: public boolean equals(Object o) {
584: return (this == o);
585: }
586:
587: public MimeHeaders getMimeHeaders() {
588: return headers;
589: }
590:
591: }
|