Access Keys:
Skip to content (Access Key - 0)

Diary of a FishEye Hacker

Well I decided that seen as nobody else outside of Atlassian has yet braved the challenge of FishEye plugin writing, I thought that I would give it a go. Here's a rather crude guide to how I did.

Day 1

Step 1 - Decide on a plugin to write

This is much harder than I originally anticipated ... at least finding a useful one is! Confluence does general information, JIRA does issues/workflows and Bamboo does cause & effect - each of these products can be abused to do various things that they weren't originally intended to.

We've made Confluence a website and JIRA a time manager – Bamboo has also been extended by others into a repository manager which tags & releases successful builds. Unfortunately FishEye is a far more focussed tool - one that was significantly enhanced by Crucible, leaving the scope for extensions somewhat limited; aside from the academic exercise of trying creating plugins.

Anyway, I eventually settled on a reporting plugin which provides a framework for alternative views on the repository data. For example: compare the commit ratio's of the various members of a group of a period of time - by size and by quantity.

Step 2 - Creating the shell

My first POM was essentially my standard Confluence POM but stripped back to to just the servlet-api and junit dependencies - I then manually add in the jar's from the fisheye distribution to enable compilation from within the IDE, however this is far from perfect.

Then Jonathan Nolen pointed me at a more useful one, and then I found another:

Both of these use FishEye 1.4.2, and I'm needing to compile against v1.5.1. After a quick word via Jonathan we now have 1.5.1 here: https://maven.atlassian.com/public/com/atlassian/fisheye/fisheye-jar/1.5.1/

Step 3 - Understand the API

Well, at least try to begin to understand the API so that I can start to produce something more useful than a Hello World! So I went on the hunt for the information that I needed to be able to write a plugin to do anything useful, that is:

  1. Static APIs in the JavaDoc
  2. Documentation about the component architecture (spring) and the components available
  3. Real-world examples of the modules being used
  4. Source to get me going when I needed to delve a little deeper

Unfortunately, the javadoc was sparse to say the least - certainly nothing in there that was any use.

Day 2

Step 4 - Debugging FishEye plugins

If you add the following to the bin/run.sh file it will cause it to listen on port 5005 for a debugger, allowing you to connect your IDE:

export FISHEYE_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"

Step 5 - Blood, Sweat and Beers

Well, working with FishEye isn't exactly a holiday; in fact it's quite the opposite as it's enough to drive to (more) drink - so to help, here are a few notes that I've got from working with it for a while:

Static APIs & Spring

  1. AppConfig.getsConfig() gets you the RootConfig object which contains the system configuration, including the repository details.
  2. You can get hold of Spring components with the @Autowired annontation, you can also use a standard setter.

There isn't any Java source available, even to commercial licensees - this causes problems when it comes to finding out what you can do. With a good IDE, a reasonable debugger and a large helping of luck/experience you can mitigate this – although you will find your swear jar filling at an alarming rate!

Plugin State Aware
Servlet, RPC & Spring Component modules don't have the StateAware methods called on enable/disable. To be more specific, none of them are called. The best I've found you can get so far, is to call enabled() from the constructor method:

public class MyServlet extends HttpServlet implements StateAware {

	public HelloWorldServlet() {
    	enabled();
	}

	// Implementation of API: StateAware
	
}

This is like building a house of cards I agree, and I appeal to the FishEye developers to have the StateAware interface respected like it is in Confluence.

WebWork & XWork Hacking
I've hacked around through APIs many times before, and David Peterson came up with the Confluence [Conveyor library] which is an elegant way of overriding actions. So my thoughts turned to attempting the following:

  1. Override an action, just to replace the result (and hopefully serve the resulting JSP from inside the plugin).
  2. Create a new action which has the same look and feel as the rest of FishEye
  3. Look at linking it in via the user interface dynamically

Man - what have I let myself in for? ... Well after a day of hacking ... hell! I've had to seriously overhaul the Conveyor library, and effectively turn it inside out. However I now have the ability to add my own actions!

Brilliant ... unfortunately the result files (*.jsp / *.vm) still need to be sourced from the root classloader (i.e. you have to put them in the content directory of the webapp). I spent a few hours digging into hacking up the velocity classloader on the fly, but it just doesn't make sense ... instead you will want to copy Confluence by adding something like this to velocity.properties:

# Plugin subsystem
resource.loader=wwfile,wwclass,confplugin

# dynamic plugin classpath loader (for plugin resources)
confplugin.resource.loader.description=Confluence Dynamic Plugin classpath loader
confplugin.resource.loader.class=com.atlassian.velocity.DynamicPluginResourceLoader

# set caching on for resource loaders (see com.opensymphony.webwork.views.velocity.VelocityManager)
# comment in these lines to add template caching (faster)
wwfile.resource.loader.cache=true
wwclass.resource.loader.cache=true
confplugin.resource.loader.cache=true

The class file will look something like this (although it will need to get the pluginAccessor from Spring another way, as ContainerManager doesn't exist):

public class DynamicPluginResourceLoader extends ResourceLoader
{
    private PluginAccessor pluginAccessor;

    public void init(ExtendedProperties extendedProperties)
    {
        // do nothing
    }

    public InputStream getResourceStream(String name) throws ResourceNotFoundException
    {
        while (name.startsWith("/") && name.length() > 1)
            name = name.substring(1);

        if (pluginAccessor == null)
        {
            pluginAccessor = (PluginAccessor) ContainerManager.getComponent("pluginAccessor");

            if (pluginAccessor == null)
                throw new ResourceNotFoundException("No plugin manager.");
        }

        return pluginAccessor.getDynamicResourceAsStream(name);
    }

    public boolean isSourceModified(Resource resource)
    {
        return false; // copied from org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
    }

    public long getLastModified(Resource resource)
    {
        return 0; // copied from org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
    }
}

I've not dug into what you'd need for JSP / Freemarker result support.

Decoration ... or the lack of
Unfortunately, FishEye doesn't use sitemesh - so decorating up is more than a pain. I've settled for the fact that I'm going to have to mimic the UI and it wont just fit in automatically. Sitemesh will also open the door to theme plugins.

Step 6?

I'm going to try and figure out how the charting stuff works in FishEye and replicate that with my own data ... that should be interesting!

We'll see how that goes.

Toggle Sidebar

Author

Archives

  1. 2010
    1. November
    2. October
  2. 2009
    1. May
    2. April
    3. March
  3. 2008
    1. November
    2. October
    3. August
    4. June
    5. May
    6. April
    7. March

Blogroll

  1. May 07, 2008

    Ross Rowe says:

    Hi Dan, I've been going through similar pain when I've been trying to use the Cr...

    Hi Dan, I've been going through similar pain when I've been trying to use the Crucible API. I've found that JD-GUI (http://jd-gui.emmanuel-dupuy.qarchive.org/) was a huge help in decompiling the source code - it supports Java 5 so I could what the annotations in each class were.

    I was half thinking of having a crack at adding Clearcase support in for Fisheye, but it looks like it'd be a largeish task...it'd be nice to see some of the plugin hooks that the other Atlassian apps have provided to make their way into Fisheye/Crucible.

    Cheers,

    Ross

    1. May 08, 2008

      Dan Hardiker says:

      I've avoided decompiling where-ever possible as that violates the EULA. I've had...

      I've avoided decompiling where-ever possible as that violates the EULA. I've had clearance from Atlassian to do what is necessary to find out the pitfalls - but I've wanted to stick with what I can as much as possible.

      My main motive for developing for FishEye was to figure out what was possible and push the boundaries. If the plugin system had just a few days of TLC it would have halved the number of classes in my plugin, and reduced by about 80% the number of lines.

      BTW: I used the JAD plugin for IntelliJ IDEA, but that doesn't support annotations (at least not the version I was using). I'll have a look at JD-GUI.

  2. Nov 05, 2008

    Tom Davies says:

    Hi Dan – we are improving a lot of the documentation around writing plugin...

    Hi Dan – we are improving a lot of the documentation around writing plugins, but it will be some time before we support xwork action plugin modules. Note that Confluence servlets are not StateAware, according to the docs: http://confluence.atlassian.com/display/DOC/Making+your+Plugin+Modules+State+Aware

Adaptavist Theme Builder Powered by Atlassian Confluence