|
|
|
org.netbeans.api.editor.mimelookup
org.netbeans.spi.editor.mimelookup
MIME Lookup defines MimeLookupAPI.
API contains only one classMimeLookup
with public methods:
static MimeLookup getMimeLookup(String mime)
- gets mime specific lookup MimeLookup childLookup(String mime)
- gets mime specific child (embeded) lookup Object lookup(Class clazz)
- Look up an object matching a given interface. Result lookup(Lookup.Template template)
- The general lookup method. Callers can get list of all instances and classes
that match the given template
and attach a listener to
this be notified about changes. MimeLookup
is represented via ProxyLookup that collects registered lookups. Particular lookups,
responsible for looking up their objects can be registered using interface MimeLookupInitializer
into default lookup
by META-INF/services registration.
In addition to this basic registration, xml layer folder registration is also available.
It is provided by registering implemented interface Class2LayerFolder
into default lookup
via META-INF/services registration.
This approach provides a mapping of class to specific subfolder.
Using this mapping one can achieve the convenient way of using MimeLookup
i.e.
MimeLookup.getMimeLookup("text/x-java").lookup(FoldManagerFactory.class);
Using this, an instance of FoldManagerFactory is retrieved from the folder with path
"Editors/text/x-java/FoldManager" provided that FoldManagerFactory.class is registered to
a subfolder "FoldManager" via Class2LayerFolder
registration.
InstanceProvider
can be used if there are files
of various types in the layer folder that need additional handling
before becoming and instance of certain class.
For more details look at use case of PopupActions creation.
The Javadoc documentation can be generated by using
cd /cvs/editor/mimelookup ant javadocQuestion (arch-usecases): Describe the main use cases of the new API. Who will use it under what circumstances? What kind of code would typically need to be written to use the module? Answer:
org.netbeans.spi.editor.fold.FoldManagerFactory
classes)
in the Editors/<mime-type>/FoldManager layer folder.
org.netbeans.spi.editor.completion.CompletionProvider
classes)
in the Editors/<mime-type>/CompletionProviders layer folder.
org.openide.util.Lookup
allowing to provide
the registered instances as a Lookup.Result
allowing to listen for changes (e.g. caused by the module enabling/disabling).
class MimeLookup extends Lookup
containing
static MimeLookup getMimeLookup(String mimeType)
.
MimeLookup childLookup(String mimeType)
method in MimeLookup
.
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java");
can be used for getting the mime specific lookup. Having this we can lookup class
or template:
Object obj = lookup.lookup(LookedUpClass.class);
or
Lookup.Result result = lookup.lookup(new Lookup.Template(LookedUpClass.class));
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-jsp").childLookup("text/x-java");
<filesystem> <folder name="Editors"> <folder name="text"> <folder name="x-java"> <file name="org-netbeans-modules-editor-mimelookuptest-MimeSpecificObject.instance"/> </folder> </folder> </folder> </filesystem>Lookup of this object will look like:
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java"); MimeSpecificObject mso = (MimeSpecificObject) lookup.lookup(MimeSpecificObject.class);
Class2LayerFolder
.
Let's register FoldManagerFactory.class to FoldManager folder.
First we need to implement the interface:
public class FoldManagerClass2LayerFolder implements Class2LayerFolder{ public FoldManagerClass2LayerFolder { } /* declaring the class */ public Class getClazz(){ return FoldManagerFactory.class; } /* assigning the declared class to folder */ public String getLayerFolderName(){ return "FoldManager"; } /* we will not support InstanceProvider */ public org.netbeans.spi.editor.mimelookup.InstanceProvider getInstanceProvider() { return null; } }Then we need to register it to default lookup via META-INF/services registration. We need to create a folder structure
META-INF/services
and place there a file org.netbeans.spi.editor.mimelookup.Class2LayerFolder
with the content FoldManagerClass2LayerFolder
having this we can register appropriate object to specific folder:
<filesystem> <folder name="Editors"> <folder name="text"> <folder name="x-java"> <folder name="FoldManager"> <file name="org-netbeans-modules-editor-MyFoldManagerFactory.instance"/> </folder> </folder> </folder> </folder> </filesystem>Lookup of this object will look like:
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java"); FoldManagerFactory foldManagerFactory = (FoldManagerFactory) lookup.lookup(FoldManagerFactory.class);or, if there should be more instances of the FoldManagerFactory:
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java"); Collection foldManagerFactories = lookup.lookup(new Lookup.Template(FoldManagerFactory.class)).allInstances();Notice, that the FoldManagerFactory object is found in "FoldManager" folder. It is not necessary for client of the API to know about some folder structure.
MimeLookup
. Implementation of MimeLookupInitializer
should be created and
registered to default lookup via META-INF/services
registration.
For details, please look at the simplified
TestMimeLookupInitializer
in mimelookup/test/unit
or LayerMimeLookupInitializer
.
InstanceProvider
and inheritance will be used together in one use case. Example of
editor context menu construction will be used. Each module can register its actions to
editor context menu via xml layer. As context menu is mime type sensitive (java editor has
different menu items than plain editor) the actions are registered into mime specific layer folders
to subfolder "Popup". When the context menu is constructing, the xml layer is scanned for the
action items located in the "Popup" subfolder of specific mime folder. In addition to
this there is inheritance mechanism used to share global actions (like Cut, Copy, Paste) over all mime
types context menus, thus not only the action items from actual mime type are considered. All
underlaying mime types are scanned also and the result is context menu with merged action items.
For example JSP scriplet context menu should be merged from action items gathered over:
MimeLookup
will solve also this embeding and the gathering of the context menu items will
looks such simply as:
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-jsp").childLookup("text/x-java"); PopupActions actions = (PopupActions) lookup.lookup(PopupActions.class); List popupActions = actions.getPopupActions();where PopupActions is implementation of
InstanceProvider
and PopupActions.class needs to be
registered to "Popup" subfolder using Class2LayerFolder
implementation. Let's register
this step by step.
Because action items are instances of various objects like:
InstanceProvider
needs to be created for this:
public class PopupActions implements InstanceProvider{ List ordered; public PopupActions(){ } public PopupActions(List ordered){ this.ordered = ordered; } public List getPopupActions(){ List retList = new ArrayList(); for (int i = 0; i<ordered.size(); i++){ DataObject dob = (DataObject) ordered.get(i); InstanceCookie ic = (InstanceCookie)dob.getCookie(InstanceCookie.class); if (ic!=null){ try{ if (String.class.isAssignableFrom(ic.instanceClass()) || Action.class.isAssignableFrom(ic.instanceClass()) || SystemAction.class.isAssignableFrom(ic.instanceClass()) || JSeparator.class.isAssignableFrom(ic.instanceClass())){ Object instance = ic.instanceCreate(); retList.add(instance); } }catch(IOException ioe){ ioe.printStackTrace(); }catch(ClassNotFoundException cnfe){ cnfe.printStackTrace(); } } else{ retList.add(dob.getName()); } } return retList; } public Object createInstance(List ordered) { return new PopupActions(ordered); } }This
InstanceProvider
needs to be declared in Class2LayerFolder
implementation:
public class PopupInitializer implements Class2LayerFolder{ public PopupInitializer() { } public Class getClazz(){ return PopupActions.class; } public String getLayerFolderName(){ return "Popup"; //NOI18N } public InstanceProvider getInstanceProvider() { return new PopupActions(); } }Now, we just need to register PopupInitializer into default lookup via META-INF/services registration and the initialization is done. Question (arch-time): What are the time estimates of the work? Answer: Done. Question (arch-quality): How will the quality of your code be tested and how are future regressions going to be prevented? Answer: Unit tests are available. There are several testing areas covered:
MimeLookupTest.java
Class2LayerFolder
.
It should be found in the appropriate mime-type specific folderClass2LayerFolder
MimeLookup
is not recursive (see issue #58991 for more details)MimeLookupInitializer
creation, registration and performing a lookupMimeLookupInheritanceTest.java
MimeLookupPopupItemsChangeTest.java
These modules are required in project.xml file:
OpenIDE-Module-Module-Dependencies: org.netbeans.modules.editor.mimelookup/1 > 1.3.22
MimeLookup
java.io.File
directly?
Answer:
Only in tests.
Question (resources-layer):
Does your module provide own layer? Does it create any files or
folders in it? What it is trying to communicate by that and with which
components?
Answer:
Yes.
Editors
-
MimeLookup
module creates folder "Editors" in default layer filesystem since
all mime types folders are expected to be located in this folder.
Question (resources-read):
Does your module read any resources from layers? For what purpose?
Answer:
Yes.
EditorsMimeTypes
-
LayerMimeLookupInitializer
gathers all mime type sensitive lookupable objects from
Editors[/<mime-type>][/<specific-subfolder>]
and expose them over layer MimeLookup.
Question (resources-mask):
Does your module mask/hide/override any resources provided by other modules in
their layers?
Answer:
No.
org.openide.util.Lookup
or any similar technology to find any components to communicate with? Which ones?
Answer:
Yes.
org.netbeans.api.editor.mimelookup.MimeLookup
-
in API extends Lookup and it searches the default lookup for instances of
MimeLookupInitializer
.
org.netbeans.modules.editor.mimelookup.LayerMimeLookupInitializer
-
searches default lookup for instances of Class2LayerFolder
.
Question (lookup-register):
Do you register anything into lookup for other code to find?
Answer:
Yes.
org.netbeans.spi.editor.mimelookup.MimeLookupInitializer
-
is registered via META-INF/services and is looked up by MimeLookup
.
org.netbeans.spi.editor.mimelookup.Class2LayerFolder
-
is registered via META-INF/services and is looked up by LayerMimeLookupInitializer
.
Question (lookup-remove):
Do you remove entries of other modules from lookup?
Answer:
No.
System.getProperty
) property?
Answer:
No.
Question (exec-component):
Is execution of your code influenced by any (string) property
of any of your components?
Answer:
No.
Question (exec-ant-tasks):
Do you define or register any ant tasks that other can use?
Answer:
No.
Question (exec-classloader):
Does your code create its own class loader(s)?
Answer:
No.
Question (exec-reflection):
Does your code use Java Reflection to execute other code?
Answer:
No.
Question (exec-privateaccess):
Are you aware of any other parts of the system calling some of
your methods by reflection?
Answer:
No.
Question (exec-process):
Do you execute an external process from your module? How do you ensure
that the result is the same on different platforms? Do you parse output?
Do you depend on result code?
Answer:
No.
Question (exec-introspection):
Does your module use any kind of runtime type information (instanceof
,
work with java.lang.Class
, etc.)?
Answer:
No.
Question (exec-threading):
What threading models, if any, does your module adhere to?
Answer:
No special threading models used.
Question (security-policy):
Does your functionality require modifications to the standard policy file?
Answer:
No.
Question (security-grant):
Does your code grant additional rights to some other code?
Answer:
No.
java.awt.datatransfer.Transferable
?
Answer:
No clipboard support.
MimeLookup
delegates to ProxyLookup performance
during lookup depends on the performance of ProxyLookup. LayerMimeLookupInitializer
instantiates
the object found in the layer only during direct lookup of the particular class using LazyLookup (inner class defined in LayerMimeLookupInitializer
).
Question (perf-limit):
Are there any hard-coded or practical limits in the number or size of
elements your code can handle?
Answer:
No limits.
Question (perf-mem):
How much memory does your component consume? Estimate
with a relation to the number of windows, etc.
Answer:
MimeLookup
caches instances of mime sensitive MimeLookups in static Map, instances of children
MimeLookups in Map, InitializerListeners and Initializers in Lists.
LayerMimeLookupInitializer
also caches mime sensitive LayerMimeLookupInitializers and LazyLookups.
Question (perf-wakeup):
Does any piece of your code wake up periodically and do something
even when the system is otherwise idle (no user interaction)?
Answer:
No.
Question (perf-progress):
Does your module execute any long-running tasks?
Answer:
No.
Question (perf-huge_dialogs):
Does your module contain any dialogs or wizards with a large number of
GUI controls such as combo boxes, lists, trees, or text areas?
Answer:
No.
Question (perf-menus):
Does your module use dynamically updated context menus, or
context-sensitive actions with complicated and slow enablement logic?
Answer:
No.
Question (perf-spi):
How the performance of the plugged in code will be enforced?
Answer:
Pluggins are just clients lookups that are installed into MimeLookup
. The performance
should be influenced by the lookupable object gathering by clients lookups. LayerMimeLookupInitializer
(client lookup provided by mimelookup module)
provides a LazyLookup, it instantiates the object found in the layer only
during direct lookup of the particular class.
Otherwise performance should be similar as ProxyLookup.
Built on May 28 2007. | Portions Copyright 1997-2005 Sun Microsystems, Inc. All rights reserved.