Child pages
  • Making Structure Dependency Optional

This documentation relates to an older version 1.5 of the Structure Plugin for JIRA. View the current documentation home.

Skip to end of metadata
Go to start of metadata

If you are integrating your plugin with Structure, or when you generally write code that uses Structure API but also should work when Structure Plugin is not present, you need to declare that dependencies are optional and isolate dependencies in the code.

1. Declare Optional Dependency

Since your plugin must first be loaded as an OSGi bundle, it should declare dependencies from the Structure API packages as optional.

Modify <Import-Package> declaration in your pom.xml or atlassian-plugin.xml and add resoltion:=optional classifier. (Add Import-Package to control API compatibility if you don't have this declaration yet.)

<Import-Package>
  com.almworks.jira.structure*;version="[3.4,4)";resolution:=optional,
  com.almworks.integers*;version="0";resolution:=optional,
  org.jetbrains.annotations;version="0";resolution:=optional
</Import-Package>

2. Isolate Dependencies in the Code

So once you have declared the optional resolution of the Structure API classes, your bundle will load - but if your code tries to access a class from the Structure API, you'll get a NoClassDefFoundError. To avoid that, you need to isolate the dependency on Structure API classes - typically in some wrapper classes.

This is also a point to make design decisions. So your code can use Structure when it's present, and can work independently when Structure is not there. Are there any abstractions that address both of these situation? What are the concepts that are realized through Structure API and through some other means when Structure is not avialable?

Here's a sample wrapper for the Structure API that provides ForestAccessor wrapper (whatever it does) when Structure is available and null otherwise.

public class StructureAccessor {
  public static boolean isStructurePresent() {
    if (!ComponentAccessor.getPluginAccessor().isPluginEnabled("com.almworks.jira.structure")) {
      return false;
    }
    try {
      Class.forName("com.almworks.jira.structure.api.StructureManager");
    } catch (Exception e) {
      return false;
    }
    return true;
  }

  public static ForestAccessor getForest(long structureId, User user) {
    if (!isStructurePresent()) return null;
    StructureManager structureManager;
    try {
      structureManager = ComponentManager.getOSGiComponentInstanceOfType(StructureManager.class);
    } catch (Exception e) {
      return null;
    }
    // check user permissions
    if (!structureManager.isAccessible(structureId, user, PermissionLevel.VIEW, false)) {
      return null;
    }
    Forest forest = null;
    try {
      forest = structureManager.getForest(structureId, user, false);
    } catch (StructureException e) {
      return null;
    }
    return new ForestAccessor(forest);
  }
}
  • No labels