1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.ws.util.xml;
  27 
  28 import com.sun.istack.internal.Nullable;
  29 import com.sun.org.apache.xml.internal.resolver.Catalog;
  30 import com.sun.org.apache.xml.internal.resolver.CatalogManager;
  31 import com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver;
  32 import com.sun.xml.internal.ws.server.ServerRtException;
  33 import com.sun.xml.internal.ws.util.ByteArrayBuffer;
  34 import org.w3c.dom.Attr;
  35 import org.w3c.dom.Element;
  36 import org.w3c.dom.EntityReference;
  37 import org.w3c.dom.Node;
  38 import org.w3c.dom.NodeList;
  39 import org.w3c.dom.Text;
  40 import org.xml.sax.EntityResolver;
  41 import org.xml.sax.ErrorHandler;
  42 import org.xml.sax.SAXException;
  43 import org.xml.sax.SAXParseException;
  44 import org.xml.sax.XMLReader;
  45 import org.xml.sax.InputSource;
  46 
  47 import javax.xml.namespace.QName;
  48 import javax.xml.parsers.ParserConfigurationException;
  49 import javax.xml.parsers.SAXParserFactory;
  50 import javax.xml.transform.Result;
  51 import javax.xml.transform.Source;
  52 import javax.xml.transform.Transformer;
  53 import javax.xml.transform.TransformerConfigurationException;
  54 import javax.xml.transform.TransformerException;
  55 import javax.xml.transform.TransformerFactory;
  56 import javax.xml.transform.sax.SAXTransformerFactory;
  57 import javax.xml.transform.sax.TransformerHandler;
  58 import javax.xml.transform.stream.StreamSource;
  59 import javax.xml.ws.WebServiceException;
  60 import java.io.IOException;
  61 import java.io.InputStream;
  62 import java.io.OutputStreamWriter;
  63 import java.io.Writer;
  64 import java.net.URL;
  65 import java.util.ArrayList;
  66 import java.util.Enumeration;
  67 import java.util.Iterator;
  68 import java.util.List;
  69 import java.util.StringTokenizer;
  70 
  71 /**
  72  * @author WS Development Team
  73  */
  74 public class XmlUtil {
  75     private final static String LEXICAL_HANDLER_PROPERTY =
  76         "http://xml.org/sax/properties/lexical-handler";
  77 
  78     public static String getPrefix(String s) {
  79         int i = s.indexOf(':');
  80         if (i == -1)
  81             return null;
  82         return s.substring(0, i);
  83     }
  84 
  85     public static String getLocalPart(String s) {
  86         int i = s.indexOf(':');
  87         if (i == -1)
  88             return s;
  89         return s.substring(i + 1);
  90     }
  91 
  92 
  93 
  94     public static String getAttributeOrNull(Element e, String name) {
  95         Attr a = e.getAttributeNode(name);
  96         if (a == null)
  97             return null;
  98         return a.getValue();
  99     }
 100 
 101     public static String getAttributeNSOrNull(
 102         Element e,
 103         String name,
 104         String nsURI) {
 105         Attr a = e.getAttributeNodeNS(nsURI, name);
 106         if (a == null)
 107             return null;
 108         return a.getValue();
 109     }
 110 
 111     public static String getAttributeNSOrNull(
 112         Element e,
 113         QName name) {
 114         Attr a = e.getAttributeNodeNS(name.getNamespaceURI(), name.getLocalPart());
 115         if (a == null)
 116             return null;
 117         return a.getValue();
 118     }
 119 
 120 /*    public static boolean matchesTagNS(Element e, String tag, String nsURI) {
 121         try {
 122             return e.getLocalName().equals(tag)
 123                 && e.getNamespaceURI().equals(nsURI);
 124         } catch (NullPointerException npe) {
 125 
 126             // localname not null since parsing would fail before here
 127             throw new WSDLParseException(
 128                 "null.namespace.found",
 129                 e.getLocalName());
 130         }
 131     }
 132 
 133     public static boolean matchesTagNS(
 134         Element e,
 135         javax.xml.namespace.QName name) {
 136         try {
 137             return e.getLocalName().equals(name.getLocalPart())
 138                 && e.getNamespaceURI().equals(name.getNamespaceURI());
 139         } catch (NullPointerException npe) {
 140 
 141             // localname not null since parsing would fail before here
 142             throw new WSDLParseException(
 143                 "null.namespace.found",
 144                 e.getLocalName());
 145         }
 146     }*/
 147 
 148     public static Iterator getAllChildren(Element element) {
 149         return new NodeListIterator(element.getChildNodes());
 150     }
 151 
 152     public static Iterator getAllAttributes(Element element) {
 153         return new NamedNodeMapIterator(element.getAttributes());
 154     }
 155 
 156     public static List<String> parseTokenList(String tokenList) {
 157         List<String> result = new ArrayList<String>();
 158         StringTokenizer tokenizer = new StringTokenizer(tokenList, " ");
 159         while (tokenizer.hasMoreTokens()) {
 160             result.add(tokenizer.nextToken());
 161         }
 162         return result;
 163     }
 164 
 165     public static String getTextForNode(Node node) {
 166         StringBuffer sb = new StringBuffer();
 167 
 168         NodeList children = node.getChildNodes();
 169         if (children.getLength() == 0)
 170             return null;
 171 
 172         for (int i = 0; i < children.getLength(); ++i) {
 173             Node n = children.item(i);
 174 
 175             if (n instanceof Text)
 176                 sb.append(n.getNodeValue());
 177             else if (n instanceof EntityReference) {
 178                 String s = getTextForNode(n);
 179                 if (s == null)
 180                     return null;
 181                 else
 182                     sb.append(s);
 183             } else
 184                 return null;
 185         }
 186 
 187         return sb.toString();
 188     }
 189 
 190     public static InputStream getUTF8Stream(String s) {
 191         try {
 192             ByteArrayBuffer bab = new ByteArrayBuffer();
 193             Writer w = new OutputStreamWriter(bab, "utf-8");
 194             w.write(s);
 195             w.close();
 196             return bab.newInputStream();
 197         } catch (IOException e) {
 198             throw new RuntimeException("should not happen");
 199         }
 200     }
 201 
 202     static final ContextClassloaderLocal<TransformerFactory> transformerFactory = new ContextClassloaderLocal<TransformerFactory>() {
 203         @Override
 204         protected TransformerFactory initialValue() throws Exception {
 205             return TransformerFactory.newInstance();
 206         }
 207     };
 208 
 209     static final ContextClassloaderLocal<SAXParserFactory> saxParserFactory = new ContextClassloaderLocal<SAXParserFactory>() {
 210         @Override
 211         protected SAXParserFactory initialValue() throws Exception {
 212             SAXParserFactory factory = SAXParserFactory.newInstance();
 213             factory.setNamespaceAware(true);
 214             return factory;
 215         }
 216     };
 217 
 218     /**
 219      * Creates a new identity transformer.
 220      */
 221     public static Transformer newTransformer() {
 222         try {
 223             return transformerFactory.get().newTransformer();
 224         } catch (TransformerConfigurationException tex) {
 225             throw new IllegalStateException("Unable to create a JAXP transformer");
 226         }
 227     }
 228 
 229     /**
 230      * Performs identity transformation.
 231      */
 232     public static <T extends Result>
 233     T identityTransform(Source src, T result) throws TransformerException, SAXException, ParserConfigurationException, IOException {
 234         if (src instanceof StreamSource) {
 235             // work around a bug in JAXP in JDK6u4 and earlier where the namespace processing
 236             // is not turned on by default
 237             StreamSource ssrc = (StreamSource) src;
 238             TransformerHandler th = ((SAXTransformerFactory) transformerFactory.get()).newTransformerHandler();
 239             th.setResult(result);
 240             XMLReader reader = saxParserFactory.get().newSAXParser().getXMLReader();
 241             reader.setContentHandler(th);
 242             reader.setProperty(LEXICAL_HANDLER_PROPERTY, th);
 243             reader.parse(toInputSource(ssrc));
 244         } else {
 245             newTransformer().transform(src, result);
 246         }
 247         return result;
 248     }
 249 
 250     private static InputSource toInputSource(StreamSource src) {
 251         InputSource is = new InputSource();
 252         is.setByteStream(src.getInputStream());
 253         is.setCharacterStream(src.getReader());
 254         is.setPublicId(src.getPublicId());
 255         is.setSystemId(src.getSystemId());
 256         return is;
 257     }
 258 
 259     /*
 260     * Gets an EntityResolver using XML catalog
 261     */
 262      public static EntityResolver createEntityResolver(@Nullable URL catalogUrl) {
 263         // set up a manager
 264         CatalogManager manager = new CatalogManager();
 265         manager.setIgnoreMissingProperties(true);
 266         // Using static catalog may  result in to sharing of the catalog by multiple apps running in a container
 267         manager.setUseStaticCatalog(false);
 268         Catalog catalog = manager.getCatalog();
 269         try {
 270             if (catalogUrl != null) {
 271                 catalog.parseCatalog(catalogUrl);
 272             }
 273         } catch (IOException e) {
 274             throw new ServerRtException("server.rt.err",e);
 275         }
 276         return workaroundCatalogResolver(catalog);
 277     }
 278 
 279     /**
 280      * Gets a default EntityResolver for catalog at META-INF/jaxws-catalog.xml
 281      */
 282     public static EntityResolver createDefaultCatalogResolver() {
 283 
 284         // set up a manager
 285         CatalogManager manager = new CatalogManager();
 286         manager.setIgnoreMissingProperties(true);
 287         // Using static catalog may  result in to sharing of the catalog by multiple apps running in a container
 288         manager.setUseStaticCatalog(false);
 289         // parse the catalog
 290         ClassLoader cl = Thread.currentThread().getContextClassLoader();
 291         Enumeration<URL> catalogEnum;
 292         Catalog catalog = manager.getCatalog();
 293         try {
 294             if (cl == null) {
 295                 catalogEnum = ClassLoader.getSystemResources("META-INF/jax-ws-catalog.xml");
 296             } else {
 297                 catalogEnum = cl.getResources("META-INF/jax-ws-catalog.xml");
 298             }
 299 
 300             while(catalogEnum.hasMoreElements()) {
 301                 URL url = catalogEnum.nextElement();
 302                 catalog.parseCatalog(url);
 303             }
 304         } catch (IOException e) {
 305             throw new WebServiceException(e);
 306         }
 307 
 308         return workaroundCatalogResolver(catalog);
 309     }
 310 
 311     /**
 312      *  Default CatalogResolver implementation is broken as it depends on CatalogManager.getCatalog() which will always create a new one when
 313      *  useStaticCatalog is false.
 314      *  This returns a CatalogResolver that uses the catalog passed as parameter.
 315      * @param catalog
 316      * @return  CatalogResolver
 317      */
 318     private static CatalogResolver workaroundCatalogResolver(final Catalog catalog) {
 319         // set up a manager
 320         CatalogManager manager = new CatalogManager() {
 321             @Override
 322             public Catalog getCatalog() {
 323                 return catalog;
 324             }
 325         };
 326         manager.setIgnoreMissingProperties(true);
 327         // Using static catalog may  result in to sharing of the catalog by multiple apps running in a container
 328         manager.setUseStaticCatalog(false);
 329 
 330         return new CatalogResolver(manager);
 331     }
 332 
 333     /**
 334      * {@link ErrorHandler} that always treat the error as fatal.
 335      */
 336     public static final ErrorHandler DRACONIAN_ERROR_HANDLER = new ErrorHandler() {
 337         public void warning(SAXParseException exception) {
 338         }
 339 
 340         public void error(SAXParseException exception) throws SAXException {
 341             throw exception;
 342         }
 343 
 344         public void fatalError(SAXParseException exception) throws SAXException {
 345             throw exception;
 346         }
 347     };
 348 }