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