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.

mail treatment overview mail treatment overview

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 );
}