001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: LSSerializerImpl.java 1225426 2011-12-29 04:13:08Z mrglavas $
020 */
021
022 package org.apache.xml.serializer.dom3;
023
024 import java.io.FileOutputStream;
025 import java.io.OutputStream;
026 import java.io.StringWriter;
027 import java.io.UnsupportedEncodingException;
028 import java.io.Writer;
029 import java.net.HttpURLConnection;
030 import java.net.URL;
031 import java.net.URLConnection;
032 import java.security.AccessController;
033 import java.security.PrivilegedAction;
034 import java.util.Properties;
035 import java.util.StringTokenizer;
036
037 import org.apache.xml.serializer.DOM3Serializer;
038 import org.apache.xml.serializer.Encodings;
039 import org.apache.xml.serializer.OutputPropertiesFactory;
040 import org.apache.xml.serializer.Serializer;
041 import org.apache.xml.serializer.SerializerFactory;
042 import org.apache.xml.serializer.utils.MsgKey;
043 import org.apache.xml.serializer.utils.SystemIDResolver;
044 import org.apache.xml.serializer.utils.Utils;
045 import org.w3c.dom.DOMConfiguration;
046 import org.w3c.dom.DOMError;
047 import org.w3c.dom.DOMErrorHandler;
048 import org.w3c.dom.DOMException;
049 import org.w3c.dom.DOMStringList;
050 import org.w3c.dom.Document;
051 import org.w3c.dom.Node;
052 import org.w3c.dom.ls.LSException;
053 import org.w3c.dom.ls.LSOutput;
054 import org.w3c.dom.ls.LSSerializer;
055 import org.w3c.dom.ls.LSSerializerFilter;
056
057 /**
058 * Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer and
059 * org.w3c.dom.ls.DOMConfiguration. Serialization is achieved by delegating
060 * serialization calls to <CODE>org.apache.xml.serializer.ToStream</CODE> or
061 * one of its derived classes depending on the serialization method, while walking
062 * the DOM in DOM3TreeWalker.
063 * @see <a href="http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html#LS-LSSerializer">org.w3c.dom.ls.LSSerializer</a>
064 * @see <a href="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMConfiguration">org.w3c.dom.DOMConfiguration</a>
065 *
066 * @version $Id:
067 *
068 * @xsl.usage internal
069 */
070 final public class LSSerializerImpl implements DOMConfiguration, LSSerializer {
071
072 // The default end-of-line character sequence used in serialization.
073 private static final String DEFAULT_END_OF_LINE;
074 static {
075 String lineSeparator = (String) AccessController.doPrivileged(new PrivilegedAction() {
076 public Object run() {
077 try {
078 return System.getProperty("line.separator");
079 }
080 catch (SecurityException ex) {}
081 return null;
082 }
083 });
084 // The DOM Level 3 Load and Save specification requires that implementations choose a default
085 // sequence which matches one allowed by XML 1.0 (or XML 1.1). If the value of "line.separator"
086 // isn't one of the XML 1.0 end-of-line sequences then we select "\n" as the default value.
087 DEFAULT_END_OF_LINE = lineSeparator != null &&
088 (lineSeparator.equals("\r\n") || lineSeparator.equals("\r")) ? lineSeparator : "\n";
089 }
090
091 /** private data members */
092 private Serializer fXMLSerializer = null;
093
094 // Tracks DOMConfiguration features.
095 protected int fFeatures = 0;
096
097 // Common DOM serializer
098 private DOM3Serializer fDOMSerializer = null;
099
100 // A filter set on the LSSerializer
101 private LSSerializerFilter fSerializerFilter = null;
102
103 // Stores the nodeArg parameter to speed up multiple writes of the same node.
104 private Node fVisitedNode = null;
105
106 // The end-of-line character sequence used in serialization. "\n" is whats used on the web.
107 private String fEndOfLine = DEFAULT_END_OF_LINE;
108
109 // The DOMErrorhandler.
110 private DOMErrorHandler fDOMErrorHandler = null;
111
112 // The Configuration parameter to pass to the Underlying serilaizer.
113 private Properties fDOMConfigProperties = null;
114
115 // The encoding to use during serialization.
116 private String fEncoding;
117
118 // ************************************************************************
119 // DOM Level 3 DOM Configuration parameter names
120 // ************************************************************************
121 // Parameter canonical-form, true [optional] - NOT SUPPORTED
122 private final static int CANONICAL = 0x1 << 0;
123
124 // Parameter cdata-sections, true [required] (default)
125 private final static int CDATA = 0x1 << 1;
126
127 // Parameter check-character-normalization, true [optional] - NOT SUPPORTED
128 private final static int CHARNORMALIZE = 0x1 << 2;
129
130 // Parameter comments, true [required] (default)
131 private final static int COMMENTS = 0x1 << 3;
132
133 // Parameter datatype-normalization, true [optional] - NOT SUPPORTED
134 private final static int DTNORMALIZE = 0x1 << 4;
135
136 // Parameter element-content-whitespace, true [required] (default) - value - false [optional] NOT SUPPORTED
137 private final static int ELEM_CONTENT_WHITESPACE = 0x1 << 5;
138
139 // Parameter entities, true [required] (default)
140 private final static int ENTITIES = 0x1 << 6;
141
142 // Parameter infoset, true [required] (default), false has no effect --> True has no effect for the serializer
143 private final static int INFOSET = 0x1 << 7;
144
145 // Parameter namespaces, true [required] (default)
146 private final static int NAMESPACES = 0x1 << 8;
147
148 // Parameter namespace-declarations, true [required] (default)
149 private final static int NAMESPACEDECLS = 0x1 << 9;
150
151 // Parameter normalize-characters, true [optional] - NOT SUPPORTED
152 private final static int NORMALIZECHARS = 0x1 << 10;
153
154 // Parameter split-cdata-sections, true [required] (default)
155 private final static int SPLITCDATA = 0x1 << 11;
156
157 // Parameter validate, true [optional] - NOT SUPPORTED
158 private final static int VALIDATE = 0x1 << 12;
159
160 // Parameter validate-if-schema, true [optional] - NOT SUPPORTED
161 private final static int SCHEMAVALIDATE = 0x1 << 13;
162
163 // Parameter split-cdata-sections, true [required] (default)
164 private final static int WELLFORMED = 0x1 << 14;
165
166 // Parameter discard-default-content, true [required] (default)
167 // Not sure how this will be used in level 2 Documents
168 private final static int DISCARDDEFAULT = 0x1 << 15;
169
170 // Parameter format-pretty-print, true [optional]
171 private final static int PRETTY_PRINT = 0x1 << 16;
172
173 // Parameter ignore-unknown-character-denormalizations, true [required] (default)
174 // We currently do not support XML 1.1 character normalization
175 private final static int IGNORE_CHAR_DENORMALIZE = 0x1 << 17;
176
177 // Parameter discard-default-content, true [required] (default)
178 private final static int XMLDECL = 0x1 << 18;
179 // ************************************************************************
180
181 // Recognized parameters for which atleast one value can be set
182 private String fRecognizedParameters [] = {
183 DOMConstants.DOM_CANONICAL_FORM,
184 DOMConstants.DOM_CDATA_SECTIONS,
185 DOMConstants.DOM_CHECK_CHAR_NORMALIZATION,
186 DOMConstants.DOM_COMMENTS,
187 DOMConstants.DOM_DATATYPE_NORMALIZATION,
188 DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
189 DOMConstants.DOM_ENTITIES,
190 DOMConstants.DOM_INFOSET,
191 DOMConstants.DOM_NAMESPACES,
192 DOMConstants.DOM_NAMESPACE_DECLARATIONS,
193 //DOMConstants.DOM_NORMALIZE_CHARACTERS,
194 DOMConstants.DOM_SPLIT_CDATA,
195 DOMConstants.DOM_VALIDATE,
196 DOMConstants.DOM_VALIDATE_IF_SCHEMA,
197 DOMConstants.DOM_WELLFORMED,
198 DOMConstants.DOM_DISCARD_DEFAULT_CONTENT,
199 DOMConstants.DOM_FORMAT_PRETTY_PRINT,
200 DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS,
201 DOMConstants.DOM_XMLDECL,
202 DOMConstants.DOM_ERROR_HANDLER
203 };
204
205
206 /**
207 * Constructor: Creates a LSSerializerImpl object. The underlying
208 * XML 1.0 or XML 1.1 org.apache.xml.serializer.Serializer object is
209 * created and initialized the first time any of the write methods are
210 * invoked to serialize the Node. Subsequent write methods on the same
211 * LSSerializerImpl object will use the previously created Serializer object.
212 */
213 public LSSerializerImpl () {
214 // set default parameters
215 fFeatures |= CDATA;
216 fFeatures |= COMMENTS;
217 fFeatures |= ELEM_CONTENT_WHITESPACE;
218 fFeatures |= ENTITIES;
219 fFeatures |= NAMESPACES;
220 fFeatures |= NAMESPACEDECLS;
221 fFeatures |= SPLITCDATA;
222 fFeatures |= WELLFORMED;
223 fFeatures |= DISCARDDEFAULT;
224 fFeatures |= XMLDECL;
225
226 // New OutputFormat properties
227 fDOMConfigProperties = new Properties();
228
229 // Initialize properties to be passed on the underlying serializer
230 initializeSerializerProps();
231
232 // Create the underlying serializer.
233 Properties configProps = OutputPropertiesFactory.getDefaultMethodProperties("xml");
234
235 // change xml version from 1.0 to 1.1
236 //configProps.setProperty("version", "1.1");
237
238 // Get a serializer that seriailizes according the the properties,
239 // which in this case is to xml
240 fXMLSerializer = SerializerFactory.getSerializer(configProps);
241
242 // Initialize Serializer
243 fXMLSerializer.setOutputFormat(fDOMConfigProperties);
244 }
245
246 /**
247 * Initializes the underlying serializer's configuration depending on the
248 * default DOMConfiguration parameters. This method must be called before a
249 * node is to be serialized.
250 *
251 * @xsl.usage internal
252 */
253 public void initializeSerializerProps () {
254 // canonical-form
255 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
256 + DOMConstants.DOM_CANONICAL_FORM, DOMConstants.DOM3_DEFAULT_FALSE);
257
258 // cdata-sections
259 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
260 + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_DEFAULT_TRUE);
261
262 // "check-character-normalization"
263 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
264 + DOMConstants.DOM_CHECK_CHAR_NORMALIZATION,
265 DOMConstants.DOM3_DEFAULT_FALSE);
266
267 // comments
268 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
269 + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_DEFAULT_TRUE);
270
271 // datatype-normalization
272 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
273 + DOMConstants.DOM_DATATYPE_NORMALIZATION,
274 DOMConstants.DOM3_DEFAULT_FALSE);
275
276 // element-content-whitespace
277 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
278 + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
279 DOMConstants.DOM3_DEFAULT_TRUE);
280
281 // entities
282 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
283 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_TRUE);
284 // preserve entities
285 fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS
286 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_TRUE);
287
288 // error-handler
289 // Should we set our default ErrorHandler
290 /*
291 * if (fDOMConfig.getParameter(Constants.DOM_ERROR_HANDLER) != null) {
292 * fDOMErrorHandler =
293 * (DOMErrorHandler)fDOMConfig.getParameter(Constants.DOM_ERROR_HANDLER); }
294 */
295
296 // infoset
297 if ((fFeatures & INFOSET) != 0) {
298 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
299 + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_DEFAULT_TRUE);
300 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
301 + DOMConstants.DOM_NAMESPACE_DECLARATIONS,
302 DOMConstants.DOM3_DEFAULT_TRUE);
303 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
304 + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_DEFAULT_TRUE);
305 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
306 + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
307 DOMConstants.DOM3_DEFAULT_TRUE);
308 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
309 + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_DEFAULT_TRUE);
310 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
311 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_FALSE);
312 // preserve entities
313 fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS
314 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_FALSE);
315 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
316 + DOMConstants.DOM_CDATA_SECTIONS,
317 DOMConstants.DOM3_DEFAULT_FALSE);
318 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
319 + DOMConstants.DOM_VALIDATE_IF_SCHEMA,
320 DOMConstants.DOM3_DEFAULT_FALSE);
321 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
322 + DOMConstants.DOM_DATATYPE_NORMALIZATION,
323 DOMConstants.DOM3_DEFAULT_FALSE);
324 }
325
326 // namespaces
327 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
328 + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_DEFAULT_TRUE);
329
330 // namespace-declarations
331 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
332 + DOMConstants.DOM_NAMESPACE_DECLARATIONS,
333 DOMConstants.DOM3_DEFAULT_TRUE);
334
335 // normalize-characters
336 /*
337 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
338 + DOMConstants.DOM_NORMALIZE_CHARACTERS,
339 DOMConstants.DOM3_DEFAULT_FALSE);
340 */
341
342 // split-cdata-sections
343 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
344 + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_DEFAULT_TRUE);
345
346 // validate
347 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
348 + DOMConstants.DOM_VALIDATE, DOMConstants.DOM3_DEFAULT_FALSE);
349
350 // validate-if-schema
351 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
352 + DOMConstants.DOM_VALIDATE_IF_SCHEMA,
353 DOMConstants.DOM3_DEFAULT_FALSE);
354
355 // well-formed
356 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
357 + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_DEFAULT_TRUE);
358
359 // pretty-print
360 fDOMConfigProperties.setProperty(
361 DOMConstants.S_XSL_OUTPUT_INDENT,
362 DOMConstants.DOM3_DEFAULT_TRUE);
363 fDOMConfigProperties.setProperty(
364 OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, Integer.toString(3));
365
366 //
367
368 // discard-default-content
369 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
370 + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT,
371 DOMConstants.DOM3_DEFAULT_TRUE);
372
373 // xml-declaration
374 fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "no");
375
376 }
377
378 // ************************************************************************
379 // DOMConfiguraiton implementation
380 // ************************************************************************
381
382 /**
383 * Checks if setting a parameter to a specific value is supported.
384 *
385 * @see org.w3c.dom.DOMConfiguration#canSetParameter(java.lang.String, java.lang.Object)
386 * @since DOM Level 3
387 * @param name A String containing the DOMConfiguration parameter name.
388 * @param value An Object specifying the value of the corresponding parameter.
389 */
390 public boolean canSetParameter(String name, Object value) {
391 if (value instanceof Boolean){
392 if ( name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)
393 || name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)
394 || name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)
395 || name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)
396 || name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)
397 || name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)
398 || name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)
399 || name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)
400 || name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)
401 || name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)
402 || name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)
403 || name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)){
404 // both values supported
405 return true;
406 }
407 else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
408 || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
409 || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
410 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)
411 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
412 // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
413 ) {
414 // true is not supported
415 return !((Boolean)value).booleanValue();
416 }
417 else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
418 // false is not supported
419 return ((Boolean)value).booleanValue();
420 }
421 }
422 else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER) &&
423 value == null || value instanceof DOMErrorHandler){
424 return true;
425 }
426 return false;
427 }
428 /**
429 * This method returns the value of a parameter if known.
430 *
431 * @see org.w3c.dom.DOMConfiguration#getParameter(java.lang.String)
432 *
433 * @param name A String containing the DOMConfiguration parameter name
434 * whose value is to be returned.
435 * @return Object The value of the parameter if known.
436 */
437 public Object getParameter(String name) throws DOMException {
438 if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)) {
439 return ((fFeatures & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE;
440 } else if (name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)) {
441 return ((fFeatures & CDATA) != 0) ? Boolean.TRUE : Boolean.FALSE;
442 } else if (name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)) {
443 return ((fFeatures & ENTITIES) != 0) ? Boolean.TRUE : Boolean.FALSE;
444 } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)) {
445 return ((fFeatures & NAMESPACES) != 0) ? Boolean.TRUE : Boolean.FALSE;
446 } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)) {
447 return ((fFeatures & NAMESPACEDECLS) != 0) ? Boolean.TRUE : Boolean.FALSE;
448 } else if (name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)) {
449 return ((fFeatures & SPLITCDATA) != 0) ? Boolean.TRUE : Boolean.FALSE;
450 } else if (name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)) {
451 return ((fFeatures & WELLFORMED) != 0) ? Boolean.TRUE : Boolean.FALSE;
452 } else if (name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)) {
453 return ((fFeatures & DISCARDDEFAULT) != 0) ? Boolean.TRUE : Boolean.FALSE;
454 } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
455 return ((fFeatures & PRETTY_PRINT) != 0) ? Boolean.TRUE : Boolean.FALSE;
456 } else if (name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)) {
457 return ((fFeatures & XMLDECL) != 0) ? Boolean.TRUE : Boolean.FALSE;
458 } else if (name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
459 return ((fFeatures & ELEM_CONTENT_WHITESPACE) != 0) ? Boolean.TRUE : Boolean.FALSE;
460 } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
461 return ((fFeatures & PRETTY_PRINT) != 0) ? Boolean.TRUE : Boolean.FALSE;
462 } else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
463 return Boolean.TRUE;
464 } else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
465 || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
466 || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
467 // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
468 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
469 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
470 return Boolean.FALSE;
471 } else if (name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)){
472 if ((fFeatures & ENTITIES) == 0 &&
473 (fFeatures & CDATA) == 0 &&
474 (fFeatures & ELEM_CONTENT_WHITESPACE) != 0 &&
475 (fFeatures & NAMESPACES) != 0 &&
476 (fFeatures & NAMESPACEDECLS) != 0 &&
477 (fFeatures & WELLFORMED) != 0 &&
478 (fFeatures & COMMENTS) != 0) {
479 return Boolean.TRUE;
480 }
481 return Boolean.FALSE;
482 } else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER)) {
483 return fDOMErrorHandler;
484 } else if (
485 name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION)
486 || name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)) {
487 return null;
488 } else {
489 // Here we have to add the Xalan specific DOM Message Formatter
490 String msg = Utils.messages.createMessage(
491 MsgKey.ER_FEATURE_NOT_FOUND,
492 new Object[] { name });
493 throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
494 }
495 }
496
497 /**
498 * This method returns a of the parameters supported by this DOMConfiguration object
499 * and for which at least one value can be set by the application
500 *
501 * @see org.w3c.dom.DOMConfiguration#getParameterNames()
502 *
503 * @return DOMStringList A list of DOMConfiguration parameters recognized
504 * by the serializer
505 */
506 public DOMStringList getParameterNames() {
507 return new DOMStringListImpl(fRecognizedParameters);
508 }
509
510 /**
511 * This method sets the value of the named parameter.
512 *
513 * @see org.w3c.dom.DOMConfiguration#setParameter(java.lang.String, java.lang.Object)
514 *
515 * @param name A String containing the DOMConfiguration parameter name.
516 * @param value An Object contaiing the parameters value to set.
517 */
518 public void setParameter(String name, Object value) throws DOMException {
519 // If the value is a boolean
520 if (value instanceof Boolean) {
521 boolean state = ((Boolean) value).booleanValue();
522
523 if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)) {
524 fFeatures = state ? fFeatures | COMMENTS : fFeatures
525 & ~COMMENTS;
526 // comments
527 if (state) {
528 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
529 + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_TRUE);
530 } else {
531 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
532 + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_FALSE);
533 }
534 } else if (name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)) {
535 fFeatures = state ? fFeatures | CDATA : fFeatures
536 & ~CDATA;
537 // cdata-sections
538 if (state) {
539 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
540 + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
541 } else {
542 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
543 + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
544 }
545 } else if (name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)) {
546 fFeatures = state ? fFeatures | ENTITIES : fFeatures
547 & ~ENTITIES;
548 // entities
549 if (state) {
550 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
551 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_TRUE);
552 fDOMConfigProperties.setProperty(
553 DOMConstants.S_XERCES_PROPERTIES_NS
554 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_TRUE);
555 } else {
556 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
557 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
558 fDOMConfigProperties.setProperty(
559 DOMConstants.S_XERCES_PROPERTIES_NS
560 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
561 }
562 } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)) {
563 fFeatures = state ? fFeatures | NAMESPACES : fFeatures
564 & ~NAMESPACES;
565 // namespaces
566 if (state) {
567 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
568 + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_TRUE);
569 } else {
570 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
571 + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_FALSE);
572 }
573 } else if (name
574 .equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)) {
575 fFeatures = state ? fFeatures | NAMESPACEDECLS
576 : fFeatures & ~NAMESPACEDECLS;
577 // namespace-declarations
578 if (state) {
579 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
580 + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
581 } else {
582 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
583 + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
584 }
585 } else if (name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)) {
586 fFeatures = state ? fFeatures | SPLITCDATA : fFeatures
587 & ~SPLITCDATA;
588 // split-cdata-sections
589 if (state) {
590 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
591 + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_EXPLICIT_TRUE);
592 } else {
593 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
594 + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_EXPLICIT_FALSE);
595 }
596 } else if (name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)) {
597 fFeatures = state ? fFeatures | WELLFORMED : fFeatures
598 & ~WELLFORMED;
599 // well-formed
600 if (state) {
601 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
602 + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_TRUE);
603 } else {
604 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
605 + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_FALSE);
606 }
607 } else if (name
608 .equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)) {
609 fFeatures = state ? fFeatures | DISCARDDEFAULT
610 : fFeatures & ~DISCARDDEFAULT;
611 // discard-default-content
612 if (state) {
613 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
614 + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT, DOMConstants.DOM3_EXPLICIT_TRUE);
615 } else {
616 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
617 + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT, DOMConstants.DOM3_EXPLICIT_FALSE);
618 }
619 } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
620 fFeatures = state ? fFeatures | PRETTY_PRINT : fFeatures
621 & ~PRETTY_PRINT;
622 // format-pretty-print
623 if (state) {
624 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
625 + DOMConstants.DOM_FORMAT_PRETTY_PRINT, DOMConstants.DOM3_EXPLICIT_TRUE);
626 }
627 else {
628 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
629 + DOMConstants.DOM_FORMAT_PRETTY_PRINT, DOMConstants.DOM3_EXPLICIT_FALSE);
630 }
631 } else if (name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)) {
632 fFeatures = state ? fFeatures | XMLDECL : fFeatures
633 & ~XMLDECL;
634 if (state) {
635 fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "no");
636 } else {
637 fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "yes");
638 }
639 } else if (name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
640 fFeatures = state ? fFeatures | ELEM_CONTENT_WHITESPACE : fFeatures
641 & ~ELEM_CONTENT_WHITESPACE;
642 // element-content-whitespace
643 if (state) {
644 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
645 + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_TRUE);
646 } else {
647 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
648 + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_FALSE);
649 }
650 } else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
651 // false is not supported
652 if (!state) {
653 // Here we have to add the Xalan specific DOM Message Formatter
654 String msg = Utils.messages.createMessage(
655 MsgKey.ER_FEATURE_NOT_SUPPORTED,
656 new Object[] { name });
657 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
658 } else {
659 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
660 + DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
661 }
662 } else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
663 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)
664 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
665 || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
666 || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
667 // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
668 ) {
669 // true is not supported
670 if (state) {
671 String msg = Utils.messages.createMessage(
672 MsgKey.ER_FEATURE_NOT_SUPPORTED,
673 new Object[] { name });
674 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
675 } else {
676 if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)) {
677 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
678 + DOMConstants.DOM_CANONICAL_FORM, DOMConstants.DOM3_EXPLICIT_FALSE);
679 } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
680 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
681 + DOMConstants.DOM_VALIDATE_IF_SCHEMA, DOMConstants.DOM3_EXPLICIT_FALSE);
682 } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)) {
683 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
684 + DOMConstants.DOM_VALIDATE, DOMConstants.DOM3_EXPLICIT_FALSE);
685 } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
686 fDOMConfigProperties.setProperty(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION
687 + DOMConstants.DOM_CHECK_CHAR_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
688 } else if (name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)) {
689 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
690 + DOMConstants.DOM_DATATYPE_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
691 } /* else if (name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)) {
692 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
693 + DOMConstants.DOM_NORMALIZE_CHARACTERS, DOMConstants.DOM3_EXPLICIT_FALSE);
694 } */
695 }
696 } else if (name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)) {
697 // infoset
698 if (state) {
699 fFeatures &= ~ENTITIES;
700 fFeatures &= ~CDATA;
701 fFeatures &= ~SCHEMAVALIDATE;
702 fFeatures &= ~DTNORMALIZE;
703 fFeatures |= NAMESPACES;
704 fFeatures |= NAMESPACEDECLS;
705 fFeatures |= WELLFORMED;
706 fFeatures |= ELEM_CONTENT_WHITESPACE;
707 fFeatures |= COMMENTS;
708
709 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
710 + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_TRUE);
711 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
712 + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
713 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
714 + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_TRUE);
715 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
716 + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_TRUE);
717 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
718 + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_TRUE);
719
720 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
721 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
722 fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS
723 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
724
725 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
726 + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
727 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
728 + DOMConstants.DOM_VALIDATE_IF_SCHEMA, DOMConstants.DOM3_EXPLICIT_FALSE);
729 fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
730 + DOMConstants.DOM_DATATYPE_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
731 }
732 } else {
733 // If this is a non-boolean parameter a type mismatch should be thrown.
734 if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER) ||
735 name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION) ||
736 name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)) {
737 String msg = Utils.messages.createMessage(
738 MsgKey.ER_TYPE_MISMATCH_ERR,
739 new Object[] { name });
740 throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
741 }
742
743 // Parameter is not recognized
744 String msg = Utils.messages.createMessage(
745 MsgKey.ER_FEATURE_NOT_FOUND,
746 new Object[] { name });
747 throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
748 }
749 } // If the parameter value is not a boolean
750 else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER)) {
751 if (value == null || value instanceof DOMErrorHandler) {
752 fDOMErrorHandler = (DOMErrorHandler)value;
753 } else {
754 String msg = Utils.messages.createMessage(
755 MsgKey.ER_TYPE_MISMATCH_ERR,
756 new Object[] { name });
757 throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
758 }
759 } else if (
760 name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION)
761 || name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)) {
762 if (value != null) {
763 if (!(value instanceof String)) {
764 String msg = Utils.messages.createMessage(
765 MsgKey.ER_TYPE_MISMATCH_ERR,
766 new Object[] { name });
767 throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
768 }
769 String msg = Utils.messages.createMessage(
770 MsgKey.ER_FEATURE_NOT_SUPPORTED,
771 new Object[] { name });
772 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
773 }
774 } else {
775 // If this is a boolean parameter a type mismatch should be thrown.
776 if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS) ||
777 name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS) ||
778 name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES) ||
779 name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES) ||
780 name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS) ||
781 name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA) ||
782 name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED) ||
783 name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT) ||
784 name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT) ||
785 name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL) ||
786 name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE) ||
787 name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS) ||
788 name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM) ||
789 name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA) ||
790 name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE) ||
791 name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION) ||
792 name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION) ||
793 name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)) {
794 String msg = Utils.messages.createMessage(
795 MsgKey.ER_TYPE_MISMATCH_ERR,
796 new Object[] { name });
797 throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
798 }
799
800 // Parameter is not recognized
801 String msg = Utils.messages.createMessage(
802 MsgKey.ER_FEATURE_NOT_FOUND,
803 new Object[] { name });
804 throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
805 }
806 }
807 // ************************************************************************
808
809
810 // ************************************************************************
811 // DOMConfiguraiton implementation
812 // ************************************************************************
813
814 /**
815 * Returns the DOMConfiguration of the LSSerializer.
816 *
817 * @see org.w3c.dom.ls.LSSerializer#getDomConfig()
818 * @since DOM Level 3
819 * @return A DOMConfiguration object.
820 */
821 public DOMConfiguration getDomConfig() {
822 return (DOMConfiguration)this;
823 }
824
825 /**
826 * Returns the DOMConfiguration of the LSSerializer.
827 *
828 * @see org.w3c.dom.ls.LSSerializer#getFilter()
829 * @since DOM Level 3
830 * @return A LSSerializerFilter object.
831 */
832 public LSSerializerFilter getFilter() {
833 return fSerializerFilter;
834 }
835
836 /**
837 * Returns the End-Of-Line sequence of characters to be used in the XML
838 * being serialized. If none is set a default "\n" is returned.
839 *
840 * @see org.w3c.dom.ls.LSSerializer#getNewLine()
841 * @since DOM Level 3
842 * @return A String containing the end-of-line character sequence used in
843 * serialization.
844 */
845 public String getNewLine() {
846 return fEndOfLine;
847 }
848
849 /**
850 * Set a LSSerilizerFilter on the LSSerializer. When set, the filter is
851 * called before each node is serialized which depending on its implemention
852 * determines if the node is to be serialized or not.
853 *
854 * @see org.w3c.dom.ls.LSSerializer#setFilter
855 * @since DOM Level 3
856 * @param filter A LSSerializerFilter to be applied to the stream to serialize.
857 */
858 public void setFilter(LSSerializerFilter filter) {
859 fSerializerFilter = filter;
860 }
861
862 /**
863 * Sets the End-Of-Line sequence of characters to be used in the XML
864 * being serialized. Setting this attribute to null will reset its
865 * value to the default value i.e. "\n".
866 *
867 * @see org.w3c.dom.ls.LSSerializer#setNewLine
868 * @since DOM Level 3
869 * @param newLine a String that is the end-of-line character sequence to be used in
870 * serialization.
871 */
872 public void setNewLine(String newLine) {
873 fEndOfLine = (newLine != null) ? newLine : DEFAULT_END_OF_LINE;
874 }
875
876 /**
877 * Serializes the specified node to the specified LSOutput and returns true if the Node
878 * was successfully serialized.
879 *
880 * @see org.w3c.dom.ls.LSSerializer#write(org.w3c.dom.Node, org.w3c.dom.ls.LSOutput)
881 * @since DOM Level 3
882 * @param nodeArg The Node to serialize.
883 * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
884 * LSSerializer was unable to serialize the node.
885 *
886 */
887 public boolean write(Node nodeArg, LSOutput destination) throws LSException {
888 // If the destination is null
889 if (destination == null) {
890 String msg = Utils.messages
891 .createMessage(
892 MsgKey.ER_NO_OUTPUT_SPECIFIED,
893 null);
894 if (fDOMErrorHandler != null) {
895 fDOMErrorHandler.handleError(new DOMErrorImpl(
896 DOMError.SEVERITY_FATAL_ERROR, msg,
897 MsgKey.ER_NO_OUTPUT_SPECIFIED));
898 }
899 throw new LSException(LSException.SERIALIZE_ERR, msg);
900 }
901
902 // If nodeArg is null, return false. Should we throw and LSException instead?
903 if (nodeArg == null ) {
904 return false;
905 }
906
907 // Obtain a reference to the serializer to use
908 // Serializer serializer = getXMLSerializer(xmlVersion);
909 Serializer serializer = fXMLSerializer;
910 serializer.reset();
911
912 // If the node has not been seen
913 if ( nodeArg != fVisitedNode) {
914 // Determine the XML Document version of the Node
915 String xmlVersion = getXMLVersion(nodeArg);
916
917 // Determine the encoding: 1.LSOutput.encoding, 2.Document.inputEncoding, 3.Document.xmlEncoding.
918 fEncoding = destination.getEncoding();
919 if (fEncoding == null ) {
920 fEncoding = getInputEncoding(nodeArg);
921 fEncoding = fEncoding != null ? fEncoding : getXMLEncoding(nodeArg) == null? "UTF-8": getXMLEncoding(nodeArg);
922 }
923
924 // If the encoding is not recognized throw an exception.
925 // Note: The serializer defaults to UTF-8 when created
926 if (!Encodings.isRecognizedEncoding(fEncoding)) {
927 String msg = Utils.messages
928 .createMessage(
929 MsgKey.ER_UNSUPPORTED_ENCODING,
930 null);
931 if (fDOMErrorHandler != null) {
932 fDOMErrorHandler.handleError(new DOMErrorImpl(
933 DOMError.SEVERITY_FATAL_ERROR, msg,
934 MsgKey.ER_UNSUPPORTED_ENCODING));
935 }
936 throw new LSException(LSException.SERIALIZE_ERR, msg);
937 }
938
939 serializer.getOutputFormat().setProperty("version", xmlVersion);
940
941 // Set the output encoding and xml version properties
942 fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
943 fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, fEncoding);
944
945 // If the node to be serialized is not a Document, Element, or Entity
946 // node
947 // then the XML declaration, or text declaration, should be never be
948 // serialized.
949 if ( (nodeArg.getNodeType() != Node.DOCUMENT_NODE
950 || nodeArg.getNodeType() != Node.ELEMENT_NODE
951 || nodeArg.getNodeType() != Node.ENTITY_NODE)
952 && ((fFeatures & XMLDECL) != 0)) {
953 fDOMConfigProperties.setProperty(
954 DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
955 DOMConstants.DOM3_DEFAULT_FALSE);
956 }
957
958 fVisitedNode = nodeArg;
959 }
960
961 // Update the serializer properties
962 fXMLSerializer.setOutputFormat(fDOMConfigProperties);
963
964 //
965 try {
966
967 // The LSSerializer will use the LSOutput object to determine
968 // where to serialize the output to in the following order the
969 // first one that is not null and not an empty string will be
970 // used: 1.LSOutput.characterStream, 2.LSOutput.byteStream,
971 // 3. LSOutput.systemId
972 // 1.LSOutput.characterStream
973 Writer writer = destination.getCharacterStream();
974 if (writer == null ) {
975
976 // 2.LSOutput.byteStream
977 OutputStream outputStream = destination.getByteStream();
978 if ( outputStream == null) {
979
980 // 3. LSOutput.systemId
981 String uri = destination.getSystemId();
982 if (uri == null) {
983 String msg = Utils.messages
984 .createMessage(
985 MsgKey.ER_NO_OUTPUT_SPECIFIED,
986 null);
987 if (fDOMErrorHandler != null) {
988 fDOMErrorHandler.handleError(new DOMErrorImpl(
989 DOMError.SEVERITY_FATAL_ERROR, msg,
990 MsgKey.ER_NO_OUTPUT_SPECIFIED));
991 }
992 throw new LSException(LSException.SERIALIZE_ERR, msg);
993
994 } else {
995 // Expand the System Id and obtain an absolute URI for it.
996 String absoluteURI = SystemIDResolver.getAbsoluteURI(uri);
997
998 URL url = new URL(absoluteURI);
999 OutputStream urlOutStream = null;
1000 String protocol = url.getProtocol();
1001 String host = url.getHost();
1002
1003 // For file protocols, there is no need to use a URL to get its
1004 // corresponding OutputStream
1005
1006 // Scheme names consist of a sequence of characters. The lower case
1007 // letters "a"--"z", digits, and the characters plus ("+"), period
1008 // ("."), and hyphen ("-") are allowed. For resiliency, programs
1009 // interpreting URLs should treat upper case letters as equivalent to
1010 // lower case in scheme names (e.g., allow "HTTP" as well as "http").
1011 if (protocol.equalsIgnoreCase("file")
1012 && (host == null || host.length() == 0 || host.equals("localhost"))) {
1013 // do we also need to check for host.equals(hostname)
1014 urlOutStream = new FileOutputStream(getPathWithoutEscapes(url.getPath()));
1015
1016 } else {
1017 // This should support URL's whose schemes are mentioned in
1018 // RFC1738 other than file
1019
1020 URLConnection urlCon = url.openConnection();
1021 urlCon.setDoInput(false);
1022 urlCon.setDoOutput(true);
1023 urlCon.setUseCaches(false);
1024 urlCon.setAllowUserInteraction(false);
1025
1026 // When writing to a HTTP URI, a HTTP PUT is performed.
1027 if (urlCon instanceof HttpURLConnection) {
1028 HttpURLConnection httpCon = (HttpURLConnection) urlCon;
1029 httpCon.setRequestMethod("PUT");
1030 }
1031 urlOutStream = urlCon.getOutputStream();
1032 }
1033 // set the OutputStream to that obtained from the systemId
1034 serializer.setOutputStream(urlOutStream);
1035 }
1036 } else {
1037 // 2.LSOutput.byteStream
1038 serializer.setOutputStream(outputStream);
1039 }
1040 } else {
1041 // 1.LSOutput.characterStream
1042 serializer.setWriter(writer);
1043 }
1044
1045 // The associated media type by default is set to text/xml on
1046 // org.apache.xml.serializer.SerializerBase.
1047
1048 // Get a reference to the serializer then lets you serilize a DOM
1049 // Use this hack till Xalan support JAXP1.3
1050 if (fDOMSerializer == null) {
1051 fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
1052 }
1053
1054 // Set the error handler on the DOM3Serializer interface implementation
1055 if (fDOMErrorHandler != null) {
1056 fDOMSerializer.setErrorHandler(fDOMErrorHandler);
1057 }
1058
1059 // Set the filter on the DOM3Serializer interface implementation
1060 if (fSerializerFilter != null) {
1061 fDOMSerializer.setNodeFilter(fSerializerFilter);
1062 }
1063
1064 // Set the NewLine character to be used
1065 fDOMSerializer.setNewLine(fEndOfLine.toCharArray());
1066
1067 // Serializer your DOM, where node is an org.w3c.dom.Node
1068 // Assuming that Xalan's serializer can serialize any type of DOM node
1069 fDOMSerializer.serializeDOM3(nodeArg);
1070
1071 } catch( UnsupportedEncodingException ue) {
1072
1073 String msg = Utils.messages
1074 .createMessage(
1075 MsgKey.ER_UNSUPPORTED_ENCODING,
1076 null);
1077 if (fDOMErrorHandler != null) {
1078 fDOMErrorHandler.handleError(new DOMErrorImpl(
1079 DOMError.SEVERITY_FATAL_ERROR, msg,
1080 MsgKey.ER_UNSUPPORTED_ENCODING, ue));
1081 }
1082 throw (LSException) createLSException(LSException.SERIALIZE_ERR, ue).fillInStackTrace();
1083 } catch (LSException lse) {
1084 // Rethrow LSException.
1085 throw lse;
1086 } catch (RuntimeException e) {
1087 throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
1088 } catch (Exception e) {
1089 if (fDOMErrorHandler != null) {
1090 fDOMErrorHandler.handleError(new DOMErrorImpl(
1091 DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
1092 null, e));
1093 }
1094 throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
1095 }
1096 return true;
1097 }
1098
1099 /**
1100 * Serializes the specified node and returns a String with the serialized
1101 * data to the caller.
1102 *
1103 * @see org.w3c.dom.ls.LSSerializer#writeToString(org.w3c.dom.Node)
1104 * @since DOM Level 3
1105 * @param nodeArg The Node to serialize.
1106 * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
1107 * LSSerializer was unable to serialize the node.
1108 *
1109 */
1110 public String writeToString(Node nodeArg) throws DOMException, LSException {
1111 // return null is nodeArg is null. Should an Exception be thrown instead?
1112 if (nodeArg == null) {
1113 return null;
1114 }
1115
1116 // Should we reset the serializer configuration before each write operation?
1117 // Obtain a reference to the serializer to use
1118 Serializer serializer = fXMLSerializer;
1119 serializer.reset();
1120
1121 if (nodeArg != fVisitedNode){
1122 // Determine the XML Document version of the Node
1123 String xmlVersion = getXMLVersion(nodeArg);
1124
1125 serializer.getOutputFormat().setProperty("version", xmlVersion);
1126
1127 // Set the output encoding and xml version properties
1128 fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
1129 fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, "UTF-16");
1130
1131 // If the node to be serialized is not a Document, Element, or Entity
1132 // node
1133 // then the XML declaration, or text declaration, should be never be
1134 // serialized.
1135 if ((nodeArg.getNodeType() != Node.DOCUMENT_NODE
1136 || nodeArg.getNodeType() != Node.ELEMENT_NODE
1137 || nodeArg.getNodeType() != Node.ENTITY_NODE)
1138 && ((fFeatures & XMLDECL) != 0)) {
1139 fDOMConfigProperties.setProperty(
1140 DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
1141 DOMConstants.DOM3_DEFAULT_FALSE);
1142 }
1143
1144 fVisitedNode = nodeArg;
1145 }
1146 // Update the serializer properties
1147 fXMLSerializer.setOutputFormat(fDOMConfigProperties);
1148
1149 // StringWriter to Output to
1150 StringWriter output = new StringWriter();
1151
1152 //
1153 try {
1154
1155 // Set the Serializer's Writer to a StringWriter
1156 serializer.setWriter(output);
1157
1158 // Get a reference to the serializer then lets you serilize a DOM
1159 // Use this hack till Xalan support JAXP1.3
1160 if (fDOMSerializer == null) {
1161 fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
1162 }
1163
1164 // Set the error handler on the DOM3Serializer interface implementation
1165 if (fDOMErrorHandler != null) {
1166 fDOMSerializer.setErrorHandler(fDOMErrorHandler);
1167 }
1168
1169 // Set the filter on the DOM3Serializer interface implementation
1170 if (fSerializerFilter != null) {
1171 fDOMSerializer.setNodeFilter(fSerializerFilter);
1172 }
1173
1174 // Set the NewLine character to be used
1175 fDOMSerializer.setNewLine(fEndOfLine.toCharArray());
1176
1177 // Serializer your DOM, where node is an org.w3c.dom.Node
1178 fDOMSerializer.serializeDOM3(nodeArg);
1179 } catch (LSException lse) {
1180 // Rethrow LSException.
1181 throw lse;
1182 } catch (RuntimeException e) {
1183 throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
1184 } catch (Exception e) {
1185 if (fDOMErrorHandler != null) {
1186 fDOMErrorHandler.handleError(new DOMErrorImpl(
1187 DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
1188 null, e));
1189 }
1190 throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
1191 }
1192
1193 // return the serialized string
1194 return output.toString();
1195 }
1196
1197 /**
1198 * Serializes the specified node to the specified URI and returns true if the Node
1199 * was successfully serialized.
1200 *
1201 * @see org.w3c.dom.ls.LSSerializer#writeToURI(org.w3c.dom.Node, String)
1202 * @since DOM Level 3
1203 * @param nodeArg The Node to serialize.
1204 * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
1205 * LSSerializer was unable to serialize the node.
1206 *
1207 */
1208 public boolean writeToURI(Node nodeArg, String uri) throws LSException {
1209 // If nodeArg is null, return false. Should we throw and LSException instead?
1210 if (nodeArg == null ) {
1211 return false;
1212 }
1213
1214 // Obtain a reference to the serializer to use
1215 Serializer serializer = fXMLSerializer;
1216 serializer.reset();
1217
1218 if (nodeArg != fVisitedNode) {
1219 // Determine the XML Document version of the Node
1220 String xmlVersion = getXMLVersion(nodeArg);
1221
1222 // Determine the encoding: 1.LSOutput.encoding,
1223 // 2.Document.inputEncoding, 3.Document.xmlEncoding.
1224 fEncoding = getInputEncoding(nodeArg);
1225 if (fEncoding == null ) {
1226 fEncoding = fEncoding != null ? fEncoding : getXMLEncoding(nodeArg) == null? "UTF-8": getXMLEncoding(nodeArg);
1227 }
1228
1229 serializer.getOutputFormat().setProperty("version", xmlVersion);
1230
1231 // Set the output encoding and xml version properties
1232 fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
1233 fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, fEncoding);
1234
1235 // If the node to be serialized is not a Document, Element, or Entity
1236 // node
1237 // then the XML declaration, or text declaration, should be never be
1238 // serialized.
1239 if ( (nodeArg.getNodeType() != Node.DOCUMENT_NODE
1240 || nodeArg.getNodeType() != Node.ELEMENT_NODE
1241 || nodeArg.getNodeType() != Node.ENTITY_NODE)
1242 && ((fFeatures & XMLDECL) != 0)) {
1243 fDOMConfigProperties.setProperty(
1244 DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
1245 DOMConstants.DOM3_DEFAULT_FALSE);
1246 }
1247
1248 fVisitedNode = nodeArg;
1249 }
1250
1251 // Update the serializer properties
1252 fXMLSerializer.setOutputFormat(fDOMConfigProperties);
1253
1254 //
1255 try {
1256 // If the specified encoding is not supported an
1257 // "unsupported-encoding" fatal error is raised. ??
1258 if (uri == null) {
1259 String msg = Utils.messages.createMessage(
1260 MsgKey.ER_NO_OUTPUT_SPECIFIED, null);
1261 if (fDOMErrorHandler != null) {
1262 fDOMErrorHandler.handleError(new DOMErrorImpl(
1263 DOMError.SEVERITY_FATAL_ERROR, msg,
1264 MsgKey.ER_NO_OUTPUT_SPECIFIED));
1265 }
1266 throw new LSException(LSException.SERIALIZE_ERR, msg);
1267
1268 } else {
1269 // REVISIT: Can this be used to get an absolute expanded URI
1270 String absoluteURI = SystemIDResolver.getAbsoluteURI(uri);
1271
1272 URL url = new URL(absoluteURI);
1273 OutputStream urlOutStream = null;
1274 String protocol = url.getProtocol();
1275 String host = url.getHost();
1276
1277 // For file protocols, there is no need to use a URL to get its
1278 // corresponding OutputStream
1279
1280 // Scheme names consist of a sequence of characters. The lower
1281 // case letters "a"--"z", digits, and the characters plus ("+"),
1282 // period ("."), and hyphen ("-") are allowed. For resiliency,
1283 // programs interpreting URLs should treat upper case letters as
1284 // equivalent to lower case in scheme names
1285 // (e.g., allow "HTTP" as well as "http").
1286 if (protocol.equalsIgnoreCase("file")
1287 && (host == null || host.length() == 0 || host
1288 .equals("localhost"))) {
1289 // do we also need to check for host.equals(hostname)
1290 urlOutStream = new FileOutputStream(getPathWithoutEscapes(url.getPath()));
1291
1292 } else {
1293 // This should support URL's whose schemes are mentioned in
1294 // RFC1738 other than file
1295
1296 URLConnection urlCon = url.openConnection();
1297 urlCon.setDoInput(false);
1298 urlCon.setDoOutput(true);
1299 urlCon.setUseCaches(false);
1300 urlCon.setAllowUserInteraction(false);
1301
1302 // When writing to a HTTP URI, a HTTP PUT is performed.
1303 if (urlCon instanceof HttpURLConnection) {
1304 HttpURLConnection httpCon = (HttpURLConnection) urlCon;
1305 httpCon.setRequestMethod("PUT");
1306 }
1307 urlOutStream = urlCon.getOutputStream();
1308 }
1309 // set the OutputStream to that obtained from the systemId
1310 serializer.setOutputStream(urlOutStream);
1311 }
1312
1313 // Get a reference to the serializer then lets you serilize a DOM
1314 // Use this hack till Xalan support JAXP1.3
1315 if (fDOMSerializer == null) {
1316 fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
1317 }
1318
1319 // Set the error handler on the DOM3Serializer interface implementation
1320 if (fDOMErrorHandler != null) {
1321 fDOMSerializer.setErrorHandler(fDOMErrorHandler);
1322 }
1323
1324 // Set the filter on the DOM3Serializer interface implementation
1325 if (fSerializerFilter != null) {
1326 fDOMSerializer.setNodeFilter(fSerializerFilter);
1327 }
1328
1329 // Set the NewLine character to be used
1330 fDOMSerializer.setNewLine(fEndOfLine.toCharArray());
1331
1332 // Serializer your DOM, where node is an org.w3c.dom.Node
1333 // Assuming that Xalan's serializer can serialize any type of DOM
1334 // node
1335 fDOMSerializer.serializeDOM3(nodeArg);
1336
1337 } catch (LSException lse) {
1338 // Rethrow LSException.
1339 throw lse;
1340 } catch (RuntimeException e) {
1341 throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
1342 } catch (Exception e) {
1343 if (fDOMErrorHandler != null) {
1344 fDOMErrorHandler.handleError(new DOMErrorImpl(
1345 DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
1346 null, e));
1347 }
1348 throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
1349 }
1350
1351 return true;
1352 }
1353 // ************************************************************************
1354
1355
1356 // ************************************************************************
1357 // Implementaion methods
1358 // ************************************************************************
1359
1360 /**
1361 * Determines the XML Version of the Document Node to serialize. If the Document Node
1362 * is not a DOM Level 3 Node, then the default version returned is 1.0.
1363 *
1364 * @param nodeArg The Node to serialize
1365 * @return A String containing the version pseudo-attribute of the XMLDecl.
1366 * @throws Throwable if the DOM implementation does not implement Document.getXmlVersion()
1367 */
1368 //protected String getXMLVersion(Node nodeArg) throws Throwable {
1369 protected String getXMLVersion(Node nodeArg) {
1370 Document doc = null;
1371
1372 // Determine the XML Version of the document
1373 if (nodeArg != null) {
1374 if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
1375 // The Document node is the Node argument
1376 doc = (Document)nodeArg;
1377 } else {
1378 // The Document node is the Node argument's ownerDocument
1379 doc = nodeArg.getOwnerDocument();
1380 }
1381
1382 // Determine the DOM Version.
1383 if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
1384 return doc.getXmlVersion();
1385 }
1386 }
1387 // The version will be treated as "1.0" which may result in
1388 // an ill-formed document being serialized.
1389 // If nodeArg does not have an ownerDocument, treat this as XML 1.0
1390 return "1.0";
1391 }
1392
1393 /**
1394 * Determines the XML Encoding of the Document Node to serialize. If the Document Node
1395 * is not a DOM Level 3 Node, then the default encoding "UTF-8" is returned.
1396 *
1397 * @param nodeArg The Node to serialize
1398 * @return A String containing the encoding pseudo-attribute of the XMLDecl.
1399 * @throws Throwable if the DOM implementation does not implement Document.getXmlEncoding()
1400 */
1401 protected String getXMLEncoding(Node nodeArg) {
1402 Document doc = null;
1403
1404 // Determine the XML Encoding of the document
1405 if (nodeArg != null) {
1406 if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
1407 // The Document node is the Node argument
1408 doc = (Document)nodeArg;
1409 } else {
1410 // The Document node is the Node argument's ownerDocument
1411 doc = nodeArg.getOwnerDocument();
1412 }
1413
1414 // Determine the XML Version.
1415 if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
1416 return doc.getXmlEncoding();
1417 }
1418 }
1419 // The default encoding is UTF-8 except for the writeToString method
1420 return "UTF-8";
1421 }
1422
1423 /**
1424 * Determines the Input Encoding of the Document Node to serialize. If the Document Node
1425 * is not a DOM Level 3 Node, then null is returned.
1426 *
1427 * @param nodeArg The Node to serialize
1428 * @return A String containing the input encoding.
1429 */
1430 protected String getInputEncoding(Node nodeArg) {
1431 Document doc = null;
1432
1433 // Determine the Input Encoding of the document
1434 if (nodeArg != null) {
1435 if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
1436 // The Document node is the Node argument
1437 doc = (Document)nodeArg;
1438 } else {
1439 // The Document node is the Node argument's ownerDocument
1440 doc = nodeArg.getOwnerDocument();
1441 }
1442
1443 // Determine the DOM Version.
1444 if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
1445 return doc.getInputEncoding();
1446 }
1447 }
1448 // The default encoding returned is null
1449 return null;
1450 }
1451
1452 /**
1453 * This method returns the LSSerializer's error handler.
1454 *
1455 * @return Returns the fDOMErrorHandler.
1456 */
1457 public DOMErrorHandler getErrorHandler() {
1458 return fDOMErrorHandler;
1459 }
1460
1461 /**
1462 * Replaces all escape sequences in the given path with their literal characters.
1463 */
1464 private static String getPathWithoutEscapes(String origPath) {
1465 if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) {
1466 // Locate the escape characters
1467 StringTokenizer tokenizer = new StringTokenizer(origPath, "%");
1468 StringBuffer result = new StringBuffer(origPath.length());
1469 int size = tokenizer.countTokens();
1470 result.append(tokenizer.nextToken());
1471 for(int i = 1; i < size; ++i) {
1472 String token = tokenizer.nextToken();
1473 if (token.length() >= 2 && isHexDigit(token.charAt(0)) &&
1474 isHexDigit(token.charAt(1))) {
1475 // Decode the 2 digit hexadecimal number following % in '%nn'
1476 result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue());
1477 token = token.substring(2);
1478 }
1479 result.append(token);
1480 }
1481 return result.toString();
1482 }
1483 return origPath;
1484 }
1485
1486 /**
1487 * Returns true if the given character is a valid hex character.
1488 */
1489 private static boolean isHexDigit(char c) {
1490 return (c >= '0' && c <= '9' ||
1491 c >= 'a' && c <= 'f' ||
1492 c >= 'A' && c <= 'F');
1493 }
1494
1495 /**
1496 * Creates an LSException. On J2SE 1.4 and above the cause for the exception will be set.
1497 */
1498 private static LSException createLSException(short code, Throwable cause) {
1499 LSException lse = new LSException(code, cause != null ? cause.getMessage() : null);
1500 if (cause != null && ThrowableMethods.fgThrowableMethodsAvailable) {
1501 try {
1502 ThrowableMethods.fgThrowableInitCauseMethod.invoke(lse, new Object [] {cause});
1503 }
1504 // Something went wrong. There's not much we can do about it.
1505 catch (Exception e) {}
1506 }
1507 return lse;
1508 }
1509
1510 /**
1511 * Holder of methods from java.lang.Throwable.
1512 */
1513 static class ThrowableMethods {
1514
1515 // Method: java.lang.Throwable.initCause(java.lang.Throwable)
1516 private static java.lang.reflect.Method fgThrowableInitCauseMethod = null;
1517
1518 // Flag indicating whether or not Throwable methods available.
1519 private static boolean fgThrowableMethodsAvailable = false;
1520
1521 private ThrowableMethods() {}
1522
1523 // Attempt to get methods for java.lang.Throwable on class initialization.
1524 static {
1525 try {
1526 fgThrowableInitCauseMethod = Throwable.class.getMethod("initCause", new Class [] {Throwable.class});
1527 fgThrowableMethodsAvailable = true;
1528 }
1529 // ClassNotFoundException, NoSuchMethodException or SecurityException
1530 // Whatever the case, we cannot use java.lang.Throwable.initCause(java.lang.Throwable).
1531 catch (Exception exc) {
1532 fgThrowableInitCauseMethod = null;
1533 fgThrowableMethodsAvailable = false;
1534 }
1535 }
1536 }
1537 }