Custom servlet plug-ins are JEE servlets that can be deployed as plug-ins within your Appian instance. A working understanding of how JEE servlets work is required for creating this type of plug-in.
When you define a servlet plugin you will have the option of making it stateless or not.
Standard servlets: These require a JEE session and have the ability to both access and update that session.
Stateless servlets: These cannot require or create a session.
Any servlet that maps to to the URL pattern /plugins/servlet/stateless/* will be a stateless servlet and will use HTTP Basic Authentication on each request to authenticate each request and should not access or create a JEE session.
All servlets that match /plugins/servlet/* but do not match /plugins/servlet/stateless/* are not stateless and require the user to have an authenticated session in order to access them, but do have access to a JEE session.
The following principles must be followed:
Custom servlet plug-ins that match the /plugins/servlet/stateless pattern must not require or create a session.
GET requests must not be used to modify data (create/update data through Appian's Java API).
Notes on CSRF Protection:
POST requests to custom plug-in servlets made within the context of a session will be intercepted and blocked by Appian's CSRF protection.
POST requests made outside the context of a session (for example, web services API calls) will not be blocked by Appian's CSRF protection. Because this type of access falls outside of Appian's security perimeter, implementation of this modification must be tested for security independently.
Creating and Deploying the Servlet Plug-In
This example assumes you are using Eclipse as your IDE.
Create a new Java project in Eclipse.
Click File > New > Other....
Select Java Project from the Select a Wizard options. Click Next.
Type a name for your project. Click Finish (accepting the default settings).
Configure the Java Build Path.
Right-click the project. Click Properties.
In the left navigation, click Java Build Path.
On the Libraries tab, click the Add External JARs... button.
Add the following Appian JAR as an external dependency and click OK.
Your plug-in must be designed to access only the classes and methods documented in the Public API javadocs.
Since this is a servlet plug-in, you'll also need to add the library that contains the javax.servlet package to the build path. This is typically in the Java EE library provided with your application server.
Similarly, if you are supporting an injectable service (e.g. ImportExportService), you'll also need to add the library that contains the javax.inject package.
Configure Project Folders.
In the Package Explorer (left navigation), right-click the src folder and select New > Folder.
Type META-INF in the folder name field and click Finish.
With the META-INF folder selected, right-click and select New > Folder. Type lib in the folder name field. Click Finish.
With the src folder selected, right-click and select New > Package. Type your desired package structure in the name field. For example: com.example.plugins.<YOUR_PLUGIN>
Click Finish. Your file structure should appear similar to the following diagram.
Add your appian-plugin.xml file to the src folder at the root level.
Export your project as a JAR file.
Right-click your project and click Export....
Select the JAR file option as the Export destination.
On the Resources to export dialog, clear the .classpath and .project selections, as these files are used exclusively by Eclipse.
Select as your export destination the _admin/plugins folder of your installation directory (<APPIAN_HOME>/_admin/plugins).
This directory is created during application server startup.
Click Finish. Your plug-in is deployed.
The plug-ins framework locates the new JAR file and deploys your custom smart service when the application server starts.
Configuring the appian-plugin.xml File
All plug-ins must contain an appian-plugin.xml configuration file. Plug-ins that do not contain this configuration file won't be registered in Appian.
appian-plugin: The main parent element. This element defines the plug-in properties and references. The name is used for documentation purposes only. The key must be unique among all Appian plug-ins. It represents a unique namespace for your plug-in function. We recommend using the same convention established for Java package names.
plugin-info: This element contains plug-in metadata, including the following sub-elements.
description: Specify a description of the plug-in itself.
vendor: Specify your organization's name and URL.
version: Specify the version of the plug-in. Remember that installing newer versions overrides older versions.
application-version: Specify the minimum version of Appian that the plug-in requires to run.
servlet: Defines the servlet module that will be deployed.
name: Name of the plug-in module that will appear in logs when the plug-in is deployed.
key: Identifier of the module. Must be unique in the system.
class: Servlet Java class. Must be a subclass of com.appiancorp.suiteapi.servlet.AppianServlet.
description: sub-element of servlet (optional) Servlet description.
url-pattern: sub-element of servlet Pattern of the URL to match. Multiple url-patterns can be defined. * and ? wildcards are valid.
init-param: sub-element of servlet (optional) Init parameters for the servlet. Multiple init-param elements can be specified for multiple.
param-name: sub-element of init-param Name of the parameter.
param-value: sub-element of init-param The value of that parameter.
Servlets must extend com.appiancorp.suiteapi.servlet.AppianServlet.
The servlet must conform to the Servlet 2.5 specification.
Be aware that the init() method of the servlet is not called on application server startup nor plug-in deployment. It's called the first time the servlet is accessed.
Once deployed, the servlet will be invoked when requests match the URL pattern relative to <context>/plugins/servlet/. For the servlet defined in the example appian-plugin.xml above, the path would be the following:
Authentication and Authorization
By default, a custom servlet plug-in is not available to unauthenticated users. However, access can be modified depending on your needs.
This is the default setting for a custom servlet plug-in. If the servlet is not listed in the Spring Security Unsecured List, a request for a custom servlet URL that does not have a current session will redirect the user to the login page.
The <context>/plugins/servlet/* pattern is authorized for authenticated users within any role (Application Users and Designers).
You can allow unauthenticated access to your servlet by adding your custom servlet plug-in to the Spring Security Unsecured List.
Because you should never make changes directly to a base-product version of a Spring Security file, create a copy of <APPIAN_HOME>/ear/suite.ear/web.war/WEB-INF/conf/security/spring-security-02-unsecured.xml and name it spring-security-02-unsecured-override.xml.
In the new file spring-security-02-unsecured-override.xml, add an entry such as <sec:http pattern="/plugins/servlet/<your servlet url pattern>" security="none"/>.
Because this type of access falls outside of Appian's security perimeter, implementation of this modification must be tested for security independently.
Note: Unauthenticated access to content is prohibited in all Appian Cloud environments.
This example is a simple servlet that returns an array of JSON objects with a relevant subset of fields for Appian process tasks assigned to the currently authenticated user.
This example assumes the following scenario:
A web portal wants to display a list of Appian tasks for a user, with links that will take the user to the corresponding task in Appian.
The web portal is capable of parsing the JSON formatted task information into a display format appropriate to the portal.
A single sign-on system is in place such that a request from the user's browser from the web portal with be authenticated with Appian.
This servlet example uses Appian's public Java API to retrieve the list of tasks for the authenticated user.
The JSON library in the org.json package is used to create the JSON representation of the task. This library does not need to be included separately because it is already provided by the plug-in container.
This example is for the "mashup" scenario, which requires Cross-Origin Resource Sharing (CORS). CORS is supported by all modern browsers. For security, it requires that the server respond with a header indicating that an AJAX request from a page served by a specific origin URL is allowed. To allow an origin to access resources on the Appian server, including your servlet plugin, add it to the list of allowed origins in the Embedded Interfaces page of the Administration Console. More information on CORS can be found in the W3C CORS specification.
This example is intentionally simple and may not cover all use cases nor handle every edge/error case in a way that would be satisfactory for production use. For example, the logic that parses the query parameters will use the default batchSize if only startIndex is given, but will use the defaults for both startIndex and batchSize if only batchSize is given or if neither parameter is given. Adapt the example as you see fit.
If the "mashup" scenario is not appropriate to your use case, but instead a back-end server-to-server integration matches your use case better, this example can be adapted to fit that example in the following ways:
Change the url-pattern element in the appian-plugin.xml to <url-pattern>/stateless/tasklist</url-pattern> to make the servlet a stateless servlet. This will cause the servlet to no longer require an authenticated session and instead will protect it using HTTP Basic authentication.
When calling the servlet, pass the user's credentials as HTTP Basic auth credentials.
If using an integration user instead of authenticating with the credentials of the user whose tasks you want to view, you will have to use a different API to run a task report for that user instead of calling ProcessAnalyticsService.getMyTasks.