FORMCYCLE deploy-plugin plugin


Plugin download (requires login)

This is a plugin for deploying plugin to Xima® Formcycle, hence the name FORMCYCLE deploy-plugin plugin.

The deploy plugin lets you upload and install plugins to Xima® Formcycle automatically. Compared with a manual installation via the backend menu, this offers several advantages:

  • Plugin developers can integrate the deployment process into the Maven build process. This allows for faster testing, rapid development and does not necessitate a context switch that might slow down developers.
  • It allows the installation of Xima® Formcycle tob e automated even further.

You can install the deploy plugin both as a client as well as a system plugin. If the former, you can only modify plugin of that cilent.  It contains a servlet action for sending a plugin JAR file via an HTTP POST request. Depending on the other HTTP parameters, the plugin is either installed, updated, or deleted.

The uploaded plugin may already exist in the system. In this this, you usually want to update plugin - not have it installed twice. This requires a way to identify whether a plugin exists already. The servlet action allows for four different possibilities:

  • (recommended) The plugin is identified based on an entry in its manifest. The manifest needs to be located at META-INF/MANIFEST.MF in the plugin JAR file, such as the group ID or artifact ID. Make sure you prepare the JAR file properly when building the plugin. This method is slightly harder to setup, but offers the advantage that the identifier always remains the same and does not depend on the file name or some internal ID.
  • The plugin is identified based on its name, i.e. the file name of the upload JAR file. This is also the name as it is shown in the plugin menu.
  • The plugin is identified based on its internal database ID. This ID is not shown in the UI currently and should only be used by developers.
  • The plugin is identified based on its UUID. This ID is not shown in the UI currently and should only be used by developers.

By default, a servlet action is accessible to everybody. Usually, you do not want anonymous users to modifying the installed plugins. To secure the servlet, you can specify a password in the plugin configuration. You then need to include this password in the HTTP POST request.

Plugin configuration

You can optionally set a password for securing the access to the plugin deploy servlet. If you do, you need to include the password in the HTTP POST request to authorize that request.

Specify the token by entering a value for the plugin property token. It must be entered in the following format:

hash_method:hashed_value

The following hash methods are available.

plain
Identity function. Lets you enter a plain text password.
sha256
SHA-256 algorithm.
sha384
SHA-384 algorithm.
sha512
SHA-512 algorithm.

To enter the password admin as plain text, use:

plain:admin

To enter the password admin hashed with SHA-256, use:

sha256:S+32GI3fWXwHHulUMtWmjpQ15EqMvgVYguuO9SKxfNw+ckAGQljP6tKlf1EITnU7

The hash is salted. You can generate a valid hash for a given password via the create-token servlet, see below.

Deploy servlet

The following describes the structure of the HTTP request you need to adhere to in order to install, update, or delete a plugin.

The HTTP method must be POST, other methods will result in an error. The endpoint URL is as follows (change the name of the FORMCYCLE server and the client ID):

POST http://localhost:8080/formcycle/plugin?name=deploy-plugin&client-id=154 HTTP/1.1

The client-id is not required in case the plugin is installed as a system plugin.

Request parameter

You can specify the parameters either directly as URL parameters, or as multipart/form-data or application/x-www-form-urlencoded. The following parameters are available and supported by the plugin deploy servlet:

deploy-action
Action to be performed on the plugin. Allowed values are save, update-properties, activate, deactivate and delete. See below for a description of each method.
client-id
ID of the client where the plugin is installed, updated, or deleted. You must specify only one of client-id or client-uuid.
client-uuid
UUID of the client where the plugin is installed, updated, or deleted. You must specify only one of client-id or client-uuid. Please note that a plugin installed as a client plugin always required the parameter client-id.
jar-file
Binary data of the JAR file with the plugin (required only when installing or updating the plugin).
token
The token (password) for authorizing the request. Required only when the a token was set in the plugin configuration.
plugin-ident
The method used for searching an already existing plugin, see above. The following methods are supported:
manifest
Identifies a plugin based on an entry in its manifest.
id
Identifies a plugin based on its database ID.
name
Identifies a plugin based on its name (the file name of the plugin JAR file).
uuid
Identifies a plugin based on its UUID.
plugin-identifier
Identifier of the plugin that should be installed, updated, or deleted. The exact meaning of this parameter depends on the chosed plugin-ident method:
plugin-ident=manifest
plugin-identifier must contain the name of the manifest property and its value, in the format Attribute-Name=value. For example, if this property is set to Implementation-Title=com.example.fc.plugin:my-plugin, this will search for a plugin with a manifest entry Implementation-Title set to com.example.fc.plugin:my-plugin.
plugin-ident=id
plugin-identifier must contain the data base ID of the target plugin, such as 53 or 893.
plugin-ident=name
plugin-identifier must contain the name of the target plugin, such as my-plugin.jar or foobar.jar.
plugin-ident=uuid
plugin-identifier must contain the UUID of the target plugin, such as 03022599-903d-429b-9822-80a324a542fc.
clear-properties
Either true or false. If set to true, all plugin property values are cleared. This is done before the new properties (see parameter property) are applied.
property
Name and value of a plugin property to set, in the format key=value. This HTTP parameter may be specified multiple times if you want set multiple properties. For example, if set to database.username=john, this sets the plugin property database.username to john.
disallow-install
Either true or false. When this is set to true and the plugin does not exists yet (as determined by the given plugin-ident and plugin-identifier parameters), the plugin is not installed and an error is returned. Otherwise, when set to false, the plugin is installed if it does not exists yet and updated if it does.
locale
The language to be used when the plugin is modified, such as en or de. May affect some error messages. Usually this parameter is not neccessary.

Deploy actions

The value of the parameter deploy-action specifies what should happen with the selected plugin. The following actions are available:

save
Transmits the plugin to the Xima® Formcycle server. You need to specify a JAR file. If the plugin does not exists yet (and the parameters disallow-install is not set), the plugin is installed and activated. Otherwise, if the plugin exists already, it is only updated and left active or inactive. For example:
# Installs or updates the given plugin.
curl -X POST \
  -F deploy-action=save \
  -F token=admin \
  -F plugin-ident=manifest \
  -F plugin-identifier=Implementation-Title=com.example:plugin \
  -F "jar-file=@my-plugin.jar" \
  "http://localhost:8080/formcycle/plugin?client-id=154&name=deploy-plugin"
delete
Deletes the given plugin. You must not specify a JAR file. If the specified plugin does not exist yet, an error is returned. For example:
# Löscht das Plugin mit dem Implementation-Title com.example:plugin
curl -X POST \
  -F deploy-action=delete \
  -F token=admin \
  -F plugin-ident=manifest \
  -F plugin-identifier=Implementation-Title=com.example:plugin \
  "http://localhost:8080/formcycle/plugin?client-id=154&name=deploy-plugin"
activate
Activates the given plugin. You must not specify a JAR file. If the specified plugin is already active, no action is performed an a success is returned. For example:
# Activates the given plugin
curl -X POST \
  -F deploy-action=activate \
  -F token=admin \
  -F plugin-ident=manifest \
  -F plugin-identifier=Implementation-Title=com.example:plugin \
  "http://localhost:8080/formcycle/plugin?client-id=154&name=deploy-plugin"
deactivate
Deactivates the given plugin. You must not specify a JAR file. If the specified plugin is already inactive, no action is performed an a success is returned. For example:
# Deactivates the given plugin
curl -X POST \
  -F deploy-action=deactivate \
  -F token=admin \
  -F plugin-ident=manifest \
  -F plugin-identifier=Implementation-Title=com.example:plugin \
  "http://localhost:8080/formcycle/plugin?client-id=154&name=deploy-plugin"
update-properties
Updates the properties of the given plugin. You must not specify a JAR file. You should specify at least one of clear-properties or property. If the given plugin does not exist yet, an error is returned. For example:
# Delete all existing plugin properties and set the property //foo// to //bar//
curl -X POST \
  -F deploy-action=update-properties \
  -F token=admin \
  -F plugin-ident=manifest \
  -F plugin-identifier=Implementation-Title=com.example:plugin \
  -F clear-properties=false
   -F property=foo=bar \
  "http://localhost:8080/formcycle/plugin?client-id=154&name=deploy-plugin"

Response

The plugin deploy servet returns a status code and a JSON object with the details. The status code is 2xx if (and only if) the deploy servlet was executed successfully.

The JSON object that is returned adheres to the following JSON schema:

{
   "$schema": "http://json-schema.org/schema",
   "description": "Represents the response of the deploy plugin servlet.",
   "required": [
       "success",
       "statusCode",
       "details",
       "message",
       "requestParameters"
    ],
   "properties": {
       "success": {
           "type": "boolean",
           "title": "Success status",
           "description": "true if the deploy plugin servlet was executed successfully, or false otherwise"
        },
       "statusCode": {
           "type": "number",
           "title": "HTTP status code",
           "description": "The status code of the HTTP request that contains this response."
        },
       "details": {
           "type": "object",
           "title": "Result details",
           "description": "Detailed information about the plugin processed by the deploy plugin servlet.",
           "oneOf": [
                {
                   "description": "If the deploy plugin servlet was successful, details about the successfully executed action.",
                   "required": [
                       "id",
                       "uuid",
                       "name",
                       "active",
                       "message"
                    ],
                   "properties": {
                       "id": {
                           "type": "number",
                           "title": "Plugin ID",
                           "description": "The database ID of the processed plugin."
                        },
                       "uuid": {
                           "type": "string",
                           "title": "Plugin UUID",
                           "description": "The UUID of the processed plugin."
                        },
                       "name": {
                           "type": "string",
                           "title": "Plugin name",
                           "description": "The name of the processed plugin, i.e. the file name of the plugin JAR file."
                        },
                       "active": {
                           "type": "boolean",
                           "title": "Plugin activation status",
                           "description": "true if the plugin is now active, false if it is now inactive."
                        },
                       "message": {
                           "type": "string",
                           "title": "Result message",
                           "description": "Human-readable message describing the performed action."
                        }
                    }
                },
                {
                   "required": [
                       "exceptionType",
                       "exceptionMessage"
                    ],
                   "description": "If the deploy plugin servlet was unsuccessful, details about the error that occurred.",
                   "properties": {
                       "exceptionType": {
                           "type": "string",
                           "title": "Exception type",
                           "description": "The type of the error that occurred, a fully-classified name of the Java exception class."
                        },
                       "exceptionMessage": {
                           "type": "string",
                           "title": "Exception message",
                           "description": "The human-readable message of the error that occurred."
                        }
                    }
                }
            ]
        },
       "message": {
           "type": "string",
           "title": "Result message",
           "description": "A human-readable message that describes this result."
        },
       "requestParameters": {
           "type": "object",
           "title": "Request parameters",
           "description": "The parameters of the request that triggered this response."
        }
    }
}

Example for a response when a plugin was updated successfully:

{
"success": true,
"requestParameters": {
 "plugin-ident": ["manifest"],
 "name": ["deploy-plugin"],
 "client-id": ["1"],
 "deploy-action": ["save"],
 "plugin-identifier": ["Implementation-Title=com.example:plugin"],
 "token": ["admin"]
 },
"details": {
 "name": "my-plugin.jar",
 "active": true,
 "id": 203,
 "message": "Plugin saved successfully.",
 "uuid": "2fe3e1ba-cb32-434e-9f59-4422f8dabcad"
 },
"message": "Plugin saved successfully.",
"statusCode": 200
}

Example for a response when a plugin could not be deleted:

{
"success": false,
"requestParameters": {
 "plugin-ident": ["manifest"],
 "name": ["deploy-plugin"],
 "client-id": ["1"],
 "deploy-action": ["delete"],
 "plugin-identifier": ["Implementation-Title=com.example:plugin"],
 "token": ["admin"]
 },
"details": {
 "exceptionType": "java.lang.IllegalArgumentException",
 "exceptionMessage": "Deploy action 'delete' requires an existing pluign, but none was found."
 },
"message": "class java.lang.IllegalArgumentException: Deploy action 'delete' requires an existing pluign, but none was found.",
"statusCode": 404
}

Create token servlet

This servlet lets you create a hash for a password that you can enter in the plugin property token. Make an HTTP GET request to the following URL (change to path to the Xima® Formcycle server and the client ID):

http://localhost:8080/formcycle/plugin?client-id=1&name=create-token&token=<PASSWORD>&method=<METHOD>
token
The password to hash.
method
Hash method, default to sha256. Supported values are plain, sha256, sha384 and sha512.

This returns a JSON object with the same schema as returned by the plugin deploy servlet. For example:

{
"success": true,
"requestParameters": {
 "name": ["create-token"],
 "client-id": ["1"],
 "token": ["admin"]
 },
"details": {
 "method": "sha256",
 "token": "sha256:S+32GI3fWXwHHulUMtWmjpQ15EqMvgVYguuO9SKxfNw+ckAGQljP6tKlf1EITnU7"
 },
"message": "Hash token created successfully",
"statusCode": 200
}

Maven deploy plugin

To upload a plugin to Xima® Formcycle after building a plugin project via Maven, you can use the maven deploy plugin. It is available from the XIMA artifactory (please note you may need the correct permissions to access this artifact).

Confguration

<plugin>
   <groupId>de.xima.fc.maven.plugin</groupId>
   <artifactId>fc-deploy-plugin-maven-plugin</artifactId>
   <version>1.1.0</version>
   <configuration>
       <url>http://localhost:8080/formcycle</url>
       <pluginName>deploy-plugin</pluginName>
       <clientId>52</clientId>
       <token>admin</token>
       <deployAction>save</deployAction>
       <pluginIdent>name</manifest>
       <pluginIdentifier>my-plugin.jar</pluginIdentifier>
       <jarFile></jarFile>
       <disallowInstall>false</disallowInstall>
       <locale>en</locale>
       <clearProperties>true</clearProperties>
       <properties>
           <property1>value1</property1>
           <property2>value2</property2>
       <properties>
  </configuration>
</plugin>

The plugin offers the following configurable settings:

url [Default value: ${fcDeployUrl}]
URL to the Xima® Formcycle server, including the context path, such as http://localhost:8080/formcycle
pluginName [Default value: deploy-plugin]
Name of the deploy plugin, the value for the parameter name. Usually you do not need to change this.
clientId [Default value: ${fcDeployClientId}]
ID of the client with the plugin to be installed, updated, or deleted. Corresponds to the parameter client-id of the plugin deploy servlet, see above.
clientUuid
Alternative for clientUUID. The UUID of the client with the plugin to be installed, updated, or deleted.Corresponds to the parameter client-uuid of the plugin deploy servlet, see above.
token [Standardwert: ${fcDeployToken}]
Password for the plugin deploy servlet, if one was set in the plugin configuration.
deployAction [Default value: save]
Method to be executed. Allowed values are save, update-properties, activate, deactivate and delete. Corresponds to the parameter deploy-action of the plugin deploy servlet, see above.
pluginIdent [Default value: manifest]
The method for identifying existing plugins. Corresponds to the parameter plugin-ident of the plugin deploy servlet, see above.
pluginIdentifier [Default value: Implementation-Title=${project.groupId}:${project.artifactId}]
Identifier of the plugin to be installed, updated, or deleted. Corresponds to the parameter plugin-identifier of the plugin deploy servlet, see above.
jarFile [Default value: Haupt-Build-Artifakt des Maven-Projekts]
Path to the JAR file to be uploaded, relative to the base directory of the maven project.
disallowInstall [Default value: false]
When set to true and the plugin does not exists yet, the plugin is not installed and an error is returned. Corresponds to the parameter disallow-install of the plugin deploy servlet, see above.
locale [Standardwert: en]
Language for the installations. Corresponds to the parameter locale of the plugin deploy servlet, see above.
clearProperties [Default value: false]
Clears all properties of the plugin. Corresponds to the parameter clear-properties of the plugin deploy servlet, see above.
properties
Key value pair with the properties to be set on the plugin. Corresponds to the parameter property of the plugin deploy servlet, see above.

Recommendations for your plugin project

While the Maven plugin offers a wide variety of options, the default settings are usually sufficient. We recommend the following steps for your plugin:

Add this code snippet to the profile section of the pom.xml:

   <properties>
   <fc-deploy-plugin-maven-plugin.version>1.1.0</fc-deploy-plugin-maven-plugin.version>
  </properties>

  <build>
   <plugins>
    <plugin>
     <groupId>de.xima.fc.maven.plugin</groupId>
     <artifactId>fc-deploy-plugin-maven-plugin</artifactId>
     <version>${fc-deploy-plugin-maven-plugin.version}</version>
    </plugin>
   </plugins>
  </build>

The plugin is identified based on the entry Implementation-Title in its Manifest.MF file. For this to work, you need to prepare the manifest correctly. You can do so either with the maven-jar-plugin or with the maven-assembly-plugin, depending on which plugin your project uses.

 <properties>
 <xfc.version>6.4.0-SNAPSHOT</xfc.version>
 <maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
 <maven-assembly-plugin.version>3.2.0</maven-assembly-plugin.version>
</properties>

<build>
 <plugins>

  <!-- If using the maven-jar-plugin -->
  <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-jar-plugin</artifactId>
   <version>${maven-jar-plugin.version}</version>
   <configuration>
    <outputDirectory>${basedir}</outputDirectory>
    <finalName>${project.artifactId}</finalName>
    <archive>
     <manifest>
      <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
     </manifest>
     <manifestEntries>
      <formcycle-version-requirement>${xfc.version}</formcycle-version-requirement>
      <Implementation-Title>${project.groupId}:${project.artifactId}</Implementation-Title>
      <Implementation-Vendor-Id>${project.groupId}</Implementation-Vendor-Id>
      <Implementation-Version>${project.version}</Implementation-Version>
      <Build-Timestamp>${maven.build.timestamp}</Build-Timestamp>
     </manifestEntries>
    </archive>
   </configuration>
  </plugin>

  <!-- If using the maven-assembly-plugin -->
  <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-assembly-plugin</artifactId>
   <version>${maven-assembly-plugin.version}</version>
   <executions>
    <execution>
     <id>fat-jar</id>
     <phase>package</phase>
     <goals>
      <goal>single</goal>
     </goals>
     <configuration>
      <outputDirectory>${basedir}</outputDirectory>
      <finalName>${project.artifactId}</finalName>
      <descriptorRefs>
       <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <appendAssemblyId>false</appendAssemblyId>
      <archive>
       <manifestEntries>
        <Build-Timestamp>${maven.build.timestamp}</Build-Timestamp>
        <Implementation-Vendor-Id>${project.groupId}</Implementation-Vendor-Id>
        <Implementation-Title>${project.groupId}:${project.artifactId}</Implementation-Title>
        <Implementation-Version>${project.version}</Implementation-Version>
        <formcycle-version-requirement>${xfc.version}</formcycle-version-requirement>
       </manifestEntries>
      </archive>
     </configuration>
    </execution>
   </executions>
  </plugin>

 </plugins>
</build>

Now you can build the plugin via Maven and upload it to a Xima® Formcycle