Skip to content

Getting started

Idriss Neumann edited this page Oct 15, 2017 · 91 revisions

Table of content

Installation with maven

Maven repository

<repository>
    <id>vo-lifecycle-mvn-repo</id>
    <url>https://raw.github.com/vo-lifecycle/vo-lifecycle-core/mvn-repo/</url>
    <snapshots>
        <enabled>true</enabled>
        <updatePolicy>always</updatePolicy>
    </snapshots>
</repository>

Maven dependency

<dependency>
    <groupId>vo-lifecycle</groupId>
    <artifactId>vo-lifecycle-core</artifactId>
    <version>${vo-lifecycle.version}</version>
</dependency>

How to use

Main components

  • org.volifecycle.lifecycle components:
    • LifeCycleSimpleActionImpl: this class implements LifeCycleAction and is an abstract class which can be extended in order to write a validation state change condition or other workflow's step;
    • LifeCycleTransitionImpl: this class implements LifeCycleTransition and is a bean which represents a transition (change of one state to another) with a target state and a collection of LifeCycleAction;
    • LifeCycleCompositeActionImpl: this class implements LifeCycleAction and is provided to represents one of output states when a transition allows multiple output states. This class contains a set of LifeCycleSimpleActionImpl.
    • LifeCycleStateImpl: this class implements LifeCycleState and is a bean which represents a value object state and which can be instantiated with a collection of LifeCycleTransitionImpl;
    • LifeCycleManagerImpl: this class implements LifeCycleManager and is a bean which can be instantiated with a collection of LifeCycleState and which can be used to run a requested transition;
    • LifeCycleChangeSaver: this interface should be implemented in order to save success transition with the following information:
      • LifeCycle id
      • Transition id
      • Value object id
      • Value object type
      • Date of change
      • State in (state before transition)
      • State out (state after transition)
    • LogLifeCycleChangeSaverImpl: this class is the default used implementation of LifeCycleChangeSaver (with a slf4j info trace only).
  • org.volifecycle.transco components:
    • TranscoImpl: this class is an implementation of Transco (which extends java.util.map) and allows us to use a bidirectional hash table.
  • org.volifecycle.event components:
    • EventManager: this interface should be implemented in order to save some event (validation failure for example) with the following information:
      • Actor which is responsible for this event
      • Date of event
      • Value object (which is affected by the event) id
      • Value object (which is affected by the event) type
      • Type of event (failure, ...)
      • Custom message
    • LogEventManagerImpl: this class is the default used implementation of EventManager (with a slf4j info trace only);
    • DiffDetectorImpl: this is a bean which can be instantiated in order to compare and save all differences between both versions of a value object (and his children) with an implementation of EventManager.

BPMN to VO LifeCycle

  • First case (blue case):
    • 1 transition (LifeCycleTransitionImpl)
    • 3 simple actions (? extends LifeCycleSimpleActionImpl): C1, C2, C3 which returns "true" or "false"
    • only one target state "STATE 1"
  • Second case (black case):
    • 1 transition (LifeCycleTransitionImpl) with two target states ("STATE 1" and "STATE 2")
    • 1 composite action (LifeCycleCompositeActionImpl) with:
      • the target state "STATE 2"
      • 4 simple actions (? extends LifeCycleSimpleActionImpl): C1, C2, C3, C4
    • 1 composite action (LifeCycleCompositeActionImpl) with:
      • the target state "STATE 3"
      • 3 simple actions (? extends LifeCycleSimpleActionImpl): C1, C2, C3 (!C4 is implicit)

Spring integration sample

Managing states's transitions for a value object

Here is a BPMN case:

Here is a sample of single Spring configuration file to manage all states's transitions for this case:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- Transco table which can be used in the adapter -->
    <bean id="vo1TranscoStates" class="org.volifecycle.transco.impl.TranscoImpl">
        <property name="map">
            <map key-type="java.lang.String" value-type="java.lang.String">
                <entry key="STATE1" value="{id in database}" />
                <entry key="STATE2" value="{id in database}" />
                <entry key="STATE3" value="{id in database}" />
            </map>
        </property>
    </bean>

    <!-- Event manager and change saver (not mandatory) -->
    <bean id="customEvtManager" class="org.yourproject.event.CustomEventManager" />
    <bean id="cusomChangeSaver" class="org.yourproject.event.CustomChangeSaver" />

    <!-- Adapters declarations -->
    <bean id="vo1Adapter" class="org.yourproject.adapter.VO1Adapter" />

    <!-- Actions declarations -->
    <bean id="actionCheckDateValidated" class="org.yourproject.actions.CheckIsDateValidated">
        <property name="id" value="actionCheckDateValidated" />
        <property name="description" value="Assert : the object have got a setted validation date" />
    </bean>

    <bean id="actionCompositeCase1" class="org.volifecycle.lifecycle.impl.LifeCycleCompositeActionImpl">
        <property name="id" value="actionCompositeCase1" />
        <property name="description" value="Case 1 : date is valid" />
        <property name="targetState" value="STATE2" />

        <!-- Opérations de vérification -->
        <property name="actions">
            <list>
                <ref bean="actionCheckDateValidated" />
            </list>
        </property>
    </bean>

    <bean id="actionCompositeCase2" class="org.volifecycle.lifecycle.impl.LifeCycleCompositeActionImpl">
        <property name="id" value="actionCompositeCase2" />
        <property name="description" value="Case 2 : date isn't valid" />
        <property name="targetState" value="STATE3" />

        <!-- Opérations de vérification -->
        <property name="actions">
            <list>
            </list>
        </property>
    </bean>

    <!-- Transitions declarations -->
    <bean id="transitionToState2OrState3" class="org.volifecycle.lifecycle.impl.LifeCycleTransitionImpl">
        <!-- Type and description -->
        <property name="type" value="manual" />
        <property name="description" value="Change to STATE2" />

        <!-- Target state -->
        <property name="targetStates">
            <list>
                <value>STATE2</value>
                <value>STATE3</value>
            </list>
        </property>

        <!-- Actions/checkers -->
        <property name="actions">
            <list>
                <ref bean="actionCompositeCase1" />
                <ref bean="actionCompositeCase2" />
            </list>
        </property>
    </bean>

    <!-- States declarations -->
    <bean id="STATE1" class="org.volifecycle.lifecycle.impl.LifeCycleStateImpl">
        <!-- Id and description -->
        <property name="id" value="STATE1" />
        <property name="description" value="State 1" />

        <!-- Transitions by state id -->
        <property name="transitionsById">
            <map key-type="java.lang.String" value-type="org.volifecycle.lifecycle.impl.LifeCycleTransitionImpl">
                <entry key="TR_ST2_OR_ST3" value-ref="transitionToState2OrState3" />
            </map>
        </property>
    </bean>

    <bean id="STATE2" class="org.volifecycle.lifecycle.impl.LifeCycleStateImpl">
        <!-- Id and description -->
        <property name="id" value="STATE2" />
        <property name="description" value="State 2" />

        <!-- Transitions by state id -->
        <property name="transitionsById">
            <map key-type="java.lang.String" value-type="org.volifecycle.lifecycle.impl.LifeCycleTransitionImpl">
            </map>
        </property>
    </bean>

    <bean id="STATE3" class="org.volifecycle.lifecycle.impl.LifeCycleStateImpl">
        <!-- Id and description -->
        <property name="id" value="STATE3" />
        <property name="description" value="State 3" />

        <!-- Transitions by state id -->
        <property name="transitionsById">
            <map key-type="java.lang.String" value-type="org.volifecycle.lifecycle.impl.LifeCycleTransitionImpl">
            </map>
        </property>
    </bean>

     <!-- Lifecycle managers declaration -->
     <bean id="vo1LifeCycleManager" class="org.volifecycle.lifecycle.impl.LifeCycleManagerImpl">
        <!-- Id and description -->
        <property name="id" value="VO1_LIFECYCLE" />
        <property name="description" value="VO1 Lifecycle" />

        <!-- Lifecycle's state -->
        <property name="statesById">
            <map key-type="java.lang.String" value-type="org.volifecycle.lifecycle.impl.LifeCycleStateImpl">
                <entry key="STATE1" value-ref="STATE1" />
                <entry key="STATE2" value-ref="STATE2" />
                <entry key="STATE3" value-ref="STATE3" />
            </map>
        </property>

        <property name="adapter" ref="vo1Adapter" />
        <property name="evtManager" ref="customEvtManager" />
        <property name="saver" ref="cusomChangeSaver" />
     </bean>
</beans>

Managing diff detector on both versions of a value object

Here is a sample of single Spring configuration file to manage diff detector on both versions of a value object:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- Event manager and change saver (not mandatory) -->
    <bean id="customEvtManager" class="org.yourproject.event.CustomEventManager" />

	<!-- listeners -->
	<bean id="valueObjectListener" class="org.volifecycle.event.ClassListener">
		<property name="className" value="org.yourproject.vo.ValueObject" />
		<property name="properties">
			<list>
				<value>code</value>
				<value>label</value>
			</list>
		</property>
	</bean>
	
	<bean id="subValueObjectListener" class="org.volifecycle.event.ClassListener">
		<property name="className" value="org.yourproject.vo.SubValueObject" />
		<property name="properties">
			<list>
				<value>something</value>
			</list>
		</property>
	</bean>

    <!--  diff detector bean -->
    <bean id="voDiffDetector" class="org.volifecycle.event.impl.DiffDetectorImpl">
    	<property name="evtManager" ref="customEvtManager" />
    	<property name="classListeners">
    		<list>
    			<ref bean="valueObjectListener" />
    			<ref bean="subValueObjectListener" />
    		</list>
    	</property>
    </bean>
</beans>

Code examples

This examples are provided for JEE projects using Spring and JPA/Hibernate.

Diff dectector implementation with JPA repository

Here is an example of repository with new implementations of saveAndFlush method:

  • You could extends this interface with your own repositories and use @Repository annotation;
  • This interface is Java 8 compliant with default methods. In lower versions of Java, you can extends SimpleJpaRepository or use Hibernate interceptors instead.
import java.io.Serializable;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.volifecycle.event.DiffDetector;
import org.volifecycle.lifecycle.LifeCycleAdapter;

/**
 * Custom repository with diffDetector information saving
 * 
 * @author Idriss Neumann <neumann.idriss@gmail.com>
 *
 * @param <T> entity type
 * @param <I> id type
 */
public interface DiffDetectorRepository<T, I extends Serializable> extends JpaSpecificationExecutor<T>, JpaRepository<T, I> {
    /**
     * New implementation of saveAndFlush with parent informations
     */
    default T saveAndFlush(I id, String parentId, String parentType, T entity, DiffDetector<T, LifeCycleAdapter<T>> detector) {
        T previous = (null == id) ? null : (T) findOne(id);
        if (null != detector) {
            detector.compare(previous, entity, parentId, parentType);
        }
        return saveAndFlush(entity);
    }

    /**
     * New implementation of saveAndFlush
     */
    default T saveAndFlush(I id, T entity, DiffDetector<T, LifeCycleAdapter<T>> detector) {
        T previous = (null == id) ? null : (T) findOne(id);
        if (null != detector) {
            detector.compare(previous, entity);
        }
        return saveAndFlush(entity);
    }
}

Implementation of EventManager with JPA/Repository

import org.springframework.beans.factory.annotation.Autowired;
import org.volifecycle.event.EventManager;
import org.volifecycle.event.vo.Event;
import org.volifecycle.utils.BeanMapperFactory;

/**
 * Example of implementation of EventManager
 * 
 * @author Idriss Neumann <neumann.idriss@gmail.com>
 *
 */
public class CustomEventManager implements EventManager {
    @Autowired
    private YourRepository repository;

    /**
     * {@inheritDoc}
     */
    @Override
    public void logEvent(Event src) {
        YourEntity target = BeanMapperFactory.getInstance().map(src, YourEntity.class);
        repository.save(target);
    }
}