KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > tools > xjc > runtime > NamespaceContextImpl


1 package com.sun.tools.xjc.runtime;
2
3 import java.util.Enumeration JavaDoc;
4 import java.util.HashMap JavaDoc;
5 import java.util.HashSet JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.util.Map JavaDoc;
8 import java.util.Set JavaDoc;
9
10 import javax.xml.XMLConstants JavaDoc;
11
12 import org.xml.sax.SAXException JavaDoc;
13
14 import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
15 import com.sun.xml.bind.marshaller.NamespaceSupport;
16
17 /**
18  * Implementation of the NamespaceContext2.
19  *
20  * This class also provides several utility methods for
21  * XMLSerializer-derived classes.
22  *
23  * The startElement method and the endElement method need to be called
24  * appropriately when used. See javadoc for those methods for details.
25  */

26 public class NamespaceContextImpl implements NamespaceContext2
27 {
28     /**
29      * Sequence generator. Used as the last resort to generate
30      * unique prefix.
31      */

32     private int iota = 1;
33     
34     /**
35      * Used to maintain association between prefixes and URIs.
36      */

37     private final NamespaceSupport nss = new NamespaceSupport();
38     
39     /**
40      * A flag that indicates the current mode of this object.
41      */

42     private boolean inCollectingMode;
43     
44     /** Assigns prefixes to URIs. Can be null. */
45     private final NamespacePrefixMapper prefixMapper;
46     
47     /**
48      * Used during the collecting mode to sort out the namespace
49      * URIs we need for this element.
50      *
51      * A map from prefixes to namespace URIs.
52      */

53     private final Map JavaDoc decls = new HashMap JavaDoc();
54     
55     private final Map JavaDoc reverseDecls = new HashMap JavaDoc();
56     
57     
58     public NamespaceContextImpl(NamespacePrefixMapper _prefixMapper) {
59         this.prefixMapper = _prefixMapper;
60         // declare the default namespace binding
61
// which are effective because of the way XML1.0 is made
62
nss.declarePrefix("","");
63         nss.declarePrefix( "xmlns", XMLConstants.XMLNS_ATTRIBUTE_NS_URI );
64 // this one is taken care of by the NamespaceSupport class by default.
65
// nss.declarePrefix( "xml", XMLConstants.XML_NS_URI );
66
}
67     
68     public final NamespacePrefixMapper getNamespacePrefixMapper() {
69         return prefixMapper;
70     }
71     
72 //
73
//
74
// public methods of MarshallingContext
75
//
76
//
77
/**
78      * @param requirePrefix
79      * true if this is called for attribute name. false otherwise.
80      */

81     public String JavaDoc declareNamespace( String JavaDoc namespaceUri, String JavaDoc preferedPrefix, boolean requirePrefix ) {
82         if( !inCollectingMode ) {
83             if( !requirePrefix && nss.getURI("").equals(namespaceUri) )
84                 return ""; // can use the default prefix. use it whenever we can
85

86             // find a valid prefix for this namespace URI
87
// ASSERTION: the result is always non-null,
88
// since we require all the namespace URIs to be declared while
89
// this object is in collection mode.
90
if (requirePrefix)
91                 return nss.getPrefix2(namespaceUri);
92             else
93                 return nss.getPrefix(namespaceUri);
94         } else {
95             if( requirePrefix && namespaceUri.length()==0 )
96                 return "";
97             
98             // collect this new namespace URI
99
String JavaDoc prefix = (String JavaDoc)reverseDecls.get(namespaceUri);
100             if( prefix!=null ) {
101                 if( !requirePrefix || prefix.length()!=0 ) {
102                     // this namespace URI is already taken care of,
103
// and it satisfies the "requirePrefix" requirement.
104
return prefix;
105                 } else {
106                     // the prefix was already allocated but it's "",
107
// and we specifically need non-empty prefix.
108

109                     // erase the current binding
110
decls.remove(prefix);
111                     reverseDecls.remove(namespaceUri);
112                 }
113             }
114             
115             
116             if( namespaceUri.length()==0 ) {
117                 // the empty namespace URI needs to be bound to the default prefix.
118
prefix = "";
119             } else {
120                 // see if this namespace URI is already in-scope
121
prefix = nss.getPrefix(namespaceUri);
122                 if( prefix==null )
123                     prefix = (String JavaDoc)reverseDecls.get(namespaceUri);
124                 
125                 if( prefix==null ) {
126                     // if not, try to allocate a new one.
127

128                     // use prefixMapper if specified. If so, just let the
129
// prefixMapper decide if it wants to use the suggested prefix.
130
// otherwise our best bet is the suggested prefix.
131
if( prefixMapper!=null )
132                         prefix = prefixMapper.getPreferredPrefix(
133                             namespaceUri,preferedPrefix,requirePrefix);
134                     else
135                        prefix = preferedPrefix;
136
137                     if( prefix==null )
138                         // if the user don't care, generate one
139
prefix = "ns"+(iota++);
140                 }
141             }
142
143             // ASSERT: prefix!=null
144

145             if( requirePrefix && prefix.length()==0 )
146                 // we can't map it to the default prefix. generate one.
147
prefix = "ns"+(iota++);
148             
149             
150             while(true) {
151                 String JavaDoc existingUri = (String JavaDoc)decls.get(prefix);
152                 
153                 if( existingUri==null ) {
154                     // this prefix is unoccupied. use it
155
decls.put( prefix, namespaceUri );
156                     reverseDecls.put( namespaceUri, prefix );
157                     return prefix;
158                 }
159                 
160                 if( existingUri.length()==0 ) {
161                     // we have to remap the new namespace URI to a different
162
// prefix because the current association of ""->"" cannot
163
// be changed
164
;
165                 } else {
166                     // the new one takes precedence. this is necessary
167
// because we might first assign "uri1"->"" and then
168
// later find that ""->"" needs to be added.
169

170                     // so change the existing one
171
decls.put( prefix, namespaceUri );
172                     reverseDecls.put( namespaceUri, prefix );
173                     
174                     namespaceUri = existingUri;
175                 }
176                 
177                 // we need to find a new prefix for URI "namespaceUri"
178
// generate a machine-made prefix
179
prefix = "ns"+(iota++);
180                 
181                 // go back to the loop and reassign
182
}
183         }
184     }
185     
186
187     public String JavaDoc getPrefix( String JavaDoc namespaceUri ) {
188         // even through the method name is "getPrefix", we
189
// use this method to declare prefixes if necessary.
190

191         // the only time a prefix is required is when we print
192
// attribute names, and in those cases we will call
193
// declareNamespace method directly. So it's safe to
194
// assume that we don't require a prefix in this case.
195
return declareNamespace(namespaceUri,null,false);
196     }
197     
198     /**
199      * Obtains the namespace URI currently associated to the given prefix.
200      * If no namespace URI is associated, return null.
201      */

202     public String JavaDoc getNamespaceURI( String JavaDoc prefix ) {
203         String JavaDoc uri = (String JavaDoc)decls.get(prefix);
204         if(uri!=null) return uri;
205         
206         return nss.getURI(prefix);
207     }
208     
209     public Iterator JavaDoc getPrefixes( String JavaDoc namespaceUri ) {
210         // not particularly efficient implementation.
211
Set JavaDoc s = new HashSet JavaDoc();
212         
213         String JavaDoc prefix = (String JavaDoc)reverseDecls.get(namespaceUri);
214         if(prefix!=null) s.add(prefix);
215         
216         if( nss.getURI("").equals(namespaceUri) )
217             s.add("");
218         
219         for( Enumeration JavaDoc e=nss.getPrefixes(namespaceUri); e.hasMoreElements(); )
220             s.add(e.nextElement());
221         
222         return s.iterator();
223     }
224
225     /**
226      * Sets the current bindings aside and starts a new element context.
227      *
228      * This method should be called at the beginning of the startElement method
229      * of the Serializer implementation.
230      */

231     public void startElement() {
232         nss.pushContext();
233         inCollectingMode = true;
234     }
235     
236     /**
237      * Reconciles the namespace URI/prefix mapping requests since the
238      * last startElement method invocation and finalizes them.
239      *
240      * This method must be called after all the necessary namespace URIs
241      * for this element is reported through the declareNamespace method
242      * or the getPrefix method.
243      */

244     public void endNamespaceDecls() {
245         if(!decls.isEmpty()) {
246             // most of the times decls is empty, so take advantage of it.
247
for( Iterator JavaDoc itr=decls.entrySet().iterator(); itr.hasNext(); ) {
248                 Map.Entry JavaDoc e = (Map.Entry JavaDoc)itr.next();
249                 String JavaDoc prefix = (String JavaDoc)e.getKey();
250                 String JavaDoc uri = (String JavaDoc)e.getValue();
251                 if(!uri.equals(nss.getURI(prefix))) // avoid redundant decls.
252
nss.declarePrefix( prefix, uri );
253             }
254             decls.clear();
255             reverseDecls.clear();
256         }
257         inCollectingMode = false;
258     }
259     
260     /**
261      * Ends the current element context and gets back to the parent context.
262      *
263      * This method should be called at the end of the endElement method
264      * of derived classes.
265      */

266     public void endElement() {
267         nss.popContext();
268     }
269
270     
271     
272     /** Iterates all newly declared namespace prefixes for this element. */
273     public void iterateDeclaredPrefixes( PrefixCallback callback ) throws SAXException JavaDoc {
274         for( Enumeration JavaDoc e=nss.getDeclaredPrefixes(); e.hasMoreElements(); ) {
275             String JavaDoc p = (String JavaDoc)e.nextElement();
276             String JavaDoc uri = nss.getURI(p);
277             
278             callback.onPrefixMapping( p, uri );
279         }
280     }
281     
282     
283 }
284
Popular Tags