Source code: javax/ide/model/spi/DocumentHook.java
1 package javax.ide.model.spi;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.List;
7 import java.util.logging.Level;
8
9 import javax.ide.extension.ElementContext;
10 import javax.ide.extension.ElementEndContext;
11 import javax.ide.extension.ElementName;
12 import javax.ide.extension.ElementStartContext;
13 import javax.ide.extension.ElementVisitor;
14 import javax.ide.extension.ExtensionHook;
15 import javax.ide.extension.spi.ExtensionVisitor;
16 import javax.ide.extension.spi.ListenerInfo;
17 import javax.ide.util.MetaClass;
18
19 /**
20 * Hook for documents.
21 */
22 public class DocumentHook extends ExtensionHook
23 {
24 public final static ElementName ELEMENT = new ElementName(
25 ExtensionHook.MANIFEST_XMLNS, "document-hook" );
26
27 private final static ElementName DOCUMENTS = new ElementName(
28 ExtensionHook.MANIFEST_XMLNS, "documents" );
29 private final static ElementName BY_SUFFIX = new ElementName(
30 ExtensionHook.MANIFEST_XMLNS, "by-suffix" );
31 private final static ElementName SUFFIX = new ElementName(
32 ExtensionHook.MANIFEST_XMLNS, "suffix" );
33 private final static ElementName BY_XML_ROOT = new ElementName(
34 ExtensionHook.MANIFEST_XMLNS, "by-xml-root" );
35 private final static ElementName BY_XML_DOCTYPE = new ElementName(
36 ExtensionHook.MANIFEST_XMLNS, "by-xml-doctype" );
37 private final static ElementName ROOT_ELEMENT = new ElementName(
38 ExtensionHook.MANIFEST_XMLNS, "root-element" );
39 private final static ElementName DOCTYPE = new ElementName(
40 ExtensionHook.MANIFEST_XMLNS, "doctype" );
41 private final static ElementName BY_RECOGNIZER = new ElementName(
42 ExtensionHook.MANIFEST_XMLNS, "by-recognizer" );
43
44
45
46 private final static ElementName LISTENERS = new ElementName(
47 ExtensionHook.MANIFEST_XMLNS, "listeners" );
48 private final static ElementName DOCUMENT_LISTENER = new ElementName(
49 ExtensionHook.MANIFEST_XMLNS, "document-listener" );
50 private final static ElementName PROPERTY_LISTENER = new ElementName(
51 ExtensionHook.MANIFEST_XMLNS, "property-listener" );
52
53 private final ElementVisitor _documentsVisitor = new DocumentsVisitor();
54 private final ElementVisitor _bySuffixVisitor = new BySuffixVisitor();
55 private final ElementVisitor _byXMLRootVisitor = new ByXMLRootVisitor();
56 private final ElementVisitor _byXMLDocTypeVisitor = new ByXMLDocTypeVisitor();
57 private final ElementVisitor _byRecognizerVisitor = new ByRecognizerVisitor();
58 private final ElementVisitor _rootElementVisitor = new RootElementVisitor();
59 private final ElementVisitor _docTypeVisitor = new DocTypeVisitor();
60
61 private final ElementVisitor _suffixVisitor = new SuffixVisitor();
62
63 private final ElementVisitor _listenersVisitor = new ListenersVisitor();
64
65 private final List _documentListeners = new ArrayList();
66 private final List _propertyListeners = new ArrayList();
67 private final List _suffixRecognizers = new ArrayList();
68 private final List _xmlRecognizers = new ArrayList();
69 private final List _customRecognizers = new ArrayList();
70
71
72 private final static String KEY_CURRENT_SUFFIX_RECOGNIZER = "currentSuffixRecognizer";
73
74 public Collection getDocumentListeners()
75 {
76 return Collections.unmodifiableCollection( _documentListeners );
77 }
78
79 public Collection getSuffixRecognizers()
80 {
81 return Collections.unmodifiableCollection( _suffixRecognizers );
82 }
83
84 public Collection getXMLRecognizers()
85 {
86 return Collections.unmodifiableCollection( _xmlRecognizers );
87 }
88
89 public Collection getCustomRecognizers()
90 {
91 return Collections.unmodifiableCollection( _customRecognizers );
92 }
93
94 public void start( ElementStartContext context )
95 {
96 context.registerChildVisitor( DOCUMENTS, _documentsVisitor );
97 context.registerChildVisitor( LISTENERS, _listenersVisitor );
98 }
99
100 private class DocumentsVisitor extends ElementVisitor
101 {
102 public void start( ElementStartContext context )
103 {
104 context.registerChildVisitor( BY_SUFFIX, _bySuffixVisitor );
105 context.registerChildVisitor( BY_XML_ROOT, _byXMLRootVisitor );
106 context.registerChildVisitor( BY_XML_DOCTYPE, _byXMLDocTypeVisitor );
107 context.registerChildVisitor( BY_RECOGNIZER, _byRecognizerVisitor );
108 }
109 }
110
111 private class BySuffixVisitor extends ElementVisitor
112 {
113 public final void start( ElementStartContext context )
114 {
115 String docClass = context.getAttributeValue( "document-class" );
116 if ( docClass == null || (docClass=docClass.trim()).length() == 0 )
117 {
118 docClass = getDefaultDocumentClassType();
119 if ( docClass == null )
120 {
121 log( context, Level.SEVERE, "Missing attribute 'document-class'." );
122 return;
123 }
124 }
125 MetaClass docMetaClass = createMetaClass( context, docClass );
126 SuffixRecognizer sr = createSuffixRecognizer( context, docMetaClass );
127 context.getScopeData().put( KEY_CURRENT_SUFFIX_RECOGNIZER, sr );
128
129 context.registerChildVisitor( SUFFIX, _suffixVisitor );
130 }
131
132 protected String getDefaultDocumentClassType()
133 {
134 return null;
135 }
136
137 protected boolean isSuffixRequired()
138 {
139 return true;
140 }
141
142 public final void end( ElementEndContext context )
143 {
144 SuffixRecognizer sr = getSuffixRecognizer( context );
145 if ( isSuffixRequired() && sr.getSuffixes().isEmpty() )
146 {
147 log( context, Level.SEVERE, "Missing 'suffix' element." );
148 }
149 else
150 {
151 registerRecognizer( context, sr );
152 }
153 }
154
155 protected void registerRecognizer( ElementContext context,
156 SuffixRecognizer sr )
157 {
158 _suffixRecognizers.add( sr );
159 }
160
161 protected SuffixRecognizer createSuffixRecognizer(
162 ElementStartContext context, MetaClass docClass )
163 {
164 return new SuffixRecognizer( docClass );
165 }
166
167
168 }
169
170 private final SuffixRecognizer getSuffixRecognizer( ElementContext context )
171 {
172 return (SuffixRecognizer) context.getScopeData().get( KEY_CURRENT_SUFFIX_RECOGNIZER );
173 }
174
175 private final class SuffixVisitor extends ElementVisitor
176 {
177 public void end( ElementEndContext context )
178 {
179 String text = context.getText();
180 if ( text == null || (text=text.trim()).length() == 0 )
181 {
182 log( context, Level.SEVERE, "Must provide text content for 'suffix'." );
183 return;
184 }
185 SuffixRecognizer r = getSuffixRecognizer( context );
186 r.addSuffix( text );
187 }
188 }
189
190 private final class ByXMLRootVisitor extends BySuffixVisitor
191 {
192 protected boolean isSuffixRequired() { return false; }
193
194 protected String getDefaultDocumentClassType()
195 {
196 return "javax.ide.model.xml.XMLDocument";
197 }
198
199 protected SuffixRecognizer createSuffixRecognizer(
200 ElementStartContext context, MetaClass docClass )
201 {
202 XMLRootElementRecognizer xmlr = new XMLRootElementRecognizer( docClass );
203
204 context.registerChildVisitor( ROOT_ELEMENT, _rootElementVisitor );
205
206 return xmlr;
207 }
208
209 protected void registerRecognizer( ElementContext context,
210 SuffixRecognizer sr )
211 {
212 XMLRootElementRecognizer xmlr = (XMLRootElementRecognizer) sr;
213 if ( xmlr.getRootElements().isEmpty() )
214 {
215 log( context, Level.SEVERE, "Must specify 'root-element'." );
216 }
217 else
218 {
219 _xmlRecognizers.add( xmlr );
220 }
221 }
222 }
223
224 private final class ByXMLDocTypeVisitor extends BySuffixVisitor
225 {
226 protected boolean isSuffixRequired() { return false; }
227
228 protected String getDefaultDocumentClassType()
229 {
230 return "javax.ide.model.xml.XMLDocument";
231 }
232
233
234 protected SuffixRecognizer createSuffixRecognizer(
235 ElementStartContext context, MetaClass docClass )
236 {
237 XMLDocTypeRecognizer xmlr = new XMLDocTypeRecognizer( docClass );
238
239 context.registerChildVisitor( DOCTYPE, _docTypeVisitor );
240
241 return xmlr;
242 }
243
244 protected void registerRecognizer( ElementContext context,
245 SuffixRecognizer sr )
246 {
247 XMLDocTypeRecognizer xmlr = (XMLDocTypeRecognizer) sr;
248 if ( xmlr.getDocTypes().isEmpty() )
249 {
250 log( context, Level.SEVERE, "Must specify 'doctype'." );
251 }
252 else
253 {
254 _xmlRecognizers.add( xmlr );
255 }
256 }
257 }
258
259
260 private class RootElementVisitor extends ElementVisitor
261 {
262 public void start( ElementStartContext context )
263 {
264 XMLRootElementRecognizer rec =
265 (XMLRootElementRecognizer)getSuffixRecognizer( context );
266
267 String ns = context.getAttributeValue( "namespace" );
268 if ( ns != null && ns.trim().length() == 0 ) ns = null;
269 String localName = context.getAttributeValue( "local-name" );
270 if ( localName == null || (localName = localName.trim()).length() == 0 )
271 {
272 log( context, Level.SEVERE, "Missing required attribute 'local-name'." );
273 return;
274 }
275 ElementName name = new ElementName( ns, localName );
276 rec.addRootElement( name );
277 }
278 }
279
280 private class DocTypeVisitor extends ElementVisitor
281 {
282 public void start( ElementStartContext context )
283 {
284 XMLDocTypeRecognizer rec =
285 (XMLDocTypeRecognizer)getSuffixRecognizer( context );
286
287 String publicId = context.getAttributeValue( "public-id" );
288 if ( publicId != null && publicId.trim().length() == 0 ) publicId = null;
289 String systemId = context.getAttributeValue( "system-id" );
290 if ( systemId != null && systemId.trim().length() == 0 ) systemId = null;
291 XMLDocType docType = new XMLDocType( publicId, systemId );
292 rec.addDocType( docType );
293 }
294 }
295
296 private class ByRecognizerVisitor extends ElementVisitor
297 {
298 public void start( ElementStartContext context )
299 {
300 String recClass = context.getAttributeValue( "recognizer-class" );
301 if ( recClass == null || (recClass=recClass.trim()).length() == 0 )
302 {
303 log( context, Level.SEVERE, "Missing required attribute 'recognizer-class'." );
304 return;
305 }
306
307 MetaClass recMetaClass = createMetaClass( context, recClass );
308 _customRecognizers.add( recMetaClass );
309 }
310 }
311
312
313
314 private final class ListenersVisitor extends ElementVisitor
315 {
316 public void start( ElementStartContext context )
317 {
318 context.registerChildVisitor( DOCUMENT_LISTENER,
319 new AbstractListenerVisitor() {
320 protected void listenerInfo( ElementContext context, ListenerInfo info )
321 {
322 _documentListeners.add( info );
323 }
324 }
325 );
326 context.registerChildVisitor( PROPERTY_LISTENER,
327 new AbstractListenerVisitor() {
328 protected void listenerInfo( ElementContext context, ListenerInfo info )
329 {
330 _propertyListeners.add( info );
331 }
332 }
333 );
334 }
335 }
336
337 private abstract class AbstractListenerVisitor extends ElementVisitor
338 {
339 public final void start( ElementStartContext context )
340 {
341 String listenerClass = context.getAttributeValue( "listener-class" );
342 if ( listenerClass == null ||
343 (listenerClass=listenerClass.trim()).length() == 0)
344 {
345 log( context, Level.SEVERE,
346 "Missing required attribute 'listener-class'." );
347 return;
348 }
349
350 String sourceClass = context.getAttributeValue( "source-class" );
351
352 ListenerInfo info = new ListenerInfo();
353 info.setListenerClass( createMetaClass( context, listenerClass ) );
354 info.setSourceID( sourceClass );
355
356 listenerInfo( context, info );
357 }
358
359 protected abstract void listenerInfo( ElementContext context,
360 ListenerInfo info );
361 }
362
363
364 private MetaClass createMetaClass( ElementContext context, String className )
365 {
366 ClassLoader classLoader = (ClassLoader)
367 context.getScopeData().get( ExtensionVisitor.KEY_CLASSLOADER );
368 return new MetaClass( classLoader, className );
369 }
370
371 }