Creating dynamic documentation plugins for the Eclipse Help System using Java

Eclipse documentation plug-ins can contain Java for creating dynamic content. You can extend the Eclipse help system by taking advantage of the org.eclipse.help.contentProducer extension point. The examples in this article demonstrate how to create a simple template that is parsed at run time to display dynamic text.

Skill level: intermediate

You can download the sample project that provides a simple framework for getting started with your own plug-in. If you have a basic level of Java programming experience or experience with other programming languages, you should be able to understand the concepts and examples.

Getting Started

This article assumes that you are using Eclipse 3.5 IDE for Java EE Developers (Galileo), but you can use other versions if they contain the Plugin Development Environment (PDE). The screenshots and steps might differ for other versions.

  1. Extract the Eclipse ZIP file and launch the Eclipse executable.
  2. Download the sample Eclipse project for a dynamic documentation plugin.
  3. Import the zip file as an archived project: File->Import->Existing Projects into Workspace. Choose the Select archive file option and browse to the downloaded sample project zip file.Displays a screen shot of the options for importing an archived project into the Eclipse workspace
  4. Click Finish and the project com.mrscripter.dynamicsample.doc will be added to your workspace and available for browsing within the Project Explorer view.

This sample provides a basic example of producing dynamic content using Java and Eclipse extension points.

Run the sample project

When you build the project, the compiled version of the plug-in will go into your eclipse/plugins directory so that you can test the dynamic content in the Eclipse help system.

  1. Right-click the project folder in the Project Explorer view and select Export.
  2. Select Plug-in Development->Deployable plug-ins and fragmentsExporting the plugin compiles the Java source and makes it available to the Eclipse environment
  3. In the export destination area, choose the Directory option and select the directory that you previously extracted your Eclipse download. You should select the folder that contains your eclipse.exe file. The export wizard creates the output jar file in the plugins subfolder, for example: C:\my_dir\eclipse\plugins\com.mrscripter.dynamicsample.doc_1.0.0.jar.

  4. Restart Eclipse to register this new plugin with the help system.

  5. After Eclipse restarts, click Help->Help Contents to display the help system.

In the help system, you will see a top-level navigation entry titled “Dynamic Documentation Sample.” Each table of contents entry within this section links to what appears to be different files; however, the contentProducer extension designates the HelloDynamicWorld class as the responder for all content requests. Each table of contents link uses a different query string title parameter that the HelloDynamicWorld class uses to populate in the text for the title and body.

The following sections explain in more detail how the plug-in works. If you have a good understanding of Java, you might choose to explore the source code at your own pace.

If you modify the plug-in code, you must re-export and restart Eclipse each time that you would like to view the results of the change.

Dissecting the plugin

The plugin.xml file contains directions that allow the Eclipse runtime environment to understand how to process the files contained within a directory or JAR file that is in the plugins directory. These instructions take the form of extensions and extension points.

The org.eclipse.help.contentProducer extension point is the key to creating dynamic output. You add this extension point to your plugin.xml and register a content producer by specifying the name of the Java class that you want to control the dynamic processing:

<extension
   id="com.mrscripter.dynamicsample.doc"
   name="Dynamic documentation sample plugin"
   point="org.eclipse.help.contentProducer">
     <contentProducer producer="HelloDynamicWorld"/>
 </extension>

Content producer

In the sample project, the content producer extension points to the HelloDynamicWorld class. This class must extend the IHelpContentProducer interface and provide the required getInputStream method, which allows the plugin to send its content to the browser:

public InputStream getInputStream(String pluginID, String href, Locale locale)

You return an InputStream from your own Java class to Eclipse for display. An InputStream is a byte representation of your text.

The HelloDynamicWorld.java class contains two important methods: getInputStream and createMyDynamicOutput.

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.net.URL;
import java.util.Locale;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.help.IHelpContentProducer;
import org.osgi.framework.Bundle;

public class HelloDynamicWorld implements IHelpContentProducer{

    private static Bundle bundle = Platform.getBundle("com.mrscripter.dynamicsample.doc");
    private static Path path = new Path("template/template.html");
    private static URL url = Platform.find(bundle, path);
    private static File templateFile=null;
    private static StringBuffer templateBuffer=null;

	public InputStream getInputStream(String pluginID, String href, Locale locale) {
		InputStream is = null;
		String title = QueryStringHelper.getValue(href,"title");
	      try{
	          return createMyDynamicOutput(href,title);
	      }
	      catch(Exception e){
	          e.printStackTrace();
	      }
	      return is;
	}

	private InputStream createMyDynamicOutput(String href, String title) throws Exception{
	    try{
        	templateBuffer = new StringBuffer();
        	templateFile = new File(FileLocator.toFileURL(url).getFile());
                BufferedReader in = new BufferedReader(new FileReader(templateFile));
                String s=null;
                while((s = in.readLine()) != null){
            	    templateBuffer.append(s);
                }
            }
            catch(Exception e){
                System.out.println(e.getMessage());
                e.printStackTrace();
            }

	    String tempOut = templateBuffer.toString().replaceAll("%TITLE%", title);
	    return new ByteArrayInputStream(tempOut.toString().getBytes("UTF-8"));
	}
}

The typical HelloWorld application is not dynamic so the sample project adds a little more code to demonstrate changing the output based on some simple input.  This sample looks for a query string parameter named “title” and gets the value of the parameter and then inserts that value into a template response. The result is returned as an InputStream for passing back to Eclipse for further processing prior to rendering.

The URL that is called is http://…../help/topic/com.mrscripter.dynamicsample.doc/something.html?title=Testing+A+Title. The content producer class intercepts all URL requests for the plug-in. You can change something.html to any name and it will still work as long as you provide the title in the querystring.

If you request a URL with an extension other than .html, some browsers won’t display the result as HTML but rather as plain text because our sample does not adjust the response type in the response header.

Template

The sample project includes a simple template file that uses basic %variable% replacement. The getInputStream method uses the QueryStringHelper class to read the title parameter from the querystring and pass the title parameter to the createMyDynamicOutput method. The createMyDynamicOutput method reads the template file to a string buffer, templateBuffer. All instances of %title% within the template/template.html file are replaced title parameter.  The string is converted into a UTF-8 encoded ByeArrayInputStream and returned to Eclipse for display.

Expanding on the HelloDynamicWorld sample

The sample project demonstrates how documentation plug-s that run within the context of the Eclipse help system or in the Eclipse information center mode can response to dynamic input from a user. The org.eclipse.help.contentProducer extension point provides the ability to create a more dynamic and response help system. New content producers could include remote content from feed, local content or external information. For example, you could integrate your online Knowledge base contents directly into your help contents to provide in-context support documents.

Ideas for implementations

For corporations that author their help content in DITA-XML, instead of using a build framework such as the DITA Open Toolkit, they could instead render DITA content dynamically on-the-fly and produce targeted content based on metadata about a users configuration or environment to create custom documentation.

Using the contentProducer as a proxy, you can eliminate the cross-domain communication limitation that Javascript frameworks face. You could query and retrieve remote content and display within your help system. You could generate a dynamic XML table of contents based on content hosted on your own website, but users would be able to see it locally on their workstations. This approach can enable a push model for some content.

2 thoughts on “Creating dynamic documentation plugins for the Eclipse Help System using Java

  1. Great article! I found it very interesting. I always wondered how this extension point might be used. Great that you provided some examples. Any ideas on how this might be integrated with indexing and search?

  2. Thanks David. By integration with the search functions, do you mean the content that is returned or created? I hadn’t yet thought about that, but obviously its important as more and more people navigate by search rather than browsing.

    I did a quick test and without any changes the search did not find the dynamic topics based on just their navigation entries. From experience, it seems that only files that are contained in navigation maps get included in the indexing so I thought there might have been a chance. One thing I also noticed that might relate to the issue, is that the dynamic topics do not pick up the breadcrumbs.

    I’m just getting started with this myself and will probably post more real world examples in the future. I’ll definitely add this to my list of things to look into.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>