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 
SerializerFactory()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    */
getSerializer(Properties format)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 }
179