/* * Copyright 2005 by Oracle USA * 500 Oracle Parkway, Redwood Shores, California, 94065, U.S.A. * All rights reserved. */ package javax.ide.model.spi; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.ide.extension.ElementContext; import javax.ide.extension.ElementEndContext; import javax.ide.extension.ElementName; import javax.ide.extension.ElementStartContext; import javax.ide.extension.ElementVisitor; import javax.ide.extension.ExtensionHook; import javax.ide.extension.spi.ExtensionVisitor; import javax.ide.extension.spi.ListenerInfo; import javax.ide.util.MetaClass; /** * Hook for documents. */ public class DocumentHook extends ExtensionHook { public final static ElementName ELEMENT = new ElementName( ExtensionHook.MANIFEST_XMLNS, "document-hook" ); private final static ElementName DOCUMENTS = new ElementName( ExtensionHook.MANIFEST_XMLNS, "documents" ); private final static ElementName BY_SUFFIX = new ElementName( ExtensionHook.MANIFEST_XMLNS, "by-suffix" ); private final static ElementName SUFFIX = new ElementName( ExtensionHook.MANIFEST_XMLNS, "suffix" ); private final static ElementName BY_XML_ROOT = new ElementName( ExtensionHook.MANIFEST_XMLNS, "by-xml-root" ); private final static ElementName BY_XML_DOCTYPE = new ElementName( ExtensionHook.MANIFEST_XMLNS, "by-xml-doctype" ); private final static ElementName ROOT_ELEMENT = new ElementName( ExtensionHook.MANIFEST_XMLNS, "root-element" ); private final static ElementName DOCTYPE = new ElementName( ExtensionHook.MANIFEST_XMLNS, "doctype" ); private final static ElementName BY_RECOGNIZER = new ElementName( ExtensionHook.MANIFEST_XMLNS, "by-recognizer" ); private final static ElementName LISTENERS = new ElementName( ExtensionHook.MANIFEST_XMLNS, "listeners" ); private final static ElementName DOCUMENT_LISTENER = new ElementName( ExtensionHook.MANIFEST_XMLNS, "document-listener" ); private final static ElementName PROPERTY_LISTENER = new ElementName( ExtensionHook.MANIFEST_XMLNS, "property-listener" ); private final ElementVisitor _documentsVisitor = new DocumentsVisitor(); private final ElementVisitor _bySuffixVisitor = new BySuffixVisitor(); private final ElementVisitor _byXMLRootVisitor = new ByXMLRootVisitor(); private final ElementVisitor _byXMLDocTypeVisitor = new ByXMLDocTypeVisitor(); private final ElementVisitor _byRecognizerVisitor = new ByRecognizerVisitor(); private final ElementVisitor _rootElementVisitor = new RootElementVisitor(); private final ElementVisitor _docTypeVisitor = new DocTypeVisitor(); private final ElementVisitor _suffixVisitor = new SuffixVisitor(); private final ElementVisitor _listenersVisitor = new ListenersVisitor(); private final List _documentListeners = new ArrayList(); private final List _propertyListeners = new ArrayList(); private final List _suffixRecognizers = new ArrayList(); private final List _xmlRecognizers = new ArrayList(); private final List _customRecognizers = new ArrayList(); private final static String KEY_CURRENT_SUFFIX_RECOGNIZER = "currentSuffixRecognizer"; public Collection getDocumentListeners() { return Collections.unmodifiableCollection( _documentListeners ); } public Collection getSuffixRecognizers() { return Collections.unmodifiableCollection( _suffixRecognizers ); } public Collection getXMLRecognizers() { return Collections.unmodifiableCollection( _xmlRecognizers ); } public Collection getCustomRecognizers() { return Collections.unmodifiableCollection( _customRecognizers ); } public void start( ElementStartContext context ) { context.registerChildVisitor( DOCUMENTS, _documentsVisitor ); context.registerChildVisitor( LISTENERS, _listenersVisitor ); } private class DocumentsVisitor extends ElementVisitor { public void start( ElementStartContext context ) { context.registerChildVisitor( BY_SUFFIX, _bySuffixVisitor ); context.registerChildVisitor( BY_XML_ROOT, _byXMLRootVisitor ); context.registerChildVisitor( BY_XML_DOCTYPE, _byXMLDocTypeVisitor ); context.registerChildVisitor( BY_RECOGNIZER, _byRecognizerVisitor ); } } private class BySuffixVisitor extends ElementVisitor { public final void start( ElementStartContext context ) { String docClass = context.getAttributeValue( "document-class" ); if ( docClass == null || (docClass=docClass.trim()).length() == 0 ) { docClass = getDefaultDocumentClassType(); if ( docClass == null ) { log( context, Level.SEVERE, "Missing attribute 'document-class'." ); return; } } MetaClass docMetaClass = createMetaClass( context, docClass ); SuffixRecognizer sr = createSuffixRecognizer( context, docMetaClass ); context.getScopeData().put( KEY_CURRENT_SUFFIX_RECOGNIZER, sr ); context.registerChildVisitor( SUFFIX, _suffixVisitor ); } protected String getDefaultDocumentClassType() { return null; } protected boolean isSuffixRequired() { return true; } public final void end( ElementEndContext context ) { SuffixRecognizer sr = getSuffixRecognizer( context ); if ( isSuffixRequired() && sr.getSuffixes().isEmpty() ) { log( context, Level.SEVERE, "Missing 'suffix' element." ); } else { registerRecognizer( context, sr ); } } protected void registerRecognizer( ElementContext context, SuffixRecognizer sr ) { _suffixRecognizers.add( sr ); } protected SuffixRecognizer createSuffixRecognizer( ElementStartContext context, MetaClass docClass ) { return new SuffixRecognizer( docClass ); } } private final SuffixRecognizer getSuffixRecognizer( ElementContext context ) { return (SuffixRecognizer) context.getScopeData().get( KEY_CURRENT_SUFFIX_RECOGNIZER ); } private final class SuffixVisitor extends ElementVisitor { public void end( ElementEndContext context ) { String text = context.getText(); if ( text == null || (text=text.trim()).length() == 0 ) { log( context, Level.SEVERE, "Must provide text content for 'suffix'." ); return; } SuffixRecognizer r = getSuffixRecognizer( context ); r.addSuffix( text ); } } private final class ByXMLRootVisitor extends BySuffixVisitor { protected boolean isSuffixRequired() { return false; } protected String getDefaultDocumentClassType() { return "javax.ide.model.xml.XMLDocument"; } protected SuffixRecognizer createSuffixRecognizer( ElementStartContext context, MetaClass docClass ) { XMLRootElementRecognizer xmlr = new XMLRootElementRecognizer( docClass ); context.registerChildVisitor( ROOT_ELEMENT, _rootElementVisitor ); return xmlr; } protected void registerRecognizer( ElementContext context, SuffixRecognizer sr ) { XMLRootElementRecognizer xmlr = (XMLRootElementRecognizer) sr; if ( xmlr.getRootElements().isEmpty() ) { log( context, Level.SEVERE, "Must specify 'root-element'." ); } else { _xmlRecognizers.add( xmlr ); } } } private final class ByXMLDocTypeVisitor extends BySuffixVisitor { protected boolean isSuffixRequired() { return false; } protected String getDefaultDocumentClassType() { return "javax.ide.model.xml.XMLDocument"; } protected SuffixRecognizer createSuffixRecognizer( ElementStartContext context, MetaClass docClass ) { XMLDocTypeRecognizer xmlr = new XMLDocTypeRecognizer( docClass ); context.registerChildVisitor( DOCTYPE, _docTypeVisitor ); return xmlr; } protected void registerRecognizer( ElementContext context, SuffixRecognizer sr ) { XMLDocTypeRecognizer xmlr = (XMLDocTypeRecognizer) sr; if ( xmlr.getDocTypes().isEmpty() ) { log( context, Level.SEVERE, "Must specify 'doctype'." ); } else { _xmlRecognizers.add( xmlr ); } } } private class RootElementVisitor extends ElementVisitor { public void start( ElementStartContext context ) { XMLRootElementRecognizer rec = (XMLRootElementRecognizer)getSuffixRecognizer( context ); String ns = context.getAttributeValue( "namespace" ); if ( ns != null && ns.trim().length() == 0 ) ns = null; String localName = context.getAttributeValue( "local-name" ); if ( localName == null || (localName = localName.trim()).length() == 0 ) { log( context, Level.SEVERE, "Missing required attribute 'local-name'." ); return; } ElementName name = new ElementName( ns, localName ); rec.addRootElement( name ); } } private class DocTypeVisitor extends ElementVisitor { public void start( ElementStartContext context ) { XMLDocTypeRecognizer rec = (XMLDocTypeRecognizer)getSuffixRecognizer( context ); String publicId = context.getAttributeValue( "public-id" ); if ( publicId != null && publicId.trim().length() == 0 ) publicId = null; String systemId = context.getAttributeValue( "system-id" ); if ( systemId != null && systemId.trim().length() == 0 ) systemId = null; XMLDocType docType = new XMLDocType( publicId, systemId ); rec.addDocType( docType ); } } private class ByRecognizerVisitor extends ElementVisitor { public void start( ElementStartContext context ) { String recClass = context.getAttributeValue( "recognizer-class" ); if ( recClass == null || (recClass=recClass.trim()).length() == 0 ) { log( context, Level.SEVERE, "Missing required attribute 'recognizer-class'." ); return; } MetaClass recMetaClass = createMetaClass( context, recClass ); _customRecognizers.add( recMetaClass ); } } private final class ListenersVisitor extends ElementVisitor { public void start( ElementStartContext context ) { context.registerChildVisitor( DOCUMENT_LISTENER, new AbstractListenerVisitor() { protected void listenerInfo( ElementContext context, ListenerInfo info ) { _documentListeners.add( info ); } } ); context.registerChildVisitor( PROPERTY_LISTENER, new AbstractListenerVisitor() { protected void listenerInfo( ElementContext context, ListenerInfo info ) { _propertyListeners.add( info ); } } ); } } private abstract class AbstractListenerVisitor extends ElementVisitor { public final void start( ElementStartContext context ) { String listenerClass = context.getAttributeValue( "listener-class" ); if ( listenerClass == null || (listenerClass=listenerClass.trim()).length() == 0) { log( context, Level.SEVERE, "Missing required attribute 'listener-class'." ); return; } String sourceClass = context.getAttributeValue( "source-class" ); ListenerInfo info = new ListenerInfo(); info.setListenerClass( createMetaClass( context, listenerClass ) ); info.setSourceID( sourceClass ); listenerInfo( context, info ); } protected abstract void listenerInfo( ElementContext context, ListenerInfo info ); } private MetaClass createMetaClass( ElementContext context, String className ) { ClassLoader classLoader = (ClassLoader) context.getScopeData().get( ExtensionVisitor.KEY_CLASSLOADER ); return new MetaClass( classLoader, className ); } }