KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > serializer > OutputPropertiesFactory


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: OutputPropertiesFactory.java,v 1.5 2004/02/18 22:57:44 minchau Exp $
18  */

19 package org.apache.xml.serializer;
20
21 import java.io.BufferedInputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.security.AccessController JavaDoc;
25 import java.security.PrivilegedAction JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Properties JavaDoc;
28 import javax.xml.transform.OutputKeys JavaDoc;
29
30 import org.apache.xml.res.XMLErrorResources;
31 import org.apache.xml.res.XMLMessages;
32 import org.apache.xml.utils.Constants;
33 import org.apache.xml.utils.WrappedRuntimeException;
34
35 /**
36  * This class acts as a factory to generate properties for the given output type
37  * ("xml", "text", "html")..
38  */

39 public class OutputPropertiesFactory
40 {
41     //************************************************************
42
//* PUBLIC CONSTANTS
43
//************************************************************
44
/** Built-in extensions namespace, reexpressed in {namespaceURI} syntax
45      * suitable for prepending to a localname to produce a "universal
46      * name".
47      */

48     public static final String JavaDoc S_BUILTIN_EXTENSIONS_UNIVERSAL =
49         "{" + Constants.S_BUILTIN_EXTENSIONS_URL + "}";
50
51     // Some special Xalan keys.
52

53     /** The number of whitespaces to indent by, if indent="yes". */
54     public static final String JavaDoc S_KEY_INDENT_AMOUNT =
55         S_BUILTIN_EXTENSIONS_UNIVERSAL + "indent-amount";
56
57     /**
58      * Fully qualified name of class with a default constructor that
59      * implements the ContentHandler interface, where the result tree events
60      * will be sent to.
61      */

62     public static final String JavaDoc S_KEY_CONTENT_HANDLER =
63         S_BUILTIN_EXTENSIONS_UNIVERSAL + "content-handler";
64
65     /** File name of file that specifies character to entity reference mappings. */
66     public static final String JavaDoc S_KEY_ENTITIES =
67         S_BUILTIN_EXTENSIONS_UNIVERSAL + "entities";
68
69     /** Use a value of "yes" if the href values for HTML serialization should
70      * use %xx escaping. */

71     public static final String JavaDoc S_USE_URL_ESCAPING =
72         S_BUILTIN_EXTENSIONS_UNIVERSAL + "use-url-escaping";
73
74     /** Use a value of "yes" if the META tag should be omitted where it would
75      * otherwise be supplied.
76      */

77     public static final String JavaDoc S_OMIT_META_TAG =
78         S_BUILTIN_EXTENSIONS_UNIVERSAL + "omit-meta-tag";
79
80     /**
81      * The old built-in extension namespace
82      */

83     public static final String JavaDoc S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL =
84         "{" + Constants.S_BUILTIN_OLD_EXTENSIONS_URL + "}";
85
86     /**
87      * The length of the old built-in extension namespace
88      */

89     public static final int S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL_LEN =
90         S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL.length();
91
92     //************************************************************
93
//* PRIVATE CONSTANTS
94
//************************************************************
95

96     private static final String JavaDoc S_XSLT_PREFIX = "xslt.output.";
97     private static final int S_XSLT_PREFIX_LEN = S_XSLT_PREFIX.length();
98     private static final String JavaDoc S_XALAN_PREFIX = "org.apache.xslt.";
99     private static final int S_XALAN_PREFIX_LEN = S_XALAN_PREFIX.length();
100
101     /** Synchronization object for lazy initialization of the above tables. */
102     private static Integer JavaDoc m_synch_object = new Integer JavaDoc(1);
103
104     /** the directory in which the various method property files are located */
105     private static final String JavaDoc PROP_DIR = "org/apache/xml/serializer/";
106     /** property file for default XML properties */
107     private static final String JavaDoc PROP_FILE_XML = "output_xml.properties";
108     /** property file for default TEXT properties */
109     private static final String JavaDoc PROP_FILE_TEXT = "output_text.properties";
110     /** property file for default HTML properties */
111     private static final String JavaDoc PROP_FILE_HTML = "output_html.properties";
112     /** property file for default UNKNOWN (Either XML or HTML, to be determined later) properties */
113     private static final String JavaDoc PROP_FILE_UNKNOWN = "output_unknown.properties";
114
115     //************************************************************
116
//* PRIVATE STATIC FIELDS
117
//************************************************************
118

119     /** The default properties of all output files. */
120     private static Properties JavaDoc m_xml_properties = null;
121
122     /** The default properties when method="html". */
123     private static Properties JavaDoc m_html_properties = null;
124
125     /** The default properties when method="text". */
126     private static Properties JavaDoc m_text_properties = null;
127
128     /** The properties when method="" for the "unknown" wrapper */
129     private static Properties JavaDoc m_unknown_properties = null;
130
131     private static final Class JavaDoc
132         ACCESS_CONTROLLER_CLASS = findAccessControllerClass();
133
134     private static Class JavaDoc findAccessControllerClass() {
135         try
136         {
137             // This Class was introduced in JDK 1.2. With the re-architecture of
138
// security mechanism ( starting in JDK 1.2 ), we have option of
139
// giving privileges to certain part of code using doPrivileged block.
140
// In JDK1.1.X applications won't be having security manager and if
141
// there is security manager ( in applets ), code need to be signed
142
// and trusted for having access to resources.
143

144             return Class.forName("java.security.AccessController");
145         }
146         catch (Exception JavaDoc e)
147         {
148             //User may be using older JDK ( JDK <1.2 ). Allow him/her to use it.
149
// But don't try to use doPrivileged
150
}
151
152         return null;
153     }
154
155     /**
156      * Creates an empty OutputProperties with the defaults specified by
157      * a property file. The method argument is used to construct a string of
158      * the form output_[method].properties (for instance, output_html.properties).
159      * The output_xml.properties file is always used as the base.
160      * <p>At the moment, anything other than 'text', 'xml', and 'html', will
161      * use the output_xml.properties file.</p>
162      *
163      * @param method non-null reference to method name.
164      *
165      * @return Properties object that holds the defaults for the given method.
166      */

167     static public Properties JavaDoc getDefaultMethodProperties(String JavaDoc method)
168     {
169         String JavaDoc fileName = null;
170         Properties JavaDoc defaultProperties = null;
171         // According to this article : Double-check locking does not work
172
// http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-toolbox.html
173
try
174         {
175             synchronized (m_synch_object)
176             {
177                 if (null == m_xml_properties) // double check
178
{
179                     fileName = PROP_FILE_XML;
180                     m_xml_properties = loadPropertiesFile(fileName, null);
181                 }
182             }
183
184             if (method.equals(Method.XML))
185             {
186                 defaultProperties = m_xml_properties;
187             }
188             else if (method.equals(Method.HTML))
189             {
190                 if (null == m_html_properties) // double check
191
{
192                     fileName = PROP_FILE_HTML;
193                     m_html_properties =
194                         loadPropertiesFile(fileName, m_xml_properties);
195                 }
196
197                 defaultProperties = m_html_properties;
198             }
199             else if (method.equals(Method.TEXT))
200             {
201                 if (null == m_text_properties) // double check
202
{
203                     fileName = PROP_FILE_TEXT;
204                     m_text_properties =
205                         loadPropertiesFile(fileName, m_xml_properties);
206                     if (null
207                         == m_text_properties.getProperty(OutputKeys.ENCODING))
208                     {
209                         String JavaDoc mimeEncoding = Encodings.getMimeEncoding(null);
210                         m_text_properties.put(
211                             OutputKeys.ENCODING,
212                             mimeEncoding);
213                     }
214                 }
215
216                 defaultProperties = m_text_properties;
217             }
218             else if (method.equals(org.apache.xml.serializer.Method.UNKNOWN))
219             {
220                 if (null == m_unknown_properties) // double check
221
{
222                     fileName = PROP_FILE_UNKNOWN;
223                     m_unknown_properties =
224                         loadPropertiesFile(fileName, m_xml_properties);
225                 }
226
227                 defaultProperties = m_unknown_properties;
228             }
229             else
230             {
231                 // TODO: Calculate res file from name.
232
defaultProperties = m_xml_properties;
233             }
234         }
235         catch (IOException JavaDoc ioe)
236         {
237             throw new WrappedRuntimeException(
238                 XMLMessages.createXMLMessage(
239                     XMLErrorResources.ER_COULD_NOT_LOAD_METHOD_PROPERTY,
240                     new Object JavaDoc[] { fileName, method }),
241                 ioe);
242         }
243
244         return new Properties JavaDoc(defaultProperties);
245     }
246
247     /**
248      * Load the properties file from a resource stream. If a
249      * key name such as "org.apache.xslt.xxx", fix up the start of
250      * string to be a curly namespace. If a key name starts with
251      * "xslt.output.xxx", clip off "xslt.output.". If a key name *or* a
252      * key value is discovered, check for : in the text, and
253      * fix it up to be ":", since earlier versions of the JDK do not
254      * handle the escape sequence (at least in key names).
255      *
256      * @param resourceName non-null reference to resource name.
257      * @param defaults Default properties, which may be null.
258      */

259     static private Properties JavaDoc loadPropertiesFile(
260         final String JavaDoc resourceName,
261         Properties JavaDoc defaults)
262         throws IOException JavaDoc
263     {
264
265         // This static method should eventually be moved to a thread-specific class
266
// so that we can cache the ContextClassLoader and bottleneck all properties file
267
// loading throughout Xalan.
268

269         Properties JavaDoc props = new Properties JavaDoc(defaults);
270
271         InputStream JavaDoc is = null;
272         BufferedInputStream JavaDoc bis = null;
273
274         try
275         {
276             if (ACCESS_CONTROLLER_CLASS != null)
277             {
278                 is = (InputStream JavaDoc) AccessController
279                     .doPrivileged(new PrivilegedAction JavaDoc() {
280                         public Object JavaDoc run()
281                         {
282                             return OutputPropertiesFactory.class
283                                 .getResourceAsStream(resourceName);
284                         }
285                     });
286             }
287             else
288             {
289                 // User may be using older JDK ( JDK < 1.2 )
290
is = OutputPropertiesFactory.class
291                     .getResourceAsStream(resourceName);
292             }
293
294             bis = new BufferedInputStream JavaDoc(is);
295             props.load(bis);
296         }
297         catch (IOException JavaDoc ioe)
298         {
299             if (defaults == null)
300             {
301                 throw ioe;
302             }
303             else
304             {
305                 throw new WrappedRuntimeException(
306                     XMLMessages.createXMLMessage(
307                         XMLErrorResources.ER_COULD_NOT_LOAD_RESOURCE,
308                         new Object JavaDoc[] { resourceName }),
309                     ioe);
310                 //"Could not load '"+resourceName+"' (check CLASSPATH), now using just the defaults ", ioe);
311
}
312         }
313         catch (SecurityException JavaDoc se)
314         {
315             // Repeat IOException handling for sandbox/applet case -sc
316
if (defaults == null)
317             {
318                 throw se;
319             }
320             else
321             {
322                 throw new WrappedRuntimeException(
323                     XMLMessages.createXMLMessage(
324                         XMLErrorResources.ER_COULD_NOT_LOAD_RESOURCE,
325                         new Object JavaDoc[] { resourceName }),
326                     se);
327                 //"Could not load '"+resourceName+"' (check CLASSPATH, applet security), now using just the defaults ", se);
328
}
329         }
330         finally
331         {
332             if (bis != null)
333             {
334                 bis.close();
335             }
336             if (is != null)
337             {
338                 is.close();
339             }
340         }
341
342         // Note that we're working at the HashTable level here,
343
// and not at the Properties level! This is important
344
// because we don't want to modify the default properties.
345
// NB: If fixupPropertyString ends up changing the property
346
// name or value, we need to remove the old key and re-add
347
// with the new key and value. However, then our Enumeration
348
// could lose its place in the HashTable. So, we first
349
// clone the HashTable and enumerate over that since the
350
// clone will not change. When we migrate to Collections,
351
// this code should be revisited and cleaned up to use
352
// an Iterator which may (or may not) alleviate the need for
353
// the clone. Many thanks to Padraig O'hIceadha
354
// <padraig@gradient.ie> for finding this problem. Bugzilla 2000.
355

356         Enumeration JavaDoc keys = ((Properties JavaDoc) props.clone()).keys();
357         while (keys.hasMoreElements())
358         {
359             String JavaDoc key = (String JavaDoc) keys.nextElement();
360             // Now check if the given key was specified as a
361
// System property. If so, the system property
362
// overides the default value in the propery file.
363
String JavaDoc value = null;
364             try
365             {
366                 value = System.getProperty(key);
367             }
368             catch (SecurityException JavaDoc se)
369             {
370                 // No-op for sandbox/applet case, leave null -sc
371
}
372             if (value == null)
373                 value = (String JavaDoc) props.get(key);
374
375             String JavaDoc newKey = fixupPropertyString(key, true);
376             String JavaDoc newValue = null;
377             try
378             {
379                 newValue = System.getProperty(newKey);
380             }
381             catch (SecurityException JavaDoc se)
382             {
383                 // No-op for sandbox/applet case, leave null -sc
384
}
385             if (newValue == null)
386                 newValue = fixupPropertyString(value, false);
387             else
388                 newValue = fixupPropertyString(newValue, false);
389
390             if (key != newKey || value != newValue)
391             {
392                 props.remove(key);
393                 props.put(newKey, newValue);
394             }
395
396         }
397
398         return props;
399     }
400
401     /**
402      * Fix up a string in an output properties file according to
403      * the rules of {@link #loadPropertiesFile}.
404      *
405      * @param s non-null reference to string that may need to be fixed up.
406      * @return A new string if fixup occured, otherwise the s argument.
407      */

408     static private String JavaDoc fixupPropertyString(String JavaDoc s, boolean doClipping)
409     {
410         int index;
411         if (doClipping && s.startsWith(S_XSLT_PREFIX))
412         {
413             s = s.substring(S_XSLT_PREFIX_LEN);
414         }
415         if (s.startsWith(S_XALAN_PREFIX))
416         {
417             s =
418                 S_BUILTIN_EXTENSIONS_UNIVERSAL
419                     + s.substring(S_XALAN_PREFIX_LEN);
420         }
421         if ((index = s.indexOf("\\u003a")) > 0)
422         {
423             String JavaDoc temp = s.substring(index + 6);
424             s = s.substring(0, index) + ":" + temp;
425
426         }
427         return s;
428     }
429
430 }
431
Popular Tags