1 /*
   2  * Copyright (c) 1997, 2015, 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  */
  25 
  26 package com.sun.xml.internal.ws.api.message.saaj;
  27 
  28 import java.util.Iterator;
  29 
  30 import javax.xml.soap.AttachmentPart;
  31 import javax.xml.soap.MessageFactory;
  32 import javax.xml.soap.SAAJMetaFactory;
  33 import javax.xml.soap.SOAPException;
  34 import javax.xml.soap.SOAPFactory;
  35 import javax.xml.soap.SOAPMessage;
  36 import javax.xml.stream.XMLStreamException;
  37 
  38 import org.xml.sax.SAXException;
  39 
  40 import com.sun.xml.internal.bind.marshaller.SAX2DOMEx;
  41 import com.sun.xml.internal.ws.api.SOAPVersion;
  42 import com.sun.xml.internal.ws.api.message.Attachment;
  43 import com.sun.xml.internal.ws.api.message.AttachmentEx;
  44 import com.sun.xml.internal.ws.api.message.Message;
  45 import com.sun.xml.internal.ws.api.message.Packet;
  46 import com.sun.xml.internal.ws.message.saaj.SAAJMessage;
  47 import com.sun.xml.internal.ws.util.ServiceFinder;
  48 import com.sun.xml.internal.ws.util.xml.XmlUtil;
  49 
  50 /**
  51  * Factory SPI for SAAJ implementations
  52  *
  53  * @since 2.2.6
  54  */
  55 public class SAAJFactory {
  56         private static final SAAJFactory instance = new SAAJFactory();
  57 
  58     /**
  59      * Creates a new <code>MessageFactory</code> object that is an instance
  60      * of the specified implementation.  May be a dynamic message factory,
  61      * a SOAP 1.1 message factory, or a SOAP 1.2 message factory. A dynamic
  62      * message factory creates messages based on the MIME headers specified
  63      * as arguments to the <code>createMessage</code> method.
  64      *
  65      * This method uses the SAAJMetaFactory to locate the implementation class
  66      * and create the MessageFactory instance.
  67      *
  68      * @return a new instance of a <code>MessageFactory</code>
  69      *
  70      * @param protocol  a string constant representing the class of the
  71      *                   specified message factory implementation. May be
  72      *                   either <code>DYNAMIC_SOAP_PROTOCOL</code>,
  73      *                   <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
  74      *                   as) <code>SOAP_1_1_PROTOCOL</code>, or
  75      *                   <code>SOAP_1_2_PROTOCOL</code>.
  76      *
  77      * @exception SOAPException if there was an error in creating the
  78      *            specified implementation of  <code>MessageFactory</code>.
  79      * @see SAAJMetaFactory
  80      */
  81         public static MessageFactory getMessageFactory(String protocol) throws SOAPException {
  82                 for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
  83                         MessageFactory mf = s.createMessageFactory(protocol);
  84                         if (mf != null)
  85                                 return mf;
  86                 }
  87 
  88         return instance.createMessageFactory(protocol);
  89         }
  90 
  91     /**
  92      * Creates a new <code>SOAPFactory</code> object that is an instance of
  93      * the specified implementation, this method uses the SAAJMetaFactory to
  94      * locate the implementation class and create the SOAPFactory instance.
  95      *
  96      * @return a new instance of a <code>SOAPFactory</code>
  97      *
  98      * @param protocol  a string constant representing the protocol of the
  99      *                   specified SOAP factory implementation. May be
 100      *                   either <code>DYNAMIC_SOAP_PROTOCOL</code>,
 101      *                   <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
 102      *                   as) <code>SOAP_1_1_PROTOCOL</code>, or
 103      *                   <code>SOAP_1_2_PROTOCOL</code>.
 104      *
 105      * @exception SOAPException if there was an error creating the
 106      *            specified <code>SOAPFactory</code>
 107      * @see SAAJMetaFactory
 108      */
 109         public static SOAPFactory getSOAPFactory(String protocol) throws SOAPException {
 110                 for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
 111                         SOAPFactory sf = s.createSOAPFactory(protocol);
 112                         if (sf != null)
 113                                 return sf;
 114                 }
 115 
 116         return instance.createSOAPFactory(protocol);
 117         }
 118 
 119         /**
 120          * Creates Message from SOAPMessage
 121          * @param saaj SOAPMessage
 122          * @return created Message
 123          */
 124         public static Message create(SOAPMessage saaj) {
 125                 for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
 126                         Message m = s.createMessage(saaj);
 127                         if (m != null)
 128                                 return m;
 129                 }
 130 
 131         return instance.createMessage(saaj);
 132         }
 133 
 134         /**
 135          * Reads Message as SOAPMessage.  After this call message is consumed.
 136          * @param soapVersion SOAP version
 137          * @param message Message
 138          * @return Created SOAPMessage
 139          * @throws SOAPException if SAAJ processing fails
 140          */
 141         public static SOAPMessage read(SOAPVersion soapVersion, Message message) throws SOAPException {
 142                 for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
 143                         SOAPMessage msg = s.readAsSOAPMessage(soapVersion, message);
 144                         if (msg != null)
 145                                 return msg;
 146                 }
 147 
 148         return instance.readAsSOAPMessage(soapVersion, message);
 149         }
 150 
 151         /**
 152      * Reads Message as SOAPMessage.  After this call message is consumed.
 153      * @param soapVersion SOAP version
 154      * @param message Message
 155      * @param packet The packet that owns the Message
 156      * @return Created SOAPMessage
 157      * @throws SOAPException if SAAJ processing fails
 158      */
 159     public static SOAPMessage read(SOAPVersion soapVersion, Message message, Packet packet) throws SOAPException {
 160         SAAJFactory saajfac = packet.getSAAJFactory();
 161         if (saajfac != null) {
 162             SOAPMessage msg = saajfac.readAsSOAPMessage(soapVersion, message, packet);
 163             if (msg != null) return msg;
 164         }
 165         for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
 166             SOAPMessage msg = s.readAsSOAPMessage(soapVersion, message, packet);
 167             if (msg != null)
 168                 return msg;
 169         }
 170 
 171         return instance.readAsSOAPMessage(soapVersion, message, packet);
 172     }
 173 
 174     /**
 175      * Reads the message within the Packet to a SAAJMessage.  After this call message is consumed.
 176      * @param packet Packet
 177      * @return Created SAAJPMessage
 178      * @throws SOAPException if SAAJ processing fails
 179      */
 180     public static SAAJMessage read(Packet packet) throws SOAPException {
 181         SAAJFactory saajfac = packet.getSAAJFactory();
 182         if (saajfac != null) {
 183             SAAJMessage msg = saajfac.readAsSAAJ(packet);
 184             if (msg != null) return msg;
 185         }
 186         // Use the Component from the Packet if it exists.  Note the logic
 187         // in the ServiceFinder is such that find(Class) is not equivalent
 188         // to find (Class, null), so the ternary operator is needed.
 189         ServiceFinder<SAAJFactory> factories = (packet.component != null ?
 190                 ServiceFinder.find(SAAJFactory.class, packet.component) :
 191                 ServiceFinder.find(SAAJFactory.class));
 192         for (SAAJFactory s : factories) {
 193             SAAJMessage msg = s.readAsSAAJ(packet);
 194             if (msg != null) return msg;
 195         }
 196         return instance.readAsSAAJ(packet);
 197     }
 198 
 199     /**
 200      * Reads the message within the Packet to a SAAJMessage.  After this call message is consumed.
 201      * @param packet Packet
 202      * @return Created SAAJPMessage
 203      * @throws SOAPException if SAAJ processing fails
 204      */
 205     public SAAJMessage readAsSAAJ(Packet packet) throws SOAPException {
 206         SOAPVersion v = packet.getMessage().getSOAPVersion();
 207         SOAPMessage msg = readAsSOAPMessage(v, packet.getMessage());
 208         return new SAAJMessage(msg);
 209     }
 210 
 211     /**
 212      * Creates a new <code>MessageFactory</code> object that is an instance
 213      * of the specified implementation.  May be a dynamic message factory,
 214      * a SOAP 1.1 message factory, or a SOAP 1.2 message factory. A dynamic
 215      * message factory creates messages based on the MIME headers specified
 216      * as arguments to the <code>createMessage</code> method.
 217      *
 218      * This method uses the SAAJMetaFactory to locate the implementation class
 219      * and create the MessageFactory instance.
 220      *
 221      * @return a new instance of a <code>MessageFactory</code>
 222      *
 223      * @param protocol  a string constant representing the class of the
 224      *                   specified message factory implementation. May be
 225      *                   either <code>DYNAMIC_SOAP_PROTOCOL</code>,
 226      *                   <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
 227      *                   as) <code>SOAP_1_1_PROTOCOL</code>, or
 228      *                   <code>SOAP_1_2_PROTOCOL</code>.
 229      *
 230      * @exception SOAPException if there was an error in creating the
 231      *            specified implementation of  <code>MessageFactory</code>.
 232      * @see SAAJMetaFactory
 233      */
 234         public MessageFactory createMessageFactory(String protocol) throws SOAPException {
 235                 return MessageFactory.newInstance(protocol);
 236         }
 237 
 238     /**
 239      * Creates a new <code>SOAPFactory</code> object that is an instance of
 240      * the specified implementation, this method uses the SAAJMetaFactory to
 241      * locate the implementation class and create the SOAPFactory instance.
 242      *
 243      * @return a new instance of a <code>SOAPFactory</code>
 244      *
 245      * @param protocol  a string constant representing the protocol of the
 246      *                   specified SOAP factory implementation. May be
 247      *                   either <code>DYNAMIC_SOAP_PROTOCOL</code>,
 248      *                   <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
 249      *                   as) <code>SOAP_1_1_PROTOCOL</code>, or
 250      *                   <code>SOAP_1_2_PROTOCOL</code>.
 251      *
 252      * @exception SOAPException if there was an error creating the
 253      *            specified <code>SOAPFactory</code>
 254      * @see SAAJMetaFactory
 255      */
 256         public SOAPFactory createSOAPFactory(String protocol) throws SOAPException {
 257                 return SOAPFactory.newInstance(protocol);
 258         }
 259 
 260         /**
 261          * Creates Message from SOAPMessage
 262          * @param saaj SOAPMessage
 263          * @return created Message
 264          */
 265         public Message createMessage(SOAPMessage saaj) {
 266                 return new SAAJMessage(saaj);
 267         }
 268 
 269         /**
 270          * Reads Message as SOAPMessage.  After this call message is consumed.
 271          * @param soapVersion SOAP version
 272          * @param message Message
 273          * @return Created SOAPMessage
 274          * @throws SOAPException if SAAJ processing fails
 275          */
 276         public SOAPMessage readAsSOAPMessage(final SOAPVersion soapVersion, final Message message) throws SOAPException {
 277         SOAPMessage msg = soapVersion.getMessageFactory().createMessage();
 278         SaajStaxWriter writer = new SaajStaxWriter(msg, soapVersion.nsUri);
 279         try {
 280             message.writeTo(writer);
 281         } catch (XMLStreamException e) {
 282             throw (e.getCause() instanceof SOAPException) ? (SOAPException) e.getCause() : new SOAPException(e);
 283         }
 284         msg = writer.getSOAPMessage();
 285         addAttachmentsToSOAPMessage(msg, message);
 286         if (msg.saveRequired())
 287                 msg.saveChanges();
 288         return msg;
 289         }
 290 
 291     public SOAPMessage readAsSOAPMessageSax2Dom(final SOAPVersion soapVersion, final Message message) throws SOAPException {
 292         SOAPMessage msg = soapVersion.getMessageFactory().createMessage();
 293         SAX2DOMEx s2d = new SAX2DOMEx(msg.getSOAPPart());
 294         try {
 295             message.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER);
 296         } catch (SAXException e) {
 297             throw new SOAPException(e);
 298         }
 299         addAttachmentsToSOAPMessage(msg, message);
 300         if (msg.saveRequired())
 301             msg.saveChanges();
 302         return msg;
 303     }
 304 
 305         static protected void addAttachmentsToSOAPMessage(SOAPMessage msg, Message message) {
 306         for(Attachment att : message.getAttachments()) {
 307             AttachmentPart part = msg.createAttachmentPart();
 308             part.setDataHandler(att.asDataHandler());
 309 
 310             // Be safe and avoid double angle-brackets.
 311             String cid = att.getContentId();
 312             if (cid != null) {
 313                 if (cid.startsWith("<") && cid.endsWith(">"))
 314                     part.setContentId(cid);
 315                 else
 316                     part.setContentId('<' + cid + '>');
 317             }
 318 
 319             // Add any MIME headers beside Content-ID, which is already
 320             // accounted for above, and Content-Type, which is provided
 321             // by the DataHandler above.
 322             if (att instanceof AttachmentEx) {
 323                 AttachmentEx ax = (AttachmentEx) att;
 324                 Iterator<AttachmentEx.MimeHeader> imh = ax.getMimeHeaders();
 325                 while (imh.hasNext()) {
 326                     AttachmentEx.MimeHeader ame = imh.next();
 327                     if ((!"Content-ID".equals(ame.getName()))
 328                             && (!"Content-Type".equals(ame.getName())))
 329                         part.addMimeHeader(ame.getName(), ame.getValue());
 330                 }
 331             }
 332             msg.addAttachmentPart(part);
 333         }
 334     }
 335 
 336     /**
 337      * Reads Message as SOAPMessage.  After this call message is consumed.
 338      * The implementation in this class simply calls readAsSOAPMessage(SOAPVersion, Message),
 339      * and ignores the other parameters
 340      * Subclasses can override and choose to base SOAPMessage creation on Packet properties if needed
 341      * @param soapVersion SOAP version
 342      * @param message Message
 343      * @return Created SOAPMessage
 344      * @throws SOAPException if SAAJ processing fails
 345      */
 346         public SOAPMessage readAsSOAPMessage(SOAPVersion soapVersion, Message message, Packet packet) throws SOAPException {
 347             return readAsSOAPMessage(soapVersion, message);
 348         }
 349 }