View Javadoc
1   package org.exolab.castor.xml.parsing;
2   
3   import java.util.Enumeration;
4   import java.util.HashMap;
5   
6   import org.apache.commons.lang.StringUtils;
7   import org.exolab.castor.mapping.FieldHandler;
8   import org.exolab.castor.mapping.MapItem;
9   import org.exolab.castor.xml.*;
10  import org.xml.sax.SAXException;
11  
12  /**
13   * This class is used by the {@link UnmarshalHandler} to handle name spaces. It
14   * manages a stack of name spaces, keeps track of when an new name space scope
15   * is needed and maps name space URIs to package names.
16   * 
17   * @author <a href="mailto:philipp DOT erlacher AT gmail DOT com">Philipp
18   *         Erlacher</a>
19   * 
20   * @since 1.3.2
21   */
22  public class NamespaceHandling {
23  
24      /**
25       * Represents the namespace stack.
26       */
27      private NamespacesStack namespacesStack = new NamespacesStack();
28  
29      /**
30       * A map of name space URIs to package names.
31       */
32      private HashMap<String, String> _namespaceToPackage = new HashMap<String, String>();
33  
34      /**
35       * A flag to keep track of when a new name space scope is needed.
36       */
37      private boolean _createNamespaceScope = true;
38  
39      /**
40       * The built-in XML prefix used for xml:space, xml:lang and, as the XML 1.0
41       * Namespaces document specifies, are reserved for use by XML and XML
42       * related specs.
43       **/
44      private static final String XML_PREFIX = "xml";
45  
46      /**
47       * Adds a mapping from the given namespace URI to the given package name.
48       * 
49       * @param nsURI
50       *            the namespace URI to map from.
51       * @param packageName
52       *            the package name to map to.
53       */
54      public void addNamespaceToPackageMapping(String nsURI, String packageName) {
55          _namespaceToPackage.put(StringUtils.defaultString(nsURI), StringUtils
56                  .defaultString(packageName));
57  
58      }
59  
60      /**
61       * Looks up the package name from the given namespace URI.
62       * 
63       * @param namespace
64       *            the namespace URI to lookup
65       * @return the package name or null.
66       */
67      public String getMappedPackage(final String namespace) {
68          return _namespaceToPackage.get(StringUtils.defaultString(namespace));
69      }
70  
71      /**
72       * Saves local namespace declarations to the object model if necessary.
73       * 
74       * @param classDesc
75       *            the current ClassDescriptor.
76       * @param object
77       *            the Object of the current state
78       **/
79      public void processNamespaces(XMLClassDescriptor classDesc, Object object) {
80  
81          if (classDesc == null) {
82              return;
83          }
84  
85          // -- process namespace nodes
86          XMLFieldDescriptor nsDescriptor = classDesc.getFieldDescriptor(null,
87                  null, NodeType.Namespace);
88  
89          if (nsDescriptor != null) {
90              FieldHandler handler = nsDescriptor.getHandler();
91              if (handler != null) {
92                  Enumeration<String> enumeration = namespacesStack
93                          .getLocalNamespacePrefixes();
94                  while (enumeration.hasMoreElements()) {
95                      String nsPrefix = StringUtils.defaultString(enumeration
96                              .nextElement());
97                      String nsURI = StringUtils.defaultString(namespacesStack
98                              .getNamespaceURI(nsPrefix));
99                      MapItem mapItem = new MapItem(nsPrefix, nsURI);
100                     handler.setValue(object, mapItem);
101                 }
102             }
103         }
104     }
105 
106     /**
107      * Extracts the prefix and resolves it to it's associated namespace. If the
108      * prefix is 'xml', then no resolution will occur, however in all other
109      * cases the resolution will change the prefix:value as {NamespaceURI}value
110      * 
111      * @param value
112      *            the QName to resolve.
113      * @return
114      * @throws SAXException
115      *             if the nammespace associated with the prefix is null
116      */
117     public Object resolveNamespace(Object value) throws SAXException {
118 
119         if ((value == null) || !(value instanceof String)) {
120             return value;
121         }
122 
123         String result = (String) value;
124         int idx = result.indexOf(':');
125         String prefix = null;
126         if (idx > 0) {
127             prefix = result.substring(0, idx);
128             if (XML_PREFIX.equals(prefix)) {
129                 // -- Do NOT Resolve the 'xml' prefix.
130                 return value;
131             }
132             result = result.substring(idx + 1);
133         }
134         String namespace = getNamespaceURI(prefix);
135         if (StringUtils.isNotEmpty(namespace)) {
136             result = '{' + namespace + '}' + result;
137             return result;
138         } else if ((namespace == null) && (prefix != null)) {
139             throw new SAXException(
140                     "The namespace associated with the prefix: '" + prefix
141                             + "' is null.");
142         } else {
143             return result;
144         }
145 
146     }
147 
148     /**
149      * Pops the current namespace instance
150      */
151     public void removeCurrentNamespaceInstance() {
152         namespacesStack.removeNamespaceScope();
153     }
154 
155     /**
156      * Binds the namespaceURI to the default namespace.
157      * 
158      * @param namespaceURI
159      *            Namespace URI
160      */
161     public void addDefaultNamespace(String namespaceURI) {
162         namespacesStack.addDefaultNamespace(namespaceURI);
163     }
164 
165     /**
166      * Binds the namespaceURI to the prefix
167      * 
168      * @param prefix
169      *            XML name space prefix
170      * @param namespaceURI
171      *            XML name space URI.
172      */
173     public void addNamespace(String prefix, String namespaceURI) {
174         namespacesStack.addNamespace(prefix, namespaceURI);
175 
176     }
177 
178     /**
179      * Gets the prefix that is bound to a namespaceURI.
180      * 
181      * @param namespaceURI
182      *            the namespaceURI to get the prefix from
183      * @return prefix
184      */
185     public String getNamespacePrefix(String namespaceURI) {
186         return namespacesStack.getNamespacePrefix(namespaceURI);
187     }
188 
189     /**
190      * Gets the namespaceURI that is bound to a prefix.
191      * 
192      * @param prefix
193      *            the prefix to get the namespaceURI from
194      * @return namespaceURI The corresponding namespace URI.
195      */
196     public String getNamespaceURI(String prefix) {
197         return namespacesStack.getNamespaceURI(prefix);
198     }
199 
200     /**
201      * Gets the namespace URI that is bound to the default name space.
202      * 
203      * @return namespaceURI The namespace URI bound to the default namespace.
204      */
205     public String getDefaultNamespaceURI() {
206         return namespacesStack.getDefaultNamespaceURI();
207     }
208 
209     /**
210      * Creates a new name space.
211      */
212     public void createNamespace() {
213         namespacesStack.addNewNamespaceScope();
214     }
215 
216     /**
217      * Returns the namespace stack.
218      * @return the namespace stack.
219      */
220     public NamespacesStack getNamespaceStack() {
221         return namespacesStack;
222     }
223 
224     /**
225      * Indicates whether a new name space scope is needed.
226      * 
227      * @return true if a new name space scope is necessary.
228      */
229     public boolean isNewNamespaceScopeNecessary() {
230         if (_createNamespaceScope) {
231             return true;
232         }
233         return false;
234     }
235 
236     /**
237      * Starts a new name space scope, and resets the corresponding flag.
238      */
239     public void startNamespaceScope() {
240         createNamespace();
241         _createNamespaceScope = true;
242     }
243 
244     /**
245      * Stops a name space scope, and resets the corresponding flag to false.
246      */
247     public void stopNamespaceScope() {
248         createNamespace();
249         _createNamespaceScope = false;
250     }
251 
252     public void setNewNamespaceScopeNecessary(boolean value) {
253         _createNamespaceScope = value;
254         
255     }
256 }