1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xml.internal.serializer;
  22 
  23 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
  24 import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
  25 import com.sun.org.apache.xml.internal.serializer.utils.Utils;
  26 import java.util.Properties;
  27 import javax.xml.transform.OutputKeys;
  28 import org.xml.sax.ContentHandler;
  29 
  30 /**
  31  * This class is a public API, it is a factory for creating serializers.
  32    *
  33    * The properties object passed to the getSerializer() method should be created by
  34    * the OutputPropertiesFactory. Although the properties object
  35    * used to create a serializer does not need to be obtained
  36    * from OutputPropertiesFactory,
  37    * using this factory ensures that the default key/value properties
  38    * are set for the given output "method".
  39    *
  40    * <p>
  41    * The standard property keys supported are: "method", "version", "encoding",
  42    * "omit-xml-declaration", "standalone", doctype-public",
  43    * "doctype-system", "cdata-section-elements", "indent", "media-type".
  44    * These property keys and their values are described in the XSLT recommendation,
  45    * see {@link <a href="http://www.w3.org/TR/1999/REC-xslt-19991116"> XSLT 1.0 recommendation</a>}
  46    *
  47    * <p>
  48    * The value of the "cdata-section-elements" property key is a whitespace
  49    * separated list of elements. If the element is in a namespace then
  50    * value is passed in this format: {uri}localName
  51    *
  52    * <p>
  53    * The non-standard property keys supported are defined in {@link OutputPropertiesFactory}.
  54    *
  55    * @see OutputPropertiesFactory
  56    * @see Method
  57    * @see Serializer
  58  * @LastModified: Oct 2017
  59    */
  60 public final class SerializerFactory
  61 {
  62   /**
  63    * This constructor is private just to prevent the creation of such an object.
  64    */
  65 
  66   private SerializerFactory() {
  67 
  68   }
  69 
  70   /**
  71    * Returns a serializer for the specified output method. The output method
  72    * is specified by the value of the property associated with the "method" key.
  73    * If no implementation exists that supports the specified output method
  74    * an exception of some type will be thrown.
  75    * For a list of the output "method" key values see {@link Method}.
  76    *
  77    * @param format The output format, minimally the "method" property must be set.
  78    * @return A suitable serializer.
  79    * @throws IllegalArgumentException if method is
  80    * null or an appropriate serializer can't be found
  81    * @throws Exception if the class for the serializer is found but does not
  82    * implement ContentHandler.
  83    * @throws WrappedRuntimeException if an exception is thrown while trying to find serializer
  84    */
  85   public static Serializer getSerializer(Properties format)
  86   {
  87       Serializer ser;
  88 
  89       try
  90       {
  91         String method = format.getProperty(OutputKeys.METHOD);
  92 
  93         if (method == null) {
  94             String msg = Utils.messages.createMessage(
  95                 MsgKey.ER_FACTORY_PROPERTY_MISSING,
  96                 new Object[] { OutputKeys.METHOD});
  97             throw new IllegalArgumentException(msg);
  98         }
  99 
 100         String className =
 101             format.getProperty(OutputPropertiesFactory.S_KEY_CONTENT_HANDLER);
 102 
 103 
 104         if (null == className)
 105         {
 106             // Missing Content Handler property, load default using OutputPropertiesFactory
 107             Properties methodDefaults =
 108                 OutputPropertiesFactory.getDefaultMethodProperties(method);
 109             className =
 110             methodDefaults.getProperty(OutputPropertiesFactory.S_KEY_CONTENT_HANDLER);
 111             if (null == className) {
 112                 String msg = Utils.messages.createMessage(
 113                     MsgKey.ER_FACTORY_PROPERTY_MISSING,
 114                     new Object[] { OutputPropertiesFactory.S_KEY_CONTENT_HANDLER});
 115                 throw new IllegalArgumentException(msg);
 116             }
 117 
 118         }
 119 
 120 
 121 
 122         Class<?> cls = ObjectFactory.findProviderClass(className, true);
 123 
 124         // _serializers.put(method, cls);
 125 
 126         Object obj = cls.getConstructor().newInstance();
 127 
 128         if (obj instanceof SerializationHandler)
 129         {
 130               // this is one of the supplied serializers
 131             ser = (Serializer) obj;
 132             ser.setOutputFormat(format);
 133         }
 134         else
 135         {
 136               /*
 137                *  This  must be a user defined Serializer.
 138                *  It had better implement ContentHandler.
 139                */
 140                if (obj instanceof ContentHandler)
 141                {
 142 
 143                   /*
 144                    * The user defined serializer defines ContentHandler,
 145                    * but we need to wrap it with ToXMLSAXHandler which
 146                    * will collect SAX-like events and emit true
 147                    * SAX ContentHandler events to the users handler.
 148                    */
 149                   className = SerializerConstants.DEFAULT_SAX_SERIALIZER;
 150                   cls = ObjectFactory.findProviderClass(className, true);
 151                   SerializationHandler sh =
 152                       (SerializationHandler) cls.getConstructor().newInstance();
 153                   sh.setContentHandler( (ContentHandler) obj);
 154                   sh.setOutputFormat(format);
 155 
 156                   ser = sh;
 157                }
 158                else
 159                {
 160                   // user defined serializer does not implement
 161                   // ContentHandler, ... very bad
 162                    throw new Exception(
 163                        Utils.messages.createMessage(
 164                            MsgKey.ER_SERIALIZER_NOT_CONTENTHANDLER,
 165                                new Object[] { className}));
 166                }
 167 
 168         }
 169       }
 170       catch (Exception e)
 171       {
 172         throw new com.sun.org.apache.xml.internal.serializer.utils.WrappedRuntimeException(e);
 173       }
 174 
 175       // If we make it to here ser is not null.
 176       return ser;
 177   }
 178 }