Source code: javax/ide/extension/spi/DefaultElementContext.java
1 package javax.ide.extension.spi;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.logging.LogRecord;
11 import java.util.logging.Logger;
12
13 import javax.ide.extension.ElementContext;
14 import javax.ide.extension.ElementEndContext;
15 import javax.ide.extension.ElementName;
16 import javax.ide.extension.ElementStartContext;
17 import javax.ide.extension.ElementVisitor;
18 import javax.ide.extension.ElementVisitorFactory;
19
20 import javax.ide.extension.ExtensionHook;
21 import org.xml.sax.Attributes;
22 import javax.ide.extension.Extension;
23 import java.net.URI;
24
25 /**
26 * A default XML context implementation. This provides access to methods that
27 * change the context and should only be used by ExtensibleSAXHandler.
28 */
29 public class DefaultElementContext
30 implements ElementContext, ElementStartContext, ElementEndContext
31 {
32 private Attributes _attributes;
33 private ElementName _name;
34 private final Stack _elementPathStack = new Stack();
35 private final ScopedMap _contextMap = new ScopedMap();
36 private final Stack _elementText = new Stack();
37
38 private final Stack _childHandlers = new Stack();
39 private Map _ceChildHandlers = null;
40
41 private Logger _logger;
42
43 private final List _visitorFactories = new ArrayList();
44
45 public DefaultElementContext()
46 {
47 // Initialize the "global" value map.
48 _childHandlers.push( null );
49 }
50
51 /**
52 * Get the local name of the current element.
53 *
54 * @return the local name of the current element.
55 */
56 public ElementName getElementName()
57 {
58 return _name;
59 }
60
61 /**
62 * Get the text contained in this element. It's only valid to call this from
63 * EDDElementHandler.handleEndElement.
64 */
65 public String getText()
66 {
67 StringBuffer buffer = (StringBuffer) _elementText.peek();
68
69 if ( buffer == null )
70 {
71 return null;
72 }
73
74 return buffer.toString();
75 }
76
77 /**
78 * Get the value of an attribute for this element. It's only valid to call
79 * this from EDDElementHandler.handleStartElement.
80 *
81 * @param attributeName the local name of an XML attribute, must not be
82 * null.
83 * @return the value of the specified attribute, or null if not present.
84 */
85 public String getAttributeValue( String attributeName )
86 {
87 if ( _attributes == null )
88 {
89 throw new IllegalStateException(
90 "Cannot call from handleEndElement"
91 );
92 }
93
94 if ( attributeName == null )
95 {
96 throw new IllegalArgumentException( "attributeName must not be null" );
97 }
98
99 return _attributes.getValue( attributeName );
100 }
101
102 public Collection getAttributeNames()
103 {
104 if (_attributes == null)
105 {
106 throw new IllegalStateException();
107 }
108 ArrayList al = new ArrayList( _attributes.getLength() );
109 for ( int i=0; i < _attributes.getLength(); i++ )
110 {
111 al.add( _attributes.getLocalName( i ) );
112 }
113
114 return Collections.unmodifiableCollection( al );
115 }
116
117 public Map getScopeData()
118 {
119 return _contextMap;
120 }
121
122 /**
123 * Register a handler that will be used only for immediate children of the
124 * current element.
125 *
126 * @param name the element name.
127 * @param visitor the {@link ElementVisitor}.
128 */
129 public void registerChildVisitor( ElementName name, ElementVisitor visitor )
130 {
131 if ( _ceChildHandlers == null )
132 {
133 _ceChildHandlers = new HashMap();
134 }
135 _ceChildHandlers.put( name, visitor );
136 }
137
138
139 public void registerVisitorFactory( ElementVisitorFactory factory )
140 {
141 _visitorFactories.add( factory );
142 }
143
144 /**
145 * Get a scoped handler for the current element (if any)
146 */
147 public ElementVisitor getScopedHandler()
148 {
149 ElementName qualified = _name;
150 ElementName unqualified = new ElementName( null, _name.getLocalName() );
151 ElementVisitor handler = null;
152
153 // Look for child-only handlers first.
154 Map childHandlerMap = (Map) _childHandlers.peek();
155 if ( childHandlerMap != null )
156 {
157 handler = (ElementVisitor) childHandlerMap.get( qualified );
158 if ( handler == null )
159 {
160 handler = (ElementVisitor) childHandlerMap.get( unqualified );
161 }
162
163 if ( handler != null )
164 {
165 return handler;
166 }
167
168 }
169
170 for ( Iterator i = _visitorFactories.iterator(); i.hasNext(); )
171 {
172 ElementVisitorFactory factory = (ElementVisitorFactory) i.next();
173
174 ElementVisitor visitor = factory.getVisitor( _name );
175 if ( visitor != null )
176 {
177 return visitor;
178 }
179 }
180
181
182 return handler;
183 }
184
185 private void setElement( String uri, String name )
186 {
187 _name = new ElementName( uri, name );
188 }
189
190 void beginElement( String uri, String name, Attributes attributes )
191 {
192 setElement( uri, name );
193 _attributes = attributes;
194
195 _contextMap.enterScope();
196
197 _childHandlers.push( _ceChildHandlers );
198 _ceChildHandlers = null;
199 }
200
201 void appendCharacters( char[] characters, int start, int length )
202 {
203 if ( _elementText.isEmpty() )
204 {
205 throw new IllegalStateException();
206 }
207
208 StringBuffer buffer = (StringBuffer) _elementText.peek();
209 if ( buffer == null )
210 {
211 buffer = new StringBuffer();
212 _elementText.replace( buffer );
213 }
214
215 buffer.append( characters, start, length );
216 }
217
218 void postEndElement()
219 {
220 _contextMap.exitScope();
221 _elementText.pop();
222 _ceChildHandlers = (Map) _childHandlers.peek();
223 _childHandlers.pop();
224
225
226 _name = null;
227 _attributes = null;
228 }
229
230 void endElement( String uri, String name )
231 {
232 setElement( uri, name );
233 _attributes = null;
234 _elementPathStack.pop();
235 }
236
237 /**
238 * Push the current element onto the element stack.
239 */
240 void postBeginElement()
241 {
242 _elementPathStack.push( _name );
243 _elementText.push( null ); // StringBuffer is created lazily.
244 }
245
246 public Logger getLogger()
247 {
248 if ( _logger == null )
249 {
250 _logger = new NullLogger();
251 }
252 return _logger;
253 }
254
255 public void setMessageReporter( Logger logger )
256 {
257 _logger = logger;
258 }
259
260 /**
261 * Get the extension currently being processed.
262 *
263 * @return the exetnsion currently being processed.
264 */
265 public Extension getExtension()
266 {
267 return (Extension) getScopeData().get( ExtensionHook.KEY_EXTENSION );
268 }
269
270
271 /**
272 * Get the URI of the source of the extension. For extensions packaged in
273 * JAR files, this is the URI of the JAR file.
274 *
275 * @return the URI of the exension source.
276 */
277 public URI getExtensionSourceURI()
278 {
279 ExtensionSource source = (ExtensionSource) getScopeData().get(
280 ExtensionVisitor.KEY_EXTENSION_SOURCE
281 );
282 return source.getURI();
283 }
284
285 private class NullLogger extends Logger
286 {
287 public NullLogger( )
288 {
289 super( null, null );
290 }
291
292 public void log( LogRecord logRecord )
293 {
294 // NO-OP
295 }
296 }
297
298 }