Programmer : Connector Programmer : Push API Connector Framework : Packaging the connector as a plugin
 
Packaging the connector as a plugin
 
Plugin structure
Create a basic plugin
About the CVPlugin public class
Top level component class(es)
Top level configuration class(es)
Setter/Getter methods
Plugins are components or resources that can be hot plugged without restarting the product. They are installed in the DATADIR, and are therefore instance-wide.
To load your custom code in Exalead CloudView, it must be packaged as a CVPlugin. You can then easily upload it in the Administration Console.
Plugins can include special component classes, such as connectors, security sources, format converters, analysis processors, etc. They can also include other materials, such as resources (linguistics, statistics, etc.).
Each component class within a plugin can have its own configuration. For example, a connector, will usually have user-defined settings, which will be edited through the Administration Console > Connectors menu. The framework will handle:
the configuration editing process,
the connector instantiation.
Plugin structure
Create a basic plugin
About the CVPlugin public class
Top level component class(es)
Top level configuration class(es)
Setter/Getter methods
Plugin structure
The plugin/component framework allows you to package a set of components within a plugin. The plugin will typically be deployed from a standalone ZIP file including all the necessary JARs and resources.
What is a plugin
A plugin is a regular ZIP file using the 1989 PKZip original format, with deflate compression or no compression (beware to produce compatible files), and must have the following structure:
META-INF/cvplugin.properties - can define several core properties related to the plugin, as key=value lines terminated by a line feed.
Note:  
Properties can only use ASCII characters, a restriction that Java annotations do not bear for properties such as "Author" or "Copyright". See Description of the META-INF/cvplugin.properties file.
lib/ - subdirectory contains the plugin JAR file(s). The JAR file(s) will be parsed by the framework to locate all classes, load the required ones, execute initialization steps, etc.
Other sub-directories can be included to collect additional resources. We strongly recommend not to put any standalone file at the top level of the ZIP directory structure, and collect necessary material in a dedicated sub-folder, such as a resources/ sub-folder.
Description of the META-INF/cvplugin.properties file
Component
Description
plugin.jars
A space-separated list of JAR names to be parsed. If defined, the framework will not scan all the jar files present in the lib/ subdirectory, but only scan those defined in this list.
Example: plugin.jars=mycomponent.jar
plugin.mainClass
The main plugin class name. If defined, the framework will use the given class name instead of searching for a unique CVPlugin-derived class.
Example: plugin.mainClass=com.example.plugins.Plugin
plugin.author
The author name.
We recommend using the @CVPluginAuthor() annotation instead.
plugin.copyright
The copyright information.
We recommend using the @CVPluginCopyright annotation instead.
plugin.description
The description.
We recommend using the @CVPluginDescription annotation instead.
plugin.version
The version information.
We recommend using the @CVPluginVersion annotation instead.
Create a basic plugin
The following procedure describes the main steps to create a CVplugin on a Linux environment.
1. Go to your plugin directory:
2. Create the META-INF/ and lib/ subdirectories:
3. Create a cvplugin.properties file under the META-INF/ subdirectory:
4. Copy your JAR component in the lib/ subdirectory:
5. Zip your plugin:
About the CVPlugin public class
To execute specific initializations through the constructor, you should define a public main class extending the CVPlugin (com.exalead.mercury.plugin.CVPlugin) class.
CVPlugin class basics
This class must be included in one of the JAR files of the lib/ subdirectory. All classes within the JAR collection are available by default through the plugin class loader.
If no such class exists, and if there is only one component within the plugin, the framework will use metadata associated with this unique component.
The name of the CVPlugin-derived class is not important. There should be at most one CVPlugin-derived class in the classes collection.
/** My plugin. **/
@CVPluginDescription("My Wonderful Plugin")
@CVPluginVersion("1.0")
@CVPluginCopyright("Copyright Wonders & Co., All Rights Reserved")
@CVPluginAuthor("Wonders & Co.")
public class Plugin extends CVPlugin {
protected final File installDirectory;

/** Default constructor. **/
public Plugin(final String name, final File installDirectory) {
super(name, installDirectory);
this.installDirectory = installDirectory;
// Optionally, define the plugin initialization code here:
}
}
CVPlugin class annotations
This CVPlugin-derived plugin class may define a number of useful annotations (located in the com.exalead.mercury.plugin package) to provide additional information.
Annotation
Description
@CVPluginAuthor
The plugin author name(s).
@CVPluginCopyright
The plugin copyright information.
@CVPluginDescription
The plugin description.
@CVPluginVersion
The plugin version information.
Top level component class(es)
A component is a class implementing the com.exalead.mercury.component.CVComponent interface.
This top-level interface is an empty interface (no defined method inside) designed to be automatically detected by the framework.
All available non-inner classes implementing this interface are collected during startup while scanning all JARs, and allow to list a subset of components implementing a specialized class or interface at runtime. For example, all components deriving from the com.exalead.papi.framework.connectors.Connector class are listed to collect the list of available connectors in the product.
Top level component class annotations
Annotation
Description
@CVComponentDescription
(com.exalead.mercury.component. CVComponentDescription)
If specified, this is the short description of the connector used in the select box of the Add connector dialog box in the Administration Console.
Example:
@CVComponentDescription("My Wonderful Connector Component")
@CVComponentConfigClass
(com.exalead.mercury.component.config. CVComponentConfigClass)
This annotation defines the:
The associated CVComponentConfig derived class used for the configuration.
CVComponentConfigCheck (com.exalead.mercury.component.config.CVComponentConfigCheck) used to enhance the configuration check of the CVComponent.
Example:
@CVComponentConfigClass(configClass = FilesystemConnectorConfig.class, configCheckClass = ConnectorConfigCheck.class)
@CVComponentLabel (com.exalead.mercury.component.CVComponentLabel)
If specified, this is the label of the component. The label is used in the Administration Console when selecting a custom document processor, semantic processor, or query prefix handler.
For example: @CVComponentLabel("My document processor")
@PropertyLabel (com.exalead.config.bean.PropertyLabel)
DEPRECATED
Similar to the @CVComponentDescription annotation.
@IsEmptyConfig (com.exalead.config.bean.)
The given configuration class is empty (no setters at all). Without this annotation, an empty class would be rejected at configuration build time.
@IntrospectableComponent
(com.exalead.mercury.component. IntrospectableComponent)
This annotation defines the:
CVComponentIntrospector (com.exalead.mercury.component.CVComponentIntrospector) derived co-class used for introspection queries, for example the Check connectivity operation available in the Administration Console.
and a list of supported query classes derived from SupportedQuery (com.exalead.mercury.component.SupportedQuery).
Example:
@IntrospectableComponent(introspectorClass = MyConnectorIntrospector.class, supportedQueries = {
@SupportedQuery(queryClass = CheckConnectivity.class),
@SupportedQuery(queryClass = TestConnection.class),
@SupportedQuery(queryClass = ListDirs.class),
@SupportedQuery(queryClass = ListFiles.class),
@SupportedQuery(queryClass = ListForms.class),
@SupportedQuery(queryClass = ListItems.class),
@SupportedQuery(queryClass = ListViews.class) })
Top level configuration class(es)
A configuration class defines a list of configuration properties that can be used by a component.
The framework will usually:
manage the serialized configuration (as an XML object),
unserialize it,
create an instance of the given class, and allow you to edit its properties,
handle the configuration of components from the Administration Console.,
etc.
The exact workflow is specific to each component type. For example, some component types may not have any configuration at all.
A configuration class must implement the empty CVComponentConfig (com.exalead.mercury.component.config.CVComponentConfig) interface to be accepted as a valid configuration class.
Example:
/**
* The configuration class for the filesystem connector.
**/
@CVComponentDescription("Filesystem simple demo (java)")
public class DemoFileSystemConnectorConfig extends ConnectorConfig
{
private File startingFolder = null;

@IsMandatory(false)
public void setStartingFolder(final File startingFolder)
{
this.startingFolder = startingFolder;
}

public File getStartingFolder()
{
return startingFolder;
}

/**
* Optional method listing all option names as they will be displayed in the UI
**/
public static String[] getMethods()
{
return new String[] { "StartingFolder" };
}
}
Note: An additional static method named getMethods may be defined in a configuration class, to return properties in a specific order. This method should be public, taking no argument, and returning an array of String corresponding to the ordered property names.
Example :
public static String[] getMethods()
{
return new String[]{"Proxy", "ProxyPort"};
}
Top level configuration additional interfaces
Interface
Description
CallAfterFill (com.exalead.config.bean.CallAfterFill)
Allows you to define a callAfterFill() observer method to be called upon filling.
This method is used to perform specific post-actions related to filled properties.
This interface is not required to get a working configuration.
CVComponentConfigSamplify (com.exalead.mercury.component.config. CVComponentConfigSamplify)
Allows you to define a samplify() method, that will be called when a sample object is requested by the framework.
This method is used to fill properties with a real-world example. For example, a Hostname property may be filled with myhostname
The following example shows the CVComponentConfig class using the samplify method.
package com.exalead.connectors;

import com.exalead.papi.framework.connectors.ConnectorConfig;
import com.exalead.config.bean.ConfigurationException;
import com.exalead.config.bean.IsMandatory;
import com.exalead.mercury.component.config.CVComponentConfig;
import com.exalead.mercury.component.config.CVComponentConfigSamplify;

public class SamplifyConnectorSampleConfig
extends ConnectorConfig
implements CVComponentConfigSamplify {
@IsMandatory(true)
public void setPrimaryServer(final WebServer primaryServer) {
this.primaryServer = primaryServer;
}
public WebServer getPrimaryServer() {
return this.primaryServer;
}

@IsMandatory(false)
public void setSecondaryServers(final WebServer[] secondaryServers) {
this.secondaryServers = secondaryServers;
}
public WebServer[] getSecondaryServers() {
return this.secondaryServers;
}

@Override
public void samplify() {
// samplify is called after the config instantiation.
this.primaryServer.setServer("mywebserver.mydomain");
this.primaryServer.setPort(80);
// Thus there will be a default value for the primary server name
// but it won't appear when adding a new secondary server
}

// a webserver is made of a server name and a network port
public static class WebServer {
@IsMandatory(true)
public void setServer(final String server) {
this.server = server;
}
public String getServer() {
return this.server;
}

@IsMandatory(true)
public void setPort(final int port) {
if (port < 0 || port > 65535) {
final ConfigurationException e =
new ConfigurationException("Invalid network port: " + port);
e.setConfigKey("Port");
throw e;
}
this.port = port;
}
public int getPort() {
return this.port;
}

public static String[] getMethods() {
return new String[] {
"Server",
"Port"
};
}

private String server;
private int port;
}

private WebServer primaryServer = new WebServer();
private WebServer[] secondaryServers;

public static String[] getMethods() {
return new String[] {
"PrimaryServer",
"SecondaryServers"
};
}
}
The UI should be similar to the following screenshot:
Setter/Getter methods
This section describes the setter and getter methods when packaging your CVPlugin.
About setters
Setters are:
public methods that do not return any value (void return type),
whose names are prefixed by set (the property names following the set prefix keep the same letter case),
and take exactly one argument (the value to be set).
Setters may bear annotations, see Setter function annotations. Setters annotated with the IsHidden (com.exalead.config.bean.IsHidden) class are ignored.
These are the setters for the Proxy and ProxyPort properties.
@IsMandatory(false)
@PropertyLabel("Proxy to use")
public void setProxy(final String proxy) {
this.proxy = proxy;
}
@IsMandatory(false)
@PropertyLabel("Proxy port to use")
public void setProxyPort(final int port) {
this.port = port;
}
Note: The first upper case is kept for the property name.
Each setter method should be associated with a getter method.
About getters
Getters are:
public methods returning a value,
the returned value should be equivalent to the value taken as argument in the setter,
and take no argument.
Getters do not bear any annotation.
These are the getters for the Proxy and ProxyPort properties.
public String getProxy()
{
return proxy;
}
public int getProxyPort()
{
return proxy;
}
Note: The first upper case is kept for the property name.
The available types, recognized by the framework for setters and getters are the following ones:
The String class.
Base boolean types: boolean, Boolean.
Base numerical types: byte, char, short, int, long, float, double, Boolean, Byte, Character, Short, Integer, Long, Float, Double.
Any class supporting the public static valueOf method taking exactly one String argument, and returning an object of its own class (in this case, the toString method from the Object base class will also be used); such as enums classes.
Any class taking exactly one String argument (in this case, the toString method from the Object base class will also be used); such as the Date class.
Generic Interface class (to accept outer components in configurations; used internally only).
An array of an allowed type.
Example of array parameters:
public class NotesServerConfig implements CVComponentConfigSamplify {
public static class NotesDBRule
{
public NotesDBRule(final String rule)
{
this.rule = rule;
}
public NotesDBRule()
{
}

protected String rule;
public String getRule()
{
return rule;
}
@Override public String toString() {
return getRule();
}
}

private NotesDBRule[] includes = new NotesDBRule[] {};

@IsMandatory(false)
@PropertyLabel("Include rules (regular expression)")
public void setIncludes(final NotesDBRule[] includes) {
this.includes = includes;
}

public NotesDBRule[] getIncludes() {
return includes;
}
}
Setter function annotations
The following annotation classes may be used in setters to provide additional information on property types and settings.
Annotation
Description
@BeeKeyValueType (com.exalead.config.bean.BeeKeyValueType)
Possible values include:
string for generic string,
numeric for a signed long integer value,
enum:value1,value2... for a selection restricted to certain values.
encrypted for values that shall be encrypted, such as passwords.
hidden for values that must not be displayed/edited at all. Consider using @IsHiddenUI instead.
@Connector (com.exalead.config.bean.Connector)
Displays a combo box to list configured connectors. The list of connectors can be restricted with the following flags:
allowSelf: if the component describes a connector, it indicates whether this connector is included in the combobox (default is false).
allowDeployed: indicates whether deployed connectors are listed (default is true).
allowUndeployed: indicates whether undeployed connectors are listed (default is true)
allowUnmanaged: indicates whether unmanaged connectors are listed (default is true)
allowManaged: indicates whether managed connectors are listed (default is true)
allowedClassId: a regular expression to filter by connector classid. If the regular expression is an empty string, then all connectors are listed.
forbiddenClassId: a regular expression to exclude connectors by classid.
allowEmpty: adds an extra empty option in the combo box. Property value will be "" when this option is selected.
@DataModelClass (com.exalead.config.bean.DataModelClass)
Displays a combo box to list available classes in all configured data models. The data models to search classes in can be restricted with the following options (both options are mutually exclusive):
dataModel: only list classes of the given data model.
buildGroup: only list classes of the data model referenced by the given build group.
@Date (com.exalead.config.bean.Date)
Displays a calendar to configure the property field. The property field will be stored as a string formatted with the date format specified in the annotation.
Default date format is: @Date(format=“yyyy-MM-dd”)
Example: If you add a startDate field with
@Date(format=“yyyy-MM-dd”)
public void setStartDate(String startDate) {
this.startDate = startDate;
}
The UI will display: Start date: [calendar widget]
And when dates are saved, they will be stored with the yyyy-MM-dd date format.
@DateTime (com.exalead.config.bean.DateTime)
Same as @Date with time information.
Default datetime format is: @DateTime(format=“yyyy-MM-dd HH:mm:ss”)
@EnumFieldType (com.exalead.config.bean.EnumFieldType)
The given setter takes only a subset of String representations (enum) as value.
Example:
@EnumFieldType(possibleValue = { @PossibleValueType("red"),
@PossibleValueType("green"), @PossibleValueType("blue") })
Note: in @PossibleValueType you can associate a label to each value.
@IsHidden (com.exalead.config.bean.IsHidden)
The given setter is to be ignored. For example, you can use it if the function is not part of the bean setter subset.
Example:
@IsHidden()
@IsHiddenUI (com.exalead.config.bean.IsHiddenUI)
The given setter property should not be editable or displayed, but must still be processed as a regular property. Use it to hide internal properties.
Example:
@IsHiddenUI()
@IsMandatory (com.exalead.config.bean.IsMandatory)
If the associated boolean is true, then the given setter property must be defined (non-empty unserialized value) so that the configuration can be considered as valid.
Otherwise, the property will be considered as optional.
Note: Without this annotation, the default is mandatory.
Example:
@IsMandatory(false)
@MultiLineString (com.exalead.config.bean.MultiLineString)
Displays a multi-line text input control.
@Path (com.exalead.config.bean.Path)
Displays a file chooser widget, that browses Exalead CloudView host filesystem.
@PropertyDescription (com.exalead.config.bean.PropertyDescription)
The property description, as a string. Typically displayed for comment or tooltip. It supports text only, no HTML code.
Example:
@PropertyDescription("Define the hostname to be used for the proxy")
@PropertyLabel (com.exalead.config.bean.PropertyLabel)
The property label, as a string. Typically displayed for short name.
Example:
@PropertyLabel("Proxy hostname")
@SecuritySource (com.exalead.config.bean.SecuritySource)
Displays a combo box to list configured security sources. The list of security sources can be restricted with the following flags:
allowSelf: if the component describes a security source, indicates whether this security source is included in the combobox (default is false)
allowDeployed: indicates whether deployed security sources are listed (default is true)
allowUndeployed: indicates whether undeployed security sources are listed (default is true)
allowedClassId: a regular expression to filter by security source classid. If the regular expression is an empty string, then all security sources are listed.
forbiddenClassId: a regular expression to exclude security sources by classid.
allowEmpty: adds an extra empty option in the combo box. Property value will be "" when this option is selected.
@WithSuggest (com.exalead.config.bean.WithSuggest)
Displays a text input that performs remote queries to suggest entries. In order to remote suggestions to work, the CVComponent must support SuggestOption queries. Here is a full example:
Component config class:
MyComponentConfig extends ConnectorConfig {
...

private String folder;

@WithSuggest
public void setFolder(String folder) {
this.folder = folder;
}
}
Component class:
@IntrospectableComponent(introspectorClass=MyComponentIntrospector.class,
supportedQueries = {@SupportedQuery(queryClass = SuggestOption.class)})
class MyComponent extends Connector {
...
}
Introspector class:
class MyComponentIntrospector implements CVComponentIntrospector {
public Object execute(CVComponentConfig componentConfig, IntrospectionQuery query) throws Exception {
if (query instanceof SuggestOption) {
SuggestOption suggestQuery = (SuggestOption) query;
SuggestOption.SuggestResult result = new SuggestOption.SuggestResult();

// disambiguate by field name if you have several fields annotated with @WithSuggest
if ("Folder".equals(suggestQuery.getConfigKey())) {
String currentValue = suggestQuery.getCurrentValue();
MyComponentConfig myConfig = (MyComponentConfig) componentConfig;
String[] suggestedValues = ...;
result.setSuggestedValues(suggestedValues);
}

return result;
}
throw new IllegalStateException("Unknown introspection query");
}
}
Available classes for setters and getters
The following classes can be used in setters and getters.
Class
Description
BooleanChecked (com.exalead.config.bean.BooleanChecked)
Ensures that the value entered for an option is either true or false.
Use it with boolean options to enforce the option values to true or false.
BytesValue (com.exalead.config.bean.BytesValue)
A value representing a number of Bytes, in any SI Unit.
For example, you can use "10KB" or "10MB" as value, and still handle an amount of bytes in your code.
MillisecondsValue (com.exalead.config.bean.MillisecondsValue)
A value representing a number of milliseconds, in any SI Unit.
For example, you can use "2min" or "5s" as value, and still handle an amount of milliseconds in your code.
OptionalBoolean (com.exalead.config.bean.OptionalBoolean)
A value representing a tri-state Boolean value, with checked value (true, false or optional)
KeyValue (com.exalead.config.bean.KeyValue)
A value representing a pair of strings (key and a value).
Possible Setter exceptions
A setter may raise exceptions, such as NumberFormatException or IllegalArgumentException, but we strongly recommend using the following built-in exceptions.
Recommended exception
Description
ConfigurationException (com.exalead.config.bean.ConfigurationException)
Generic exception thrown when a configuration exception occurs.
IllegalValueException (com.exalead.config.bean.IllegalValueException)
Exception thrown when a setter encounters an illegal value.