/*
* Copyright 2005 by Oracle USA
* 500 Oracle Parkway, Redwood Shores, California, 94065, U.S.A.
* All rights reserved.
*/
package javax.ide.editor.spi;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.ide.extension.ElementContext;
import javax.ide.extension.ElementName;
import javax.ide.extension.ElementStartContext;
import javax.ide.extension.ElementVisitor;
import javax.ide.extension.ExtensionHook;
import javax.ide.extension.I18NStringVisitor;
import javax.ide.extension.spi.ExtensionVisitor;
import javax.ide.util.MetaClass;
/**
* Editor information gathered from processing the editor-hook
* section of an extension manifest. The information recorded
* here describes a new editor.
*/
public final class EditorHook extends ExtensionHook
{
public static final ElementName ELEMENT = new ElementName(
MANIFEST_XMLNS, "editor-hook" );
private static final ElementName EDITORS = new ElementName(
MANIFEST_XMLNS, "editors" );
private static final ElementName EDITOR = new ElementName(
MANIFEST_XMLNS, "editor" );
private static final ElementName NAME = new ElementName(
MANIFEST_XMLNS, "name" );
private static final ElementName MAPPINGS = new ElementName(
MANIFEST_XMLNS, "mappings" );
private static final ElementName MAPPING = new ElementName(
MANIFEST_XMLNS, "mapping" );
private static final ElementName OPEN_WITH = new ElementName(
MANIFEST_XMLNS, "open-with" );
private static final ElementName LISTENERS = new ElementName(
MANIFEST_XMLNS, "editor-listeners" );
private static final ElementName EDITOR_LISTENER = new ElementName(
MANIFEST_XMLNS, "editor-listener" );
private ElementVisitor _editorsVisitor = new EditorsVisitor();
private ElementVisitor _editorVisitor = new EditorVisitor();
private ElementVisitor _mappingsVisitor = new MappingsVisitor();
private ElementVisitor _mappingVisitor = new MappingVisitor();
private ElementVisitor _openWithVisitor = new OpenWithVisitor();
private ElementVisitor _listenersVisitor = new ListenersVisitor();
private ElementVisitor _listenerVisitor = new ListenerVisitor();
private static final String KEY_DOCUMENT_CLASS = "documentClass";
private static final String KEY_OPEN_WITH_COLL = "openWithColl";
public static final String ANY_EDITOR_CLASS = "_anyListener";
private Map /**/ _editorsByClassName = new HashMap();
private Map /**/ _mappings = new HashMap();
private Map /**/ _listeners = new HashMap();
private Map /**/ _editorDisplayInfo = new HashMap();
/**
* Get the display information for the specified editor class.
*
* @param editorClass the editor class.
* @return display information for this class of editor.
*/
public DisplayInfo getDisplayInfo( MetaClass editorClass )
{
return (DisplayInfo) _editorDisplayInfo.get( editorClass );
}
/**
* Get all registered editors.
*
* @return MetaClass instances for all editor classes registered in extension
* manifests.
*/
public Collection /**/ getEditors()
{
return _editorsByClassName.values();
}
/**
* Get the editor meta class for the specified unique editor class name.
*
* @param className the editor class name.
* @return the editor meta class.
*/
public MetaClass getEditorClass( String className )
{
return (MetaClass)_editorsByClassName.get( className );
}
/**
* Get the class names of all mapped document classes.
*
* @return a collection of document class names that are mapped.
*/
public Collection /**/ getMappedDocumentClasses()
{
return _mappings.keySet();
}
/**
* Get the list of mapping infos for the specified document class. Each
* mapping info is an editor class and a value indicating whether
*
* @param documentClass the class of a document.
*
* @return the document-editor {@link MappingInfo}s. If none available,
* return an empty collection.
*/
public Collection /**/ getEditorsForDocClass( Class documentClass )
{
return (Collection)_mappings.get( documentClass.getName() );
}
/**
* Get the list of editor listeners declared in an extension
* manifest. This information records the editor listener
* classes interested in receiving events from specific editor types.
*
* @return a map of all listeners. The keys are class names of editors, the
* values are Collections of MetaClass instances for each
* listener for the corresponding editor class.
*
*/
public Map /*>*/ getListeners()
{
return _listeners;
}
public void start( ElementStartContext context )
{
context.registerChildVisitor( EDITORS, _editorsVisitor );
context.registerChildVisitor( MAPPINGS, _mappingsVisitor );
context.registerChildVisitor( LISTENERS, _listenersVisitor );
}
private class EditorsVisitor extends ElementVisitor
{
public void start( ElementStartContext context )
{
context.registerChildVisitor( EDITOR, _editorVisitor );
}
}
private class EditorVisitor extends ElementVisitor
{
public void start( ElementStartContext context )
{
String editorClass = context.getAttributeValue( "editor-class" );
if ( editorClass == null || (editorClass=editorClass.trim()).length() == 0 )
{
log( context, Level.SEVERE, "Missing required 'editor-class' attribute." );
return;
}
ClassLoader cl = (ClassLoader) context.getScopeData().get(
ExtensionVisitor.KEY_CLASSLOADER
);
final MetaClass editorMetaClass = new MetaClass( cl, editorClass );
_editorsByClassName.put( editorClass, editorMetaClass );
context.registerChildVisitor( NAME, new I18NStringVisitor() {
protected void string( ElementContext context, String text )
{
_editorDisplayInfo.put( editorMetaClass, new DisplayInfo( text ) );
}
});
}
}
private class MappingsVisitor extends ElementVisitor
{
public void start( ElementStartContext context )
{
context.registerChildVisitor( MAPPING, _mappingVisitor );
}
}
private class MappingVisitor extends ElementVisitor
{
public void start( ElementStartContext context )
{
String docClass = context.getAttributeValue( "document-class" );
if ( docClass == null || (docClass=docClass.trim()).length() == 0 )
{
log( context, Level.SEVERE, "Missing required 'document-class' attribute." );
}
else
{
context.getScopeData().put( KEY_DOCUMENT_CLASS, docClass );
List mappings = (List) _mappings.get( docClass );
if ( mappings == null )
{
mappings = new ArrayList();
_mappings.put( docClass, mappings );
}
context.getScopeData().put( KEY_OPEN_WITH_COLL, mappings );
context.registerChildVisitor( OPEN_WITH, _openWithVisitor );
}
}
}
private class OpenWithVisitor extends ElementVisitor
{
public void start( ElementStartContext context )
{
String editorClass = context.getAttributeValue( "editor-class" );
if ( editorClass == null || (editorClass=editorClass.trim()).length() == 0)
{
log( context, Level.SEVERE, "Missing required attribute 'editor-class'" );
return;
}
String isPreferred = context.getAttributeValue( "preferred" );
boolean preferred = isPreferred == null ? false : Boolean.valueOf( isPreferred ).booleanValue();
MappingInfo mi = new MappingInfo( editorClass, preferred );
List mappings = (List) context.getScopeData().get( KEY_OPEN_WITH_COLL );
mappings.add( mi );
}
}
private class ListenersVisitor extends ElementVisitor
{
public void start( ElementStartContext context )
{
context.registerChildVisitor( EDITOR_LISTENER, _listenerVisitor );
}
}
private class ListenerVisitor extends ElementVisitor
{
public void start( ElementStartContext context )
{
String sourceClass = context.getAttributeValue( "source-class" );
final String listenerClass = context.getAttributeValue( "listener-class" );
if ( listenerClass == null )
{
log( context, Level.SEVERE, "Required attribute 'listener-class' missing.");
return;
}
ClassLoader cl =
(ClassLoader) context.getScopeData().get( ExtensionVisitor.KEY_CLASSLOADER );
MetaClass mc = new MetaClass( cl, listenerClass );
if ( sourceClass == null )
{
sourceClass = ANY_EDITOR_CLASS;
}
List listeners = (List) _listeners.get( sourceClass );
if ( listeners == null )
{
listeners = new ArrayList();
_listeners.put( sourceClass, listeners );
}
listeners.add( mc );
}
}
}