Robert (Bob) Brodt [
http://community.jboss.org/people/bbrodt] modified the document:
"Eclipse File Content Types"
To view the document, visit:
http://community.jboss.org/docs/DOC-15183
--------------------------------------------------------------
h1. The Big Picture
http://community.jboss.org/servlet/JiveServlet/showImage/2580/soup.jpg
http://community.jboss.org/servlet/JiveServlet/downloadImage/2580/57-97/s... When you
pick up a can of soup and the label reads “TOMATO SOUP”, you expect tomato soup to be
inside, right? What if soup manufacturers all decided not to label their products and
simply used generic containers with the label “SOUP”? One could argue that even if the
soup cans were clearly labeled, who's to say that what's inside really is TOMATO
SOUP? The only way to be absolutely certain is to open the can and peek inside!
Since the dawn of MS-DOS, file name extensions have been used, much like soup can labels,
to identify file contents and, typically which application is associated with that file.
Eclipse has been following this same tried-and-true philosophy to launch the proper editor
or viewer plugin when you double-click on a resource in the eclipse Navigator. But with
the proliferation of XML formats that describe everything from
http://graffitianalysis.com/gml/ graffiti to
http://xml.coverpages.org/geml.html DNA
patterns, the file name extension “XML” has become somewhat ambiguous. OK, we know
it's SOUP but what *kind* of SOUP?
That's essentially the idea behind the eclipse
http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc....
content-type extension point. When the eclipse workbench opens a folder resource for the
first time, it looks at the folder's contained IFile resources and then all plugins
that contribute to this extension point are allowed to “peek inside the can” to see if it
contains a SOUP that they can consume. The extension point then provides an ID which is is
associated with the IFile and cached by the workbench. If the name of the IFile changes,
the workbench goes through the same content type checking again.
As you can imagine, the time it takes for the workbench to run through this process
increases (roughly) with the number of plugins that contribute to content-type multiplied
by the number of files in your projects. So, as a plugin developer you need to ensure that
content type checking is as fast as possible: peek inside the can, take a quick sniff and
move on; don't grab a spoon and try to take a taste!
h1. The Details
If you have been around eclipse long enough you probably already know that the SDK
documentation was written by Captain Obvious and is of little help when you're trying
figure out how to do something that should be so...simple. Case-in-point:
h2. Package org.eclipse.core.runtime.content
Provides core support for content types.
*See:*
http://help.eclipse.org/help32/topic/org.eclipse.platform.doc.isv/referen...
*Description*
|| %1,2% *Interface Summary* ||
| *IContentDescriber*
(
http://help.eclipse.org/help32/topic/org.eclipse.platform.doc.isv/referen...)
| Content describers describe contents. |
| *IContentDescription*
(
http://help.eclipse.org/help32/topic/org.eclipse.platform.doc.isv/referen...)
| A description for content. |
| *IContentTypeManager*
(
http://help.eclipse.org/help32/topic/org.eclipse.platform.doc.isv/referen...)
| Content type managers manage content types. |
|| %1,2% *Class Summary* ||
| *BinarySignatureDescriber*
(
http://help.eclipse.org/help32/topic/org.eclipse.platform.doc.isv/referen...)
| A describer for binary signatures. |
| *XMLRootElementContentDescriber*
(
http://help.eclipse.org/help32/topic/org.eclipse.platform.doc.isv/referen...)
| A content describer for XML root elements. |
Luckily there are a lot of folks out there doing amazing work with eclipse and publishing
their experiences. I just wanted to give something back by describing the steps I took to
add this feature to the eclipse
http://eclipse.org/bpel/ BPEL editor.
The “org.eclipse.ui.editors” extension point in your plugin.xml probably looks something
like this:
<extension
point="org.eclipse.ui.editors">
<editor
class="org.eclipse.bpel.ui.BPELMultipageEditorPart"
default="true"
*extensions=**"bpel"*
*icon=**"icons/obj16/bpel.gif"*
id="org.eclipse.bpel.ui.bpeleditor"
name="%BPEL_EDITOR_NAME">
</editor>
</extension>
There are a couple of things wrong with this if you intend to do content type checking:
first, do not specify file extensions here since this defeats the purpose of the
content-type extension point; second, do not specify an icon for your editor here either,
since the workbench will slap this decorator on all files based on their file extension
instead of their content. Instead, replace these attributes with the following:
<extension
point="org.eclipse.ui.editors">
<editor
class="org.eclipse.bpel.ui.BPELMultipageEditorPart"
default="true"
id="org.eclipse.bpel.ui.bpeleditor"
name="%BPEL_EDITOR_NAME">
*<contentTypeBinding*
*contentTypeId=**"org.eclipse.bpel.contenttype"**>*
*</contentTypeBinding>*
</editor>
</extension>
The contentTypeBinding element references a type ID which is defined in the content-type
extension point:
<extension
point="org.eclipse.core.contenttype.contentTypes">
<content-type
base-type="org.eclipse.core.runtime.xml"
id="org.eclipse.bpel.contenttype"
name="BPEL Editor File"
file-extensions="bpel,bpel2,xml"
priority="normal">
<describer
class="org.eclipse.core.runtime.content.XMLRootElementContentDescriber2">
<parameter
name="element"
value="{http://docs.oasis-open.org/wsbpel/2.0/process/executable}pro...
</describer>
</content-type>
</extension>
I'm not going to repeat the eclipse reference documentation here, but I did want to
make a few comments.
1. Notice the file-extensions attribute is specified here, and you will still need to
provide at least one file name extension for your content type. As of eclipse 3.5.2
https://bugs.eclipse.org/bugs/show_bug.cgi?id=46297 file name extensions are still
required – you can not, for example, create an XML file that has no file name extension
and expect the XML editor to correctly recognize it based on content.
2. The eclipse framework already provides an XML root element content describer and there
are lots of examples out there that demonstrate how to use it. Note however, that a lot fo
these examples refer to the deprecated class XMLRootElementContentDescriber - you should
use XMLRootElementContentDescriber2 defined in the org.eclipse.core.runtime.content
package instead.
3. Whenever possible, provide a namespace for your root element. This will avoid possible
conflicts with other plugins. For example, I discovered (after much gnashing of teeth)
that JBoss Drools Flow editor files (*.rf files) also have a “process” root element.
The icon attribute in the org.eclipse.editors extension point should be removed and
specified in an org.eclipse.ui.decorators extension point instead, like so:
<extension
point="org.eclipse.ui.decorators">
<decorator
adaptable="true"
icon="icons/obj16/bpel.gif"
id="org.eclipse.bpel.ui.icondecorator"
label="BPEL Resource Decorator"
lightweight="true"
location="TOP_LEFT"
state="true">
<enablement>
<and>
<objectClass
name="org.eclipse.core.resources.IFile">
</objectClass>
<objectState
name="contentTypeId"
value="org.eclipse.bpel.contenttype">
</objectState>
</and>
</enablement>
</decorator>
</extension>
This will ensure that your editor's files will always display the correct icon
regardless of what the file name extension is, as long as it's one of the extensions
declared by your content-type.
The last point I wanted to discuss was EMF support for content types. As far as I can tell
this has been around since EMF 2.2.2 (possibly earlier). If your editor uses an EMF model,
you also need to contribute an EMF content parser extension point:
<extension point="org.eclipse.emf.ecore.content_parser">
<parser
class="org.eclipse.bpel.model.resource.BPELResourceFactoryImpl"
contentTypeIdentifier="org.eclipse.bpel.contenttype">
</parser>
</extension>
The resource factory is then responsible for constructing the correct XMI parser for your
EMF model.
Finally, don't forget to go through your editor code and replace all of the file name
extension checking with content type checking! For example, stuff like this:
IResource res;
*if* (res.getType() == IResource.+FILE+) {
*if* ("bpel".equalsIgnoreCase(((IFile)res).getFileExtension())) {
// load it...
}
}
should be replaced with this:
IResource res;
* if* (res.getType() == IResource.+FILE+) {
IContentDescription desc = ((IFile)res).getContentDescription();
* if* (desc != *null*) {
IContentType type = desc.getContentType();
* if* ("org.eclipse.bpel.contenttype".equals(type.getId())) {
// load it...
}
}
}
h1. Going Further
The XMLRootElementContentDescriber2 provided by eclipse should fill most of your content
type checking needs. But, if you need to drill down deeper into the XML document, you may
need to write your own custom content describer class. Keep in mind though that your
implementation should only do the absolute bare minimum required to make its determination
– for instance don't read the entire document using a DOM parser if you only need to
check a couple of elements!
Techniques that work well are to use either an
http://www.xmlpull.org/ XML pull parser or
use the SAX parser and throw exceptions to terminate parsing after the first element.
I've provided an example of my BPEL content describer using a SAX parser for your
reading enjoyment:
*public* *class* BPELContentDescriber *implements* ITextContentDescriber {
* private* *static* *final* String +WSBPEL_2_NAMESPACE+ =
"http://docs.oasis-open.org/wsbpel/2.0/process/executable"; //$NON-NLS-1$
* private* *static* *final* String +ROOT_ELEMENT+ = "process"; //$NON-NLS-1$
* private* RootElementParser parser = *new* RootElementParser();
* public* BPELContentDescriber() {
}
*public* *int* describe(Reader contents, IContentDescription description) *throws*
IOException {
*return* doDescribe(contents) == *null* ? +INVALID+ : +VALID+;
}
*public* *int* describe(InputStream contents, IContentDescription description) *throws*
IOException {
*return* describe(*new* InputStreamReader(contents), description);
}
*private* String doDescribe(Reader contents) *throws* IOException {
InputSource source = *new* InputSource(contents);
*try* {
parser.parse(source);
} *catch* (SAXException e) {
*return* *null*;
} *catch* (AcceptedException e) {
*return* e.acceptedRootElement;
} *catch* (RejectedException e) {
*return* *null*;
}
*return* *null*;
}
*public* QualifiedName[] getSupportedOptions() {
*return* *null*;
}
*private* *class* RootElementParser *extends* SAXParser {
*public* *void* startElement(QName qName, XMLAttributes attributes, Augmentations
augmentations) *throws* XNIException {
*super*.startElement(qName, attributes, augmentations);
*if* (+ROOT_ELEMENT+.equals(qName.localpart)) {
String namespace = fNamespaceContext.getURI(qName.prefix);
*if* (namespace != *null* && +WSBPEL_2_NAMESPACE+.equals(namespace))
*throw* *new* AcceptedException(qName.localpart);
*else*
*throw* *new* RejectedException();
} *else*
*throw* *new* RejectedException();
}
}
*private* *class* AcceptedException *extends* RuntimeException {
*public* String acceptedRootElement;
*public* AcceptedException(String acceptedRootElement) {
*this*.acceptedRootElement = acceptedRootElement;
}
*private* *static* *final* *long* +serialVersionUID+ = 1L;
}
*private* *class* RejectedException *extends* RuntimeException {
*private* *static* *final* *long* +serialVersionUID+ = 1L;
}
}
h1. References
http://wiki.bioclipse.net/index.php?title=Contenttypes_and_describers Contenttypes and
describers
Eclipse Tip: Define Custom Content Types to Identify Your Data Files
(
http://www.developer.com/java/other/article.php/3648736/Eclipse-Tip-Defin...)
Lessons from Behind The Curtain
(
http://cvalcarcel.wordpress.com/2009/10/25/writing-an-eclipse-plug-in-par...)
EMF Bits (
http://www.eclipticalsoftware.com/emf/#contenttype)
Eclipse Zone (
http://www.eclipsezone.com/eclipse/forums/t107605.html)
--------------------------------------------------------------
Comment by going to Community
[
http://community.jboss.org/docs/DOC-15183]
Create a new document in JBoss Tools Development at Community
[
http://community.jboss.org/choose-container!input.jspa?contentType=102&am...]