Examples
Connection examples - SMTP connection
The purpose of this example is to give you an overview of the various mechanisms the Connectors Framework brings to you for creating connections by creating an SMTP connection.
Developing a connection is quite straightforward. You just need to create the following elements:
- Runtime and Editor Java classes;
- and an XML definition and a string resource XML files.
You can download the example here.
Define the connection and set up the configuration
This file should be available from the relative path WEB-INF\storage<custom><connections>\education-mail.xml
within the final connectors package.
<?xml version="1.0" encoding="UTF-8"?>
<connections>
<connection-settings name="smtp.connection" category="education">
<class qualifiedName="com.axemble.education.connectors.smtp.SampleSMTPConnection" />
<configuration>
<class qualifiedName="com.axemble.education.connectors.smtp.SampleSMTPConnectionEditor" />
<section name="settings" label="LG_SETTINGS">
<fields>
<field name="fldMailBaseUrl" label="LG_MAIL_BASE_URL" ctrl="com.axemble.vdp.ui.core.document.fields.TextBoxField" />
<field name="fldSmtpServer" label="LG_SMTP_SERVER" ctrl="com.axemble.vdp.ui.core.document.fields.TextBoxField" mandatory="true" />
<field name="fldSmtpPort" label="LG_SMTP_PORT" ctrl="com.axemble.vdp.ui.core.document.fields.TextBoxField" mandatory="true" />
<field name="fldMailAdministrator" label="LG_SMTP_MAIL_ADMINISTRATOR" ctrl="com.axemble.vdp.ui.core.document.fields.TextBoxField" />
<field name="fldMailSender" label="LG_SMTP_MAIL_SENDER" ctrl="com.axemble.vdp.ui.core.document.fields.TextBoxField" />
</fields>
</section>
</configuration>
</connection-settings>
</connections>
Create the runtime class for the SMTP connection
Declare the package, the imports and the class
package com.axemble.education.connectors.smtp;
import java.io.Serializable;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import com.axemble.vdoc.sdk.connectors.BaseConnection;
import com.axemble.vdoc.sdk.utils.Logger;
public class SampleSMTPConnection extends BaseConnection
Declare an internal structure to represent the connection object
public class InnerConnection implements Serializable {
private static final long serialVersionUID = 8564201166004587558L;
private Session session;
private Transport transport;
/**
* @param session
* @param transport
*/
public InnerConnection(Session session, Transport transport) {
super();
this.session = session;
this.transport = transport;
}
public Session getSession() {
return session;
}
public Transport getTransport() {
return transport;
}
}
Example getConnection method
@Override
public Object getConnection() {
try {
String serverName = (String)getConnectionDefinition().getValue( SampleSMTPConnectionEditor.FIELD_SMTP_SERVER );
String portNumber = (String)getConnectionDefinition().getValue( SampleSMTPConnectionEditor.FIELD_SMTP_PORT );
String smtpLogin = getPortalModule().getConfiguration().getStringProperty( "mail.smtp.login" );
String smtpPassword = getPortalModule().getConfiguration().getStringProperty( "mail.smtp.password" );
Properties prop = System.getProperties();
prop.put( "mail.smtp.host", serverName );
prop.put( "mail.smtp.port", portNumber );
Session session = Session.getDefaultInstance( prop, null );
Transport transport = session.getTransport( "smtp" );
transport.connect( serverName, smtpLogin, smtpPassword );
return new InnerConnection( session, transport );
} catch( Exception e ) {
Logger.getLogger( this.getClass() ).error( getPortalModule().getStaticString( "LG_TEST_SEND_MAIL_ERROR" ) + e.toString() );
}
return null;
}
Example validate method
@Override
public boolean validate() throws Exception {
Transport transport = null;
try {
// get a connection
InnerConnection innerConnection = (InnerConnection)getConnection();
if ( innerConnection == null ) {
return false;
}
String senderEmail = (String)getConnectionDefinition().getValue( SampleSMTPConnectionEditor.FIELD_MAIL_SENDER );
String administratorEmail = (String)getConnectionDefinition().getValue( SampleSMTPConnectionEditor.FIELD_MAIL_ADMINISTRATOR );
Session session = innerConnection.getSession();
MimeMessage mimeMessage = new MimeMessage( session );
mimeMessage.setSubject( "E-mail de test" );
mimeMessage.setText( "Ceci est un test d'envoi d'e-mail" );
mimeMessage.setFrom( new InternetAddress( senderEmail ) );
InternetAddress[] internetAddresses = new InternetAddress[1];
internetAddresses[0] = new InternetAddress( administratorEmail );
mimeMessage.setRecipients( Message.RecipientType.TO, internetAddresses );
transport = innerConnection.getTransport();
transport.sendMessage( mimeMessage, mimeMessage.getAllRecipients() );
return true;
} finally {
safeClose( transport );
}
}
Treatment connector examples - Mail treatment
The email treatment connector allows the designer to configure, through the diagram editor, various email entry-points inside the diagram.
The purpose of this example is to give you an overview of the various mechanisms the Connectors Framework brings to you.
Developing a connector is quite straightforward. You just need to create the following elements:
- Runtime and Editor Java classes;
- an XML definition file;
- and a string resource XML file.
You can download the example here.
Asynchronous treatments
Sending an email can require time execution and because you don’t want to slow down your documents you need to use asynchronous treatments. Asynchronous treatments are executed through the Process Engine Server.
Create the “send mail treatment” connector
Define the connector, the treatment and set up its configuration
This file should be available from the relative path WEB-INF\storage<custom><connectors>\education-mail.xml
.
<?xml version="1.0" encoding="UTF-8"?>
<connectors>
<connector name="sample" label="sample-connector.label" description="sample-connector.description" version="1.0" company="Visiativ Software" ref-connection="sample.connection">
<treatments>
<treatment name="fooTreatment" label="sample.treatment.foo.label">
<class qualifiedName="com.axemble.education.connectors.sample.DummyTreatmentConnector" />
<configuration>
<class qualifiedName="com.axemble.education.connectors.sample.DummyTreatmentConnectorEditor" />
<section name="main" label="LG_MAIN">
<fields>
<field name="fldBody" label="treatment.sample.foo.body.label" description="treatment.sample.foo.body.description" ctrl="selector" screen="Property" method="select" mandatory="true" type="string" quick-create="Field.quickCreate" quick-create-type="string" />
</fields>
</section>
<custom />
</configuration>
<entry-points>
<workflow-library categoryName="education" />
</entry-points>
</treatment>
</treatments>
</connector>
</connectors>
Create the runtime class for the send mail treatment connector
Declare the package, the imports and the class
package com.axemble.education.connectors.smtp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Date;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.w3c.dom.Element;
import com.axemble.education.connectors.smtp.SampleSMTPConnection.InnerConnection;
import com.axemble.vdoc.sdk.connectors.BaseTreatmentConnector;
import com.axemble.vdoc.sdk.document.fields.LocalizedTextField;
import com.axemble.vdoc.sdk.exceptions.SDKException;
import com.axemble.vdoc.sdk.interfaces.IContext;
import com.axemble.vdoc.sdk.interfaces.ITaskInstance;
import com.axemble.vdoc.sdk.interfaces.IUser;
import com.axemble.vdoc.sdk.interfaces.IWorkflowInstance;
public class SampleSendMailTreatmentConnector extends BaseTreatmentConnector
Example execute method
@Override
public int execute( IContext context, IWorkflowInstance workflowInstance, ITaskInstance taskInstance, Element customElement ) {
if ( context == null ) {
context = getWorkflowModule().getContextByLogin( "sysadmin" );
}
// Use another connection
InnerConnection innerConnection = null;
try {
innerConnection = (InnerConnection)getConnection();
// create the MimeMessage
MimeMessage message = new MimeMessage( innerConnection.getSession() );
// set the sender from the context
InternetAddress senderAddress = new InternetAddress( context.getUser().getEmail(), context.getUser().getFullName() );
message.setFrom( senderAddress );
// set the recipients
ArrayList<InternetAddress> toAddresses = new ArrayList<InternetAddress>();
IUser user = getDirectoryModule().getUserByLogin( "sboirol" );
toAddresses.add( new InternetAddress( user.getEmail(), user.getFullName() ) );
InternetAddress[] toInternetAddresses = new InternetAddress[toAddresses.size()];
toAddresses.toArray( toInternetAddresses );
message.setRecipients( Message.RecipientType.TO, toInternetAddresses );
// set the subject
String subjectValue = (String)getTreatmentDefinition().getValue( SampleSendMailTreatmentConnectorEditor.FIELD_SUBJECT );
if ( subjectValue.startsWith( "false;" ) ) {
subjectValue = LocalizedTextField.getValue( subjectValue );
subjectValue = evaluateExpressions( context, workflowInstance, subjectValue );
} else {
subjectValue = getStaticString( LocalizedTextField.getValue( subjectValue ) );
}
message.setSubject( subjectValue );
// set the body
Object bodyContentValue = getTreatmentDefinition().getValue( SampleSendMailTreatmentConnectorEditor.FIELD_BODY );
if ( bodyContentValue == null ) {
throw new SDKException( getStaticString( "treatment.mail.sendMail.errors.emptyMessageContent" ) );
}
String textBodyContentValue = new String( (byte[])bodyContentValue ).toString();
textBodyContentValue = evaluateExpressions( context, workflowInstance, textBodyContentValue );
message.setContent( textBodyContentValue, "text/html; charset=utf-8" );
message.setSentDate( new Date() );
// serialize the message for asynchronous treatment (see asyncExecute)
serializeMessage( message );
return IExecuteStatus.CONTINUE;
} catch( Exception e ) {
return IExecuteStatus.STOP;
} finally {
safeClose( innerConnection );
}
}
Example asyncExecute method
@Override
public void asyncExecute( Element customElement ) {
try {
// Use another connection
InnerConnection innerConnection = null;
try {
innerConnection = (InnerConnection)getConnection();
// load the MimeMessage
MimeMessage message = deserializeMessage( innerConnection.getSession(), this.messageBytes );
// send mail using java mail API
innerConnection.getTransport().sendMessage( message, message.getAllRecipients() );
} finally {
safeClose( innerConnection );
}
} catch( Exception e ) {
throw new SDKException( e );
}
}
Example beforeCompletion and afterCompletion methods
@Override
public void beforeCompletion( IContext context, Element customElement ) {
super.beforeCompletion( context, customElement );
}
@Override
public void afterCompletion( IContext context, Element customElement, boolean committed ) {
super.afterCompletion( context, customElement, committed );
}
Serialize and deserialize the MimeMessage
private void serializeMessage( MimeMessage message ) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
message.writeTo( baos );
this.messageBytes = baos.toByteArray();
} catch( Exception e ) {
throw new SDKException( e );
}
}
private MimeMessage deserializeMessage( Session session, byte[] bytes ) {
try {
return new MimeMessage( session, new ByteArrayInputStream( bytes ) );
} catch( Exception e ) {
throw new SDKException( e );
}
}
Bookmarks description
Objects syntax: ${key}
Examples | Description |
---|---|
${iUser} | current context user |
${iWorkflowInstance} | current workflow instance |
Objects syntax with introspection: ${key.property1.property2…propertyX}
Examples | Description |
---|---|
${iUser.FullName} | Full name of the current context user |
${iUser.Organization.Name} | Organization of the current context user (sysadmin does not have an organization!) |
${iWorkflowInstance.Catalog.Project.Name} | Name of the project of the document |
Document values: ${key-document.property1.property2…propertyX}
Examples | Description |
---|---|
${iWorkflowInstance-document.sys_Creator.FullName} | Full name of the creator of the document. |
${iWorkflowInstance-document.period.startDate} | Start date of a period field. |
${iWorkflowInstance-document.period.endDate} | End date of a period field. |
Connection definition configuration: ${iConnectionDefinition-configuration.property1…propertyX}
${iConnectionDefinition-configuration.fieldname}
Examples | Description |
---|---|
${iConnectionDefinitionConfiguration.fldMailBaseUrl } | Base mail URL. |
${iConnectionDefinitionConfiguration.fldSmtpServer} | The SMTP server host name. |
${iConnectionDefinitionConfiguration.fldSmtpPort} | The SMTP server port number. |
${iConnectionDefinitionConfiguration.fldMailAdministrator} | The administrator email. |
${iConnectionDefinitionConfiguration.fldMailSender} | The default sender email. |
Server configuration: ${iServerConfiguration.property1…propertyX}
Examples | Description |
---|---|
${iServerConfiguration.SERVER_BASE_URL} | Base server URL set on the server configuration. |
${iServerConfiguration.mail.server} | The SMTP server host name set on the server configuration. |
${iServerConfiguration.mail.smtp.port} | The SMTP server port number set on the server configuration. |
${iServerConfiguration.mail.administrator} | The administrator email set on the server configuration. |
Service connector examples - Navigation connector
The navigation connector allows the designer to specify, through the form editor, three actions on form elements:
- hide fields or fragments;
- make fields editable;
- make fields mandatory.
The purpose of this example is to give you an overview of the various mechanisms the Connectors Framework brings to you by creating a navigation service connector.
Developing a connector is quite straightforward. You just need to create the following elements:
- Runtime and Editor Java classes;
- an XML definition file;
- and a string resource XML file.
You can download the example here.
Define the connector, the services and set up their configuration
This file should be available from the relative path WEB-INF\storage<custom><connectors>\education-navigation.xml
.
<?xml version="1.0" encoding="UTF-8"?>
<connectors>
<connector name="navigation" label="navigation-connector.label" description="navigation-connector.description"
version="1.0" company="Visiativ Software">
<services>
<service name="hideElements" label="service.navigation.hideElements.label"
description="service.navigation.hideElements.description" useExternalDataConnection="false">
<class qualifiedName="com.axemble.education.connectors.navigation.HideElementsServiceConnector"/>
<icons>
<icon name="small" path="navigation/hidefield.png"/>
<icon name="medium" path=""/>
<icon name="large" path=""/>
</icons>
<configuration>
<class qualifiedName="com.axemble.education.connectors.navigation.HideElementsServiceConnectorEditor"/>
<section name="settings" label="service.navigation.hideElements.section.settings.label">
<fields>
<!-- hide elements -->
<field name="fldElementsChoices"
label="service.navigation.hideElements.selectElements.label"
description="service.navigation.hideElements.selectElements.description"
ctrl="textselectlist" mode="write" throw-events="true" mandatory="true"
string-value="fromValue">
<options>
<option key="fromValue" labelid="LG_FROM_VALUE"/>
<option key="fromField" labelid="LG_FROM_FIELD"/>
</options>
</field>
<field name="fldElementsValue" label="service.navigation.hideElements.elementsValue.label"
description="service.navigation.hideElements.elementsValue.description" ctrl="text"
mandatory="true" maxlength="64" defaultValue=""/>
<field name="fldElementsField" label="service.navigation.hideElements.elementsField.label"
description="service.navigation.hideElements.elementsField.description"
ctrl="selector" mandatory="true" screen="Property" method="select" multiple="true"/>
<field name="fldValue" label="service.navigation.hideElements.value.label"
description="service.navigation.hideElements.value.description" ctrl="checkbox"/>
</fields>
</section>
</configuration>
<inputs>
<input name="iResource" type="com.axemble.vdoc.sdk.interfaces.IResource"/>
<input name="iWorkflowInstance" type="com.axemble.vdoc.sdk.interfaces.IWorkflowInstance"/>
</inputs>
<outputs>
<output name="result" type="java.lang.Boolean"/>
<output name="error" type="java.lang.String"/>
<output name="errorMessage" type="java.lang.String"/>
</outputs>
<entry-points>
<connectors-library familyName="education"/>
</entry-points>
<supported-events>
<front-end-events>
<resource-definition>
<form>
<events>
<event name="onAfterLoad" default="true"/>
</events>
</form>
</resource-definition>
</front-end-events>
</supported-events>
</service>
<service name="mandatoryField" label="service.navigation.mandatoryField.label" description="service.navigation.mandatoryField.description" useExternalDataConnection="false">
<class qualifiedName="com.axemble.education.connectors.navigation.MandatoryFieldServiceConnector"/>
<icons>
<icon name="small" path="navigation/mandatoryfield.png"/>
<icon name="medium" path=""/>
<icon name="large" path=""/>
</icons>
<configuration>
<class qualifiedName="com.axemble.education.connectors.navigation.MandatoryFieldServiceConnectorEditor"/>
<section name="settings" label="service.navigation.mandatoryField.section.settings.label">
<fields>
<field name="fldElementsField" label="service.navigation.mandatoryField.elementsField.label"
description="service.navigation.mandatoryField.elementsField.description"
ctrl="selector" mandatory="true" screen="Property" method="select" multiple="true"/>
<field name="fldValue" label="service.navigation.mandatoryField.value.label"
description="service.navigation.mandatoryField.value.description" ctrl="checkbox"/>
</fields>
</section>
</configuration>
<inputs>
<input name="iResource" type="com.axemble.vdoc.sdk.interfaces.IResource"/>
<input name="iWorkflowInstance" type="com.axemble.vdoc.sdk.interfaces.IWorkflowInstance"/>
</inputs>
<outputs>
<output name="result" type="java.lang.Boolean"/>
<output name="error" type="java.lang.String"/>
<output name="errorMessage" type="java.lang.String"/>
</outputs>
<entry-points>
<connectors-library familyName="education"/>
</entry-points>
<supported-events>
<front-end-events>
<resource-definition>
<form>
<events>
<event name="onAfterLoad" default="true"/>
</events>
</form>
</resource-definition>
</front-end-events>
</supported-events>
</service>
<service name="editField" label="service.navigation.editField.label" description="service.navigation.editField.description" useExternalDataConnection="false">
<class qualifiedName="com.axemble.education.connectors.navigation.EditFieldServiceConnector"/>
<icons>
<icon name="small" path="navigation/editfield.png"/>
<icon name="medium" path=""/>
<icon name="large" path=""/>
</icons>
<configuration>
<class qualifiedName="com.axemble.education.connectors.navigation.EditFieldServiceConnectorEditor"/>
<section name="settings" label="service.navigation.editField.section.settings.label">
<fields>
<field name="fldElementsField" label="service.navigation.editField.elementsField.label"
description="service.navigation.editField.elementsField.description" ctrl="selector"
edit="true" screen="Property" method="select" multiple="true"/>
<field name="fldValue" label="service.navigation.editField.value.label"
description="service.navigation.editField.value.description" ctrl="checkbox"/>
</fields>
</section>
</configuration>
<inputs>
<input name="iResource" type="com.axemble.vdoc.sdk.interfaces.IResource"/>
<input name="iWorkflowInstance" type="com.axemble.vdoc.sdk.interfaces.IWorkflowInstance"/>
</inputs>
<outputs>
<output name="result" type="java.lang.Boolean"/>
<output name="error" type="java.lang.String"/>
<output name="errorMessage" type="java.lang.String"/>
</outputs>
<entry-points>
<connectors-library familyName="education"/>
</entry-points>
<supported-events>
<front-end-events>
<resource-definition>
<form>
<events>
<event name="onAfterLoad" default="true"/>
</events>
</form>
</resource-definition>
</front-end-events>
</supported-events>
</service>
</services>
</connector>
</connectors>
Create the runtime class for the hide element connector
Declare the package, the imports and the class
package com.axemble.education.connectors.navigation;
import java.util.Collection;
import com.axemble.education.connectors.navigation.common.CommonNavigationServiceConnector;
import com.axemble.education.connectors.navigation.common.CommonNavigationServiceConnectorEditor;
import com.axemble.vdoc.sdk.interfaces.IProperty;
import com.axemble.vdoc.sdk.interfaces.IResourceController;
import com.axemble.vdp.utils.StringUtils;
public class HideElementsServiceConnector extends CommonNavigationServiceConnector
Example execute method
@Override
public int execute( IContext context, int eventType, String eventName, Element customElement ) {
try {
IResourceController resourceController = getWorkflowModule().getResourceController( getResource() );
boolean value = ( (Boolean)getServiceDefinition().getValue( CommonNavigationServiceConnectorEditor.FIELD_VALUE ) ).booleanValue();
String option = (String)getServiceDefinition().getValue( HideElementsServiceConnectorEditor.FIELD_ELEMENTS_CHOICES );
switch ( option ) {
case HideElementsServiceConnectorEditor.OPTION_FROM_VALUE : {
String stringMarkers = (String)getServiceDefinition().getValue( HideElementsServiceConnectorEditor.FIELD_ELEMENTS_VALUE );
if ( StringUtils.isNotEmpty( stringMarkers ) ) {
stringMarkers = stringMarkers.trim();
String[] markers = StringUtils.split( stringMarkers, "," );
for ( int i = 0 ; i < markers.length ; i++ ) {
String marker = markers[i];
resourceController.showBodyBlock( marker, !value );
}
}
}
break;
case HideElementsServiceConnectorEditor.OPTION_FROM_FIELD : {
Collection<IProperty> properties = (Collection<IProperty>)getServiceDefinition().getValue( CommonNavigationServiceConnectorEditor.FIELD_ELEMENTS_FIELD );
if ( properties != null ) {
for ( IProperty property : properties ) {
resourceController.setHidden( property.getName(), value );
}
}
}
break;
}
} catch( Exception e ) {
String errorMessage = getErrorMessage();
this.getServiceOutputs().addOutput( OUTPUT_RESULT, Boolean.FALSE );
this.getServiceOutputs().addOutput( OUTPUT_ERROR_MESSAGE, errorMessage );
this.getServiceOutputs().addOutput( OUTPUT_ERROR_NUMBER, -900 );
buildError( eventType, errorMessage, e );
return IConnectorExecutionStatus.STOP;
}
this.getServiceOutputs().addOutput( OUTPUT_RESULT, Boolean.TRUE );
return IConnectorExecutionStatus.STOP_ASYNCHRONOUS;
}
Example beforeCompletion and afterCompletion methods
@Override
public void beforeCompletion( IContext context, Element customElement ) {
super.beforeCompletion( context, customElement );
}
@Override
public void afterCompletion( IContext context, Element customElement, boolean committed ) {
super.afterCompletion( context, customElement, committed );
}