-
Notifications
You must be signed in to change notification settings - Fork 3
Plugin Pattern
WARNING: this guide is currently under revision for the release of Entando 3.2
The Entando path to plugins
- Scope of the document
- Introdution
- Plugin installation
- How to start a brand new Plugin
-
Plugin pattern
- Sources
- Naming conventions
- [Beans (Spring Objects) of the Plugin core] (#bean_core)
- Beans (Spring Objects) of the Actions (Struts² Objects)
- Tiles
- I18n
- Permissions
- Bean for a sub-menu in the administration area
- Database tables
- Configuration items
- Static resources
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.
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.
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.
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
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.
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
-
update the dependencies
-
update the system tables, both using your favorite DB admin tool (eg. PgAdmin3, phpMyAdmin etc.) or running specific Ant tasks.
If you are familiar with the previous version of Entando (namely, jAPS / jAPS 2.0 Entando) the current installation process is a lot easier.
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>
and, if the plugin has database scripts,
<!--
SQL files, needed to complete the installation.
-->
<dependency>
<groupId>org.entando.entando.plugins</groupId>
<artifactId>entando-plugin-jpsurvey</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>zip</type>
<classifier>misc</classifier>
</dependency>
Now we have to make Maven update the dependencies; if you IDE of choice doesn't do it automatically you can type the command mvn clean process-resources
in the terminal (or the command prompt) from your project root folder.
We are almost done: the only thing left, before restarting the server, is to update the system database. There are two options:
-
Take them from
src/main/sql/postgresql/*.sql
and execute them with pgAdmin3, psql etc. -
You can use the brand new ant target
PG-db-restore-plugins
.
-
Install
ant-contrib
in your system, following these instructions.
Linux users might want to check whether their distribution provides the package for an immediate installation: e.g. in Ubuntu just typesudo apt-get install ant-contrib
from the shell terminal. -
Check where you put the jar, and edit in
buildProperties.xml
, the propertyant-contrib.jar.path
accordingly (Ubuntu users don't need to configure anything). -
Launch
PG-db-restore-plugins
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.
The installation process is the same for those plugins which require other plugins as prerequisite! Please be aware that, if you don't have ant-contrib installed, you will have to manually update the system tables, restoring the tables of the requested plugins first.
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:
-
groupId
: org.entando.entando.plugins -
artifactId
: entando-plugin-jpmyspecialthingy -
package
: com.mycompany.plugins.jpmyspecialthingy -
pluginCode
: jpmyspecialthingy -
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>
Let's say that our new shining plugin depends on
entando-plugin-jpmail
: we have to manually specify this dependency in the POM of the entando-plugin-jpmyspecialthingy
. It's worth noting that you have to add five entries for each dependency, as shown below:
<dependencies>
.....
<dependency>
<groupId>org.entando.entando.plugins</groupId>
<artifactId>entando-plugin-jpmail</artifactId>
<version>3.0.0</version><!-- version. Don't remove this comment. -->
<type>war</type>
</dependency>
<dependency>
<groupId>org.entando.entando.plugins</groupId>
<artifactId>entando-plugin-jpmail</artifactId>
<version>3.0.0</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>3.0.0</version><!-- version. Don't remove this comment. -->
<type>zip</type>
<classifier>misc</classifier>
</dependency>
<dependency>
<groupId>org.entando.entando.plugins</groupId>
<artifactId>entando-plugin-jpmail</artifactId>
<version>3.0.0</version><!-- version. Don't remove this comment. -->
<type>jar</type>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.entando.entando.plugins</groupId>
<artifactId>entando-plugin-jpmail</artifactId>
<version>3.0.0</version><!-- version. Don't remove this comment. -->
<type>zip</type>
<classifier>misc-test</classifier>
</dependency>
.....
</dependencies>
Please do not copy and paste blindly! Take care of the version of the plugin that, starting from Entando 3.0, matches the core version.
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, insideplugins
. This is to put all the artifacts of the same organization inside in the same place. The usual arrangement of the code inaps
andapsadmin
shouldn't surprise you. -
resources
: the resources needed by the plugin to work. They are divided inapi
(declaration of the web API supported),shortcuts
(declaration of the shortcut available) andspring
(definitions of the beans of the system services) -
sql
: contains the database update scripts either formysql
andpostgres
-
tld
: as for sources, TLD files are organized inside aplugins
directory and grouped by plugin code -
webapp
: here are contained the web application sources. Static resources images, CSS and javascripts are grouped inresources
; finallyWEB-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.
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.
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.
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
.
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
.
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.
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
.
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.
The id of the Bean for a sub-menu of the Plugins menu item, must be as
follows: <PLUGIN_ID>SubMenu
.
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 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.
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
.
All the material here contained is published under the GNU Free Documentation License v1.3
The Entando trademark and logo are registered trademarks of Entando, srl. All
Rights Reserved.
All other trademarks are the property of their respective owners.