Skip to content

Plugin Pattern

MEM2677 edited this page Mar 27, 2013 · 15 revisions

Developer's Guide - Plugins

The Entando path to plugins

Table of Contents

Scope of the document

The present guide introduces the Entando plugins. Starting from the 3.0 relase, Entando is a Maven project so plugin management and creation is easier than in previous versions. This guide covers the basics about plugin creation and the conventions to adopt during the creation process.

What this document is not

We won't show how to implement a new service, this is the aim of the Pattern for application services creation and integration, being aware that the only difference between developing an application service in the core of Entando and in a plugin is only marginal in that a plugin must obey to precise constraints of directories path and naming conventions.

Intended audience

This document is aimed to developers who are taking the first steps in the Entando world.
In order to take maximum advantage from the present document, it is necessary to have basic knowledge about the Java platform, the Apache Tomcat servlet engine (optionally Jetty), Ant and the PosgreSQL DBMS or MySQL.
Since Maven helps us a lot in the project management, you must have a strong understanding of what Maven is and what it does and how it manages archetypes to generate artifacts.

Prerequisites

This document assumes that reader has a a grasp on the document Pattern for application services creation and integration and a working development environment as described in Setup a Java development environment for the Entando Platform

top

Introduction

A plugin is a module which can add new features to the Entando platform or modify existing ones; they are best viewed as service, thus the principles guiding the process of writing a plugin are basically the same guiding the development of a new service, but with precise naming and path constraints.

Plugins come in two flavors:

  • PurePlugins
  • Modifications

A PurePlugin adds new services without modifying the core: one or more pure plugins may coexist at the same time in the same project without interaction and conflicts thus without affecting system stability.

On the contrary, the Modifications are the ones which either expand, substitute, or modify (from slightly to deeply) the behavior of the core elements of Entando.

In order to reduce to the minimum the risk of conflicts, the development of a Modification has to be done trying to limit the elements which interact with or modify the core; this fundamental achievement can be reached taking advantage of the elements given by the system and by the inner frameworks (like Spring and Struts2), i.e. the Event Notification service, the AOP, the Interceptors architecture which comes with Struts², and many others.

top

Plugin installation

To install an Entando community plugin basically we have to:

  • stop your servlet container (Tomcat, Jboss etc.)

  • add the plugin dependencies in the POM of the project of interest

If you are familiar with the previous version of Entando (namely, jAPS / jAPS 2.0 Entando) the current installation process is a lot easier.

Stand alone plugin

By stand alone plugin we intend a plugin that does not require any dependency to be met; for instance, we chose to install the entando-plugin-jpsurvey, whose code is jpsurvey.

Once that you have stopped the servlet container edit the POM of the project to add the dependency of the plugin. In other words you add:

    <!--
      The Plugin, with all its files and 
        entando-plugin-jpsurvey.jar in WEB-INF/lib
    -->
    <dependency>
        <groupId>org.entando.entando.plugins</groupId>
        <artifactId>entando-plugin-jpsurvey</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>war</type>
    </dependency>

You are now done!

You can:

  • mvn package to get the war
  • or Run As --> Run on Server if you use Eclipse
  • or mvn jetty:run if you prefer Jetty

You will find the plugin there.

Plugin with dependencies

The installation process is the same for those plugins which depends on others plugin: thanks to maven which handles the prerequisites and a new module introduced by Entando 3.2 which handles the database the installation is easier than ever.

top

How to start a brand new Plugin

In this use case we will create a plugin that for this occasion is named entando-plugin-jpmyspecialthingy.

We will assume that entando-plugin-jpmyspecialthingy doesn't need any other plugin to get its job done;

  • download the project plugins-parent from our Github page

  • generate a new module with the familiar mvn archetype:generate

  • use the archetype entando-archetype-plugin-generic

  • when asked for provide the following values:

    1. groupId : org.entando.entando.plugins
    2. artifactId : entando-plugin-jpmyspecialthingy
    3. package : com.mycompany.plugins.jpmyspecialthingy
    4. pluginCode : jpmyspecialthingy
    5. pluginName : My Special Thingy

We will discuss later the naming conventions, so just for now accept the default values:

That was that simple! Maven created the skeleton of our new plugin.

You may want to edit the entando-plugins-parent/pom.xml and make sure that the following line exists:

    <modules>
      .....
      <module>entando-plugin-jpmyspecialthingy</module>
      .....
    </modules>

What about plugin dependencies?

Let's say that our new shining plugin depends on jpmail: we have to manually specify this dependency in the pom.xml of jpmyspecialthingy. It's worth noting that you have to add three entries for each dependency, as shown below:

    <dependencies>
      .....
            <dependency>
                <groupId>org.entando.entando.plugins</groupId>
                <artifactId>entando-plugin-jpmail</artifactId>
                <version>${entando.version}</version><!-- version. Don't remove this comment. -->
                <type>war</type>
            </dependency>
            <dependency>
                <groupId>org.entando.entando.plugins</groupId>
                <artifactId>entando-plugin-jpmail</artifactId>
                <version>${entando.version}</version><!-- version. Don't remove this comment. -->
                <type>jar</type>
                <classifier>classes</classifier>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.entando.entando.plugins</groupId>
                <artifactId>entando-plugin-jpmail</artifactId>
                <version>${entando.version}</version><!-- version. Don't remove this comment. -->
                <type>jar</type>
                <classifier>tests</classifier>
                <scope>test</scope>
            </dependency>
      .....
        </dependencies>

Then the dependency must be declared in the component descriptor of the plugin: modify the file entando-plugin-jpmyspecialthingy/src/main/resources/component/plugins/jpmyspecialthingy/component.xml as report below:

<?xml version="1.0" encoding="UTF-8"?>
<component>
  <code>jpmyspecialthingy</code>
	<description>My special thing</description>
	<dependencies>
		<code>jpmail</code>
		<!-- other dependencies here -->
	</dependencies>
...
</component>

top

Plugin pattern

This chapter shows the general rules to follow when developing a plugin. Using the default archetype when creating a new plugin helps us by providing the correct directory layout which respects the structure of the core itself.

Let's have a look to the entando-plugin-myspecialthingy:

└── src
    ├── main
    │ ├── java
    │ │ └── com
    │ │     └── mycompany
    │ │         └── plugins
    │ │             └── jpmyspecialthingy
    │ │                 ├── aps
    │ │                 └── apsadmin
    │ ├── resources
    │ │ ├── api
    │ │ │ └── plugins
    │ │ │     └── jpmyspecialthingy
    │ │ │         └── aps
    │ │ ├── shortcuts
    │ │ │ └── plugins
    │ │ │     └── jpmyspecialthingy
    │ │ │         └── apsadmin
    │ │ └── spring
    │ │     └── plugins
    │ │         └── jpmyspecialthingy
    │ │             ├── aps
    │ │             │ └── managers
    │ │             └── apsadmin
    │ ├── sql
    │ │ ├── mysql
    │ │ └── postgresql
    │ ├── tld
    │ │ └── plugins
    │ │     └── jpmyspecialthingy
    │ └── webapp
    │     ├── resources
    │     │ └── plugins
    │     │     └── jpmyspecialthingy
    │     │         └── administration
    │     │             ├── css
    │     │             ├── img
    │     │             └── js
    │     └── WEB-INF
    │         └── plugins
    │             └── jpmyspecialthingy
    │                 ├── aps
    │                 │ └── jsp
    │                 └── apsadmin
    │                     └── jsp
    │                         └── common
    │                             └── template
    │                                 └── extraresources
    └── test
        ├── java
        │ └── com
        │     └── mycompany
        │         └── plugins
        │             └── jpmyspecialthingy
        │                 ├── aps
        │                 └── apsadmin
        ├── resources
        │ └── spring
        └── sql
            ├── mysql
            └── postgresql

If you have read the Maven standard directory layout you will find yourself comfortable with the layout above.

The src directory contains all the sources and resources of the artifact:

  • main: contains the sources organized by technology, java, in directories which are the reversed domain of your company. Sources are entirely contained in the directory matching the plugin code, inside plugins. This is to put all the artifacts of the same organization inside in the same place. The usual arrangement of the code in aps and apsadmin shouldn't surprise you.

  • resources: the resources needed by the plugin to work. They are divided in api (declaration of the web API supported), shortcuts (declaration of the shortcut available) and spring (definitions of the beans of the system services)

  • sql: contains the database update scripts either for mysql and postgres

  • tld: as for sources, TLD files are organized inside a plugins directory and grouped by plugin code

  • webapp: here are contained the web application sources. Static resources images, CSS and javascripts are grouped in resources; finally WEB-INF contains the JSP files, tiles definitions etc.

  • test: contains the sources needed to run the jUnit tests. The sub-directories have the same arrangement -when present- of the main folder, with the solely exception of webapp which doesn't exist.

Sources

If Maven worked properly – and I don't have any doubt about that – we have all the directories structure properly organized: so it's pretty obvious to organize our packages in the form of

<R_DOMAIN>.plugins.<PLUGIN_ID> where <R_DOMAIN> is the reversal of the domain name of the developer (company, association, web site, person...) of the Plugin. For myspecialthingy we should have this package com.mycompany.plugins.jpmyspecialthingy.whatever. The same apply for the test classes.

Every class should come with proper Javadoc in English for an easy understanding of the code and of the application flow. Every interface and concrete class should have the Javadoc in the head part, and for every method and public or private variable. You may also want to write some Javadoc for complex or not-so-readable private methods.

Naming conventions

The naming conventions shows how to properly name plugin components to avoid unintentional name collisions leading to the unwanted overwriting of core elements and thus to serious system problems. Once again Maven helps us a lot by generating the proper directory layout so that, following its standard directory layout, is quite natural for developers to place the various elements in their standardized positions; as result, many of the path constraints are not needed anymore starting from Entando 3.0.

A plugin is identified by a plugin code (or ID) and a plugin name: the former is the unique name used within the code and in configuration files, the latter is the human readable name used in the documentation.

For example jpmyspecialthingy is the code (or ID), “My special thingy” is the name.

The Java classes of the Plugin must be written following the coding standard of the Entando platform. They must be gathered under the package <R_DOMAIN>.plugins.<PLUGIN_ID> where <R_DOMAIN> is the reversal of the domain name of the developer (company, association, web site, person...) of the Plugin.

Example: From a domain name to a package name

Company: MyCompany.com, package: com.mycompany.plugins.<PLUGIN_ID>

The same apply for the test classes.

This syntax resembles the one defined in the Java Language Specification by Oracle.

Beans (Spring Objects) of the Plugin core

The name of the beans definition files are left to the user because, whatever their name is, they will be automatically loaded during system startup.

What must be taken care of is the name of the bean ID: it must be preceded by the plugin code. In the particular case of a Manager, the ID must be <PLUGIN_ID><SERVICE_NAME>Manager. For jpmyspecialthingy a correct name can be jpmyspecialthingyBookserviceManager.

Beans (Spring Objects) of the Actions (Struts² Objects)

In addition to what was said in the previous paragraph, when Struts² comes into play, the action, the namespace and the package ID must be coded as well.

The paths in the namespaces must have the ID of the plugin following the string used for the mapping of the Struts2 filter or, in other words, this pattern: /do/<PLUGIN_ID>/<SUB_PATH>.

Let's say that our jpmyspecialthingy is going to have a generic edit operation for the current user: a valid namespace for the edit action would be /do/jpmyspecialthingy/CurrentUser/edit.action.

The ID of the package must be in the form of <PLUGIN_ID>_do/<PLUGIN_ID>/<SUB_PATH>. Again, actions of jpmyspecialthingy plugin would be grouped in a package similar to the following:

jpmyspecialthingy_do/jpmyspecialthingy/CurrentUser.

Tiles

The Tiles definition file, placed in src/main/webapp/WEB-INF/plugins/<PLUGIN_ID>/apsadmin,

must have a name that ends with the postfix -tiles; e.g. valid file names would be jpmyspecialthingy1-tiles.xml, jpmyspecialthingy2-tiles.xml end so on.

The definition itself must follow this pattern: <PLUGIN_ID>.<FEATURE>.<NAME_OF_THE_VIEW>: jpmyspecialthingy.edit.editForm could be used to reference the JSP for the hypothetical edit action showed in the example above.

I18n

If the Plugin has its own GUI for the public frontend, you must provide the proper labels (which are stored in the database table localstrings and are outputted through the wp:i18n custom tag). I.e. labels for forms, subtitles, notes, and so on.

Example of some valid labels for the frontend

  • jpmyspecialthingy_SEARCH_FORM=Search
  • jpmyspecialthingy_ADDRESS_COUNTRY=Country

The same is for any GUI in the administration area. In this case you must provide the files package_<LANG_CODE>.properties as described in the document Pattern for application services creation and integration. As always, both frontend and backend keys must avoid any overlapping of the ones in the main core or other Plugins. This can be achieved properly using the id of the Plugin as a prefix.

Example of valid labels for the administration area

  • jpmyspecialthingy.mylabel=My really simple label
  • jpmyspecialthingy.myarea.myotherlabel=This is a note, just like the one up there

Furthermore, in src/main/java/com/agiletec/plugins/jpsurvey/apsadmin/ there at least always one property file for the default language, namely global_messages_<LANG_CODE>.properties, e.g. global_messages_en.properties.

Permissions

If a plugin must add one or several permissions in the system, their ID must always be preceded by the plugin id and by an underscore e.g. jpmyspecialthingy_edit. Please take care of the length of the permission name that, as of Entando 3.2, is 30 characters long.

Bean for a sub-menu in the administration area

The id of the Bean for a sub-menu of the Plugins menu item, must be as follows: <PLUGIN_ID>SubMenu.

Database tables

The names of the tables in either the *Port or *Serv database, must be prefixed by the ID of the Plugin followed by an underscore (_ character).

Configuration items

Configuration items must be placed in the table sysconfig belonging to the *port database; with that said, as usual prefix the name of the item with the the ID of the Plugin followed by an underscore.

A valid example is jpmyspecialthingy_config.

Static resources

Optional static resources must be placed in src/main/webapp/resources/plugins/<PLUGIN_ID>/static, and like the administration directory at the same level, it should contain the usual subdirectories in css, img, js.

top

Clone this wiki locally