FELIX-3867 : Drop support for JDK 1.4 completely
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1437370 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java
index 39dbee7..fb26f9b 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java
@@ -23,12 +23,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
-import java.io.StringWriter;
import java.io.Writer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import java.util.Properties;
import javax.xml.transform.OutputKeys;
@@ -41,37 +36,33 @@
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
-import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
-import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* Utility class for xml/sax handling.
- * It provides support for "older" sax implementations (like the default one shipped with JDK 1.4.2)
- * which have bugs in the namespace handling.
*/
public class IOUtils {
/** The transformer factory. */
private static final SAXTransformerFactory FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
- /** The URI for xml namespaces */
- private static final String XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace";
-
/**
* Parse a file and send the sax events to the content handler.
* @param file
* @param handler
* @throws TransformerException
*/
- public static final void parse(InputStream file, ContentHandler handler)
+ public static final void parse(final InputStream file, final ContentHandler handler)
throws TransformerException {
final Transformer transformer = FACTORY.newTransformer();
transformer.transform( new StreamSource( file ), new SAXResult( handler ) );
}
+ /**
+ * Get a serializer to write XML to a file.
+ */
public static ContentHandler getSerializer(final File file)
throws SAXException {
try {
@@ -85,296 +76,16 @@
format.put(OutputKeys.OMIT_XML_DECLARATION, "no");
format.put(OutputKeys.ENCODING, "UTF-8");
format.put(OutputKeys.INDENT, "yes");
+
transformer.setOutputProperties(format);
transformerHandler.setResult(new StreamResult(writer));
- if ( needsNamespacesAsAttributes(format) ) {
- return new NamespaceAsAttributes(transformerHandler);
- }
-
return transformerHandler;
} catch (final IOException se) {
- throw new SAXException("Unable to detect if namespace support for sax works properly.", se);
+ throw new SAXException("Unable to open file for writing: " + file, se);
} catch (final TransformerException se) {
- throw new SAXException("Unable to detect if namespace support for sax works properly.", se);
- }
- }
-
- /**
- * Checks if the used Trax implementation correctly handles namespaces set using
- * <code>startPrefixMapping()</code>, but wants them also as 'xmlns:' attributes.
- * <p>
- * The check consists in sending SAX events representing a minimal namespaced document
- * with namespaces defined only with calls to <code>startPrefixMapping</code> (no
- * xmlns:xxx attributes) and check if they are present in the resulting text.
- */
- protected static boolean needsNamespacesAsAttributes(Properties format)
- throws TransformerException, SAXException {
- // Serialize a minimal document to check how namespaces are handled.
- final StringWriter writer = new StringWriter();
-
- final String uri = "namespaceuri";
- final String prefix = "nsp";
- final String check = "xmlns:" + prefix + "='" + uri + "'";
-
- final TransformerHandler handler = FACTORY.newTransformerHandler();
-
- handler.getTransformer().setOutputProperties(format);
- handler.setResult(new StreamResult(writer));
-
- // Output a single element
- handler.startDocument();
- handler.startPrefixMapping(prefix, uri);
- handler.startElement(uri, "element", "element", new AttributesImpl());
- handler.endElement(uri, "element", "element");
- handler.endPrefixMapping(prefix);
- handler.endDocument();
-
- final String text = writer.toString();
-
- // Check if the namespace is there (replace " by ' to be sure of what we search in)
- boolean needsIt = (text.replace('"', '\'').indexOf(check) == -1);
-
- return needsIt;
- }
-
- /**
- * A pipe that ensures that all namespace prefixes are also present as
- * 'xmlns:' attributes. This used to circumvent Xalan's serialization behaviour
- * which is to ignore namespaces if they're not present as 'xmlns:xxx' attributes.
- */
- public static class NamespaceAsAttributes implements ContentHandler {
-
- /** The wrapped content handler. */
- private final ContentHandler contentHandler;
-
- /**
- * The prefixes of startPrefixMapping() declarations for the coming element.
- */
- private List<String> prefixList = new ArrayList<String>();
-
- /**
- * The URIs of startPrefixMapping() declarations for the coming element.
- */
- private List<String> uriList = new ArrayList<String>();
-
- /**
- * Maps of URI<->prefix mappings. Used to work around a bug in the Xalan
- * serializer.
- */
- private Map<String, String> uriToPrefixMap = new HashMap<String, String>();
- private Map<String, String> prefixToUriMap = new HashMap<String, String>();
-
- /**
- * True if there has been some startPrefixMapping() for the coming element.
- */
- private boolean hasMappings = false;
-
- public NamespaceAsAttributes(ContentHandler ch) {
- this.contentHandler = ch;
- }
-
- public void startDocument() throws SAXException {
- // Cleanup
- this.uriToPrefixMap.clear();
- this.prefixToUriMap.clear();
- clearMappings();
- this.contentHandler.startDocument();
- }
-
- /**
- * Track mappings to be able to add <code>xmlns:</code> attributes
- * in <code>startElement()</code>.
- */
- public void startPrefixMapping(String prefix, String uri) throws SAXException {
- // Store the mappings to reconstitute xmlns:attributes
- // except prefixes starting with "xml": these are reserved
- // VG: (uri != null) fixes NPE in startElement
- if (uri != null && !prefix.startsWith("xml")) {
- this.hasMappings = true;
- this.prefixList.add(prefix);
- this.uriList.add(uri);
-
- // append the prefix colon now, in order to save concatenations later, but
- // only for non-empty prefixes.
- if (prefix.length() > 0) {
- this.uriToPrefixMap.put(uri, prefix + ":");
- } else {
- this.uriToPrefixMap.put(uri, prefix);
- }
-
- this.prefixToUriMap.put(prefix, uri);
- }
- this.contentHandler.startPrefixMapping(prefix, uri);
- }
-
- /**
- * Ensure all namespace declarations are present as <code>xmlns:</code> attributes
- * and add those needed before calling superclass. This is a workaround for a Xalan bug
- * (at least in version 2.0.1) : <code>org.apache.xalan.serialize.SerializerToXML</code>
- * ignores <code>start/endPrefixMapping()</code>.
- */
- public void startElement(String eltUri, String eltLocalName, String eltQName, Attributes attrs)
- throws SAXException {
-
- // try to restore the qName. The map already contains the colon
- if (null != eltUri && eltUri.length() != 0 && this.uriToPrefixMap.containsKey(eltUri)) {
- eltQName = this.uriToPrefixMap.get(eltUri) + eltLocalName;
- }
- if (this.hasMappings) {
- // Add xmlns* attributes where needed
-
- // New Attributes if we have to add some.
- AttributesImpl newAttrs = null;
-
- int mappingCount = this.prefixList.size();
- int attrCount = attrs.getLength();
-
- for (int mapping = 0; mapping < mappingCount; mapping++) {
-
- // Build infos for this namespace
- String uri = this.uriList.get(mapping);
- String prefix = this.prefixList.get(mapping);
- String qName = prefix.length() == 0 ? "xmlns" : ("xmlns:" + prefix);
-
- // Search for the corresponding xmlns* attribute
- boolean found = false;
- for (int attr = 0; attr < attrCount; attr++) {
- if (qName.equals(attrs.getQName(attr))) {
- // Check if mapping and attribute URI match
- if (!uri.equals(attrs.getValue(attr))) {
- throw new SAXException("URI in prefix mapping and attribute do not match");
- }
- found = true;
- break;
- }
- }
-
- if (!found) {
- // Need to add this namespace
- if (newAttrs == null) {
- // Need to test if attrs is empty or we go into an infinite loop...
- // Well know SAX bug which I spent 3 hours to remind of :-(
- if (attrCount == 0) {
- newAttrs = new AttributesImpl();
- } else {
- newAttrs = new AttributesImpl(attrs);
- }
- }
-
- if (prefix.length() == 0) {
- newAttrs.addAttribute(XML_NAMESPACE_URI, "xmlns", "xmlns", "CDATA", uri);
- } else {
- newAttrs.addAttribute(XML_NAMESPACE_URI, prefix, qName, "CDATA", uri);
- }
- }
- } // end for mapping
-
- // Cleanup for the next element
- clearMappings();
-
- // Start element with new attributes, if any
- this.contentHandler.startElement(eltUri, eltLocalName, eltQName, newAttrs == null ? attrs : newAttrs);
- } else {
- // Normal job
- this.contentHandler.startElement(eltUri, eltLocalName, eltQName, attrs);
- }
- }
-
-
- /**
- * Receive notification of the end of an element.
- * Try to restore the element qName.
- */
- public void endElement(String eltUri, String eltLocalName, String eltQName) throws SAXException {
- // try to restore the qName. The map already contains the colon
- if (null != eltUri && eltUri.length() != 0 && this.uriToPrefixMap.containsKey(eltUri)) {
- eltQName = this.uriToPrefixMap.get(eltUri) + eltLocalName;
- }
- this.contentHandler.endElement(eltUri, eltLocalName, eltQName);
- }
-
- /**
- * End the scope of a prefix-URI mapping:
- * remove entry from mapping tables.
- */
- public void endPrefixMapping(String prefix) throws SAXException {
- // remove mappings for xalan-bug-workaround.
- // Unfortunately, we're not passed the uri, but the prefix here,
- // so we need to maintain maps in both directions.
- if (this.prefixToUriMap.containsKey(prefix)) {
- this.uriToPrefixMap.remove(this.prefixToUriMap.get(prefix));
- this.prefixToUriMap.remove(prefix);
- }
-
- if (hasMappings) {
- // most of the time, start/endPrefixMapping calls have an element event between them,
- // which will clear the hasMapping flag and so this code will only be executed in the
- // rather rare occasion when there are start/endPrefixMapping calls with no element
- // event in between. If we wouldn't remove the items from the prefixList and uriList here,
- // the namespace would be incorrectly declared on the next element following the
- // endPrefixMapping call.
- int pos = prefixList.lastIndexOf(prefix);
- if (pos != -1) {
- prefixList.remove(pos);
- uriList.remove(pos);
- }
- }
-
- this.contentHandler.endPrefixMapping(prefix);
- }
-
- /**
- * @see org.xml.sax.ContentHandler#endDocument()
- */
- public void endDocument() throws SAXException {
- // Cleanup
- this.uriToPrefixMap.clear();
- this.prefixToUriMap.clear();
- clearMappings();
- this.contentHandler.endDocument();
- }
-
- private void clearMappings() {
- this.hasMappings = false;
- this.prefixList.clear();
- this.uriList.clear();
- }
-
- /**
- * @see org.xml.sax.ContentHandler#characters(char[], int, int)
- */
- public void characters(char[] ch, int start, int length) throws SAXException {
- contentHandler.characters(ch, start, length);
- }
-
- /**
- * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
- */
- public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
- contentHandler.ignorableWhitespace(ch, start, length);
- }
-
- /**
- * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
- */
- public void processingInstruction(String target, String data) throws SAXException {
- contentHandler.processingInstruction(target, data);
- }
-
- /**
- * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
- */
- public void setDocumentLocator(Locator locator) {
- contentHandler.setDocumentLocator(locator);
- }
-
- /**
- * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
- */
- public void skippedEntity(String name) throws SAXException {
- contentHandler.skippedEntity(name);
+ throw new SAXException("Unable to create xml writer for: " + file, se);
}
}
@@ -386,7 +97,7 @@
* @param name The name of the attribute.
* @param value The value of the attribute.
*/
- protected static void addAttribute(AttributesImpl ai, String name, Object value) {
+ public static void addAttribute(final AttributesImpl ai, final String name, final Object value) {
if ( value != null ) {
ai.addAttribute("", name, name, "CDATA", value.toString());
}
@@ -398,7 +109,7 @@
* @param text
* @throws SAXException
*/
- protected static void text(ContentHandler ch, String text)
+ public static void text(final ContentHandler ch, final String text)
throws SAXException {
if ( text != null ) {
final char[] c = text.toCharArray();
@@ -412,7 +123,7 @@
* @param ch The content handler.
* @param level The level of indention.
*/
- protected static void indent(ContentHandler ch, int level)
+ public static void indent(final ContentHandler ch, final int level)
throws SAXException {
for(int i=0;i<level;i++) {
IOUtils.text(ch, " ");
@@ -424,7 +135,7 @@
* @param ch The content handler.
* @throws SAXException
*/
- protected static void newline(ContentHandler ch)
+ public static void newline(final ContentHandler ch)
throws SAXException {
IOUtils.text(ch, "\n");
}