View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements. See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership. The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License. You may obtain a copy of the License at
    9    *
    10   * http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing,
    13   * software distributed under the License is distributed on an
    14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   * KIND, either express or implied. See the License for the
    16   * specific language governing permissions and limitations
    17   * under the License.
    18   */
    19
    20  package org.apache.ws.commons.schema.utils;
    21
    22  import org.apache.ws.commons.schema.constants.Constants;
    23
    24  import org.w3c.dom.NamedNodeMap;
    25  import org.w3c.dom.Node;
    26
    27  import javax.xml.namespace.NamespaceContext;
    28
    29  import java.lang.reflect.Method;
    30  import java.util.*;
    31
    32  /**
    33   * Implementation of {@link NamespaceContext}, which is based on a DOM node.
    34   */
    35  public class NodeNamespaceContext implements NamespacePrefixList {
    36      private static final String NODE_NAMSPACE_CONTEXT = NamespacePrefixList.class.getName();
    37      private static final Collection XML_NS_PREFIX_COLLECTION = Collections.singletonList(Constants.XML_NS_PREFIX);
    38      private static final Collection XMLNS_ATTRIBUTE_COLLECTION = Collections.singletonList(Constants.XMLNS_ATTRIBUTE);
    39
    40      static Method getUserData;
    41      static Method setUserData;
    42      static {
    43          try {
    44              Class cls = Class.forName("org.w3c.dom.UserDataHandler", false, Node.class.getClassLoader());
    45              getUserData = Node.class.getMethod("getUserData", new Class[]{String.class});
    46              setUserData = Node.class.getMethod("setUserData", new Class[]{String.class, Object.class, cls});
    47          } catch (Throwable e) {
    48              getUserData = null;
    49              setUserData = null;
    50          }
    51      }
    52
    53
    54
    55      private final Map declarations;
    56      private String[] prefixes;
    57
    58      /**
    59       * Creates a new instance with the given nodes context.
    60       */
    61      private NodeNamespaceContext(Map decls) {
    62          declarations = decls;
    63      }
    64
    65      public static NodeNamespaceContext getNamespaceContext(Node pNode) {
    66          if (getUserData != null) {
    67              try {
    68                  NodeNamespaceContext ctx = (NodeNamespaceContext)getUserData.invoke(pNode, new Object[] {NODE_NAMSPACE_CONTEXT});
    69                  if (ctx == null) {
    70                      Map declarations = new HashMap();
    71
    72                      Node parentNode = pNode.getParentNode();
    73                      if (parentNode != null) {
    74                          NodeNamespaceContext parent =
    75                              (NodeNamespaceContext)getUserData.invoke(parentNode, new Object[] {NODE_NAMSPACE_CONTEXT});
    76                          if (parent == null) {
    77                              parent = getNamespaceContext(parentNode);
    78                          }
    79                          declarations.putAll(parent.declarations);
    80                      }
    81
    82                      NamedNodeMap map = pNode.getAttributes();
    83                      if (map != null) {
    84                          for (int i = 0; i < map.getLength(); i++) {
    85                              Node attr = map.item(i);
    86                              final String uri = attr.getNamespaceURI();
    87                              if (Constants.XMLNS_ATTRIBUTE_NS_URI.equals(uri)) {
    88                                  String localName = attr.getLocalName();
    89                                  String prefix = Constants.XMLNS_ATTRIBUTE.equals(localName) ? Constants.DEFAULT_NS_PREFIX : localName;
    90                                  declarations.put(prefix, attr.getNodeValue());
    91                              }
    92                          }
    93                      }
    94                      ctx = new NodeNamespaceContext(declarations);
    95                      setUserData.invoke(pNode, new Object[] {NODE_NAMSPACE_CONTEXT, ctx, null});
    96                  }
    97                  return ctx;
    98              } catch (Throwable t) {
    99                  //ignore.  DOM level 2 implementation would not have the getUserData stuff.
    100                 //Thus, fall back to the old, slower method.
    101             }
    102         }
    103
    104         final Map declarations = new HashMap();
    105         new PrefixCollector(){
    106             protected void declare(String pPrefix, String pNamespaceURI) {
    107                 declarations.put(pPrefix, pNamespaceURI);
    108             }
    109         }.searchAllPrefixDeclarations(pNode);
    110         return new NodeNamespaceContext(declarations);
    111     }
    112
    113     public String getNamespaceURI(String pPrefix) {
    114         if (pPrefix == null) {
    115             throw new IllegalArgumentException("The prefix must not be null.");
    116         }
    117         if (Constants.XML_NS_PREFIX.equals(pPrefix)) {
    118             return Constants.XML_NS_URI;
    119         }
    120         if (Constants.XMLNS_ATTRIBUTE.equals(pPrefix)) {
    121             return Constants.XMLNS_ATTRIBUTE_NS_URI;
    122         }
    123         final String uri = (String) declarations.get(pPrefix);
    124         return uri == null ? Constants.NULL_NS_URI : uri;
    125     }
    126
    127     public String getPrefix(String pNamespaceURI) {
    128         if (pNamespaceURI == null) {
    129             throw new IllegalArgumentException("The namespace URI must not be null.");
    130         }
    131         if (Constants.XML_NS_URI.equals(pNamespaceURI)) {
    132             return Constants.XML_NS_PREFIX;
    133         }
    134         if (Constants.XMLNS_ATTRIBUTE_NS_URI.equals(pNamespaceURI)) {
    135             return Constants.XMLNS_ATTRIBUTE;
    136         }
    137         for (Iterator iter = declarations.entrySet().iterator();  iter.hasNext();  ) {
    138             Map.Entry entry = (Map.Entry) iter.next();
    139             if (pNamespaceURI.equals(entry.getValue())) {
    140                 return (String) entry.getKey();
    141             }
    142         }
    143         return null;
    144     }
    145
    146     public Iterator getPrefixes(String pNamespaceURI) {
    147         if (pNamespaceURI == null) {
    148             throw new IllegalArgumentException("The namespace URI must not be null.");
    149         }
    150         if (Constants.XML_NS_URI.equals(pNamespaceURI)) {
    151             return XML_NS_PREFIX_COLLECTION.iterator();
    152         }
    153         if (Constants.XMLNS_ATTRIBUTE_NS_URI.equals(pNamespaceURI)) {
    154             return XMLNS_ATTRIBUTE_COLLECTION.iterator();
    155         }
    156         final List list = new ArrayList();
    157         for (Iterator iter = declarations.entrySet().iterator();  iter.hasNext();  ) {
    158             Map.Entry entry = (Map.Entry) iter.next();
    159             if (pNamespaceURI.equals(entry.getValue())) {
    160                 list.add(entry.getKey());
    161             }
    162         }
    163         return list.iterator();
    164     }
    165
    166     public String[] getDeclaredPrefixes() {
    167         if (prefixes == null) {
    168             Collection keys = declarations.keySet();
    169             prefixes = (String[]) keys.toArray(new String[keys.size()]);
    170         }
    171         return prefixes;
    172     }
    173 }