# AfterUpdateCollectionCascader.java

    package org.codefilarete.stalactite.engine.cascade;

    import java.util.Collection;
    import java.util.Objects;
    import java.util.stream.Collectors;

    import org.codefilarete.tool.Duo;
    import org.codefilarete.tool.collection.Iterables;
    import org.codefilarete.stalactite.engine.EntityPersister;
    import org.codefilarete.stalactite.engine.listener.UpdateListener;

    /**
     * Cascader for update, written for one-to-many style of cascade where Trigger owns the relation to Target.
     * Target instances are updated after Trigger instances
     *
     * @param <TRIGGER> type of the elements that trigger this cascade
     * @param <TARGET> relation entity type
     * @author Guillaume Mary
     */
    public abstract class AfterUpdateCollectionCascader<TRIGGER, TARGET> implements UpdateListener<TRIGGER> {

    	private final EntityPersister<TARGET, ?> persister;

    	public AfterUpdateCollectionCascader(EntityPersister<TARGET, ?> persister) {
    		this.persister = persister;
    		this.persister.addUpdateListener(new UpdateListener<TARGET>() {
    			@Override
    			public void afterUpdate(Iterable<? extends Duo<TARGET, TARGET>> entities, boolean allColumnsStatement) {
    				postTargetUpdate(entities);
    			}
    		});
    	}

    	public EntityPersister<TARGET, ?> getPersister() {
    		return persister;
    	}

    	/**
    	 * Overridden to update Target instances of the Trigger instances.
    	 * @param entities source entities previously updated
    	 * @param allColumnsStatement true if all columns must be updated, false if only changed ones must be in the update statement
    	 */
    	@Override
    	public void afterUpdate(Iterable<? extends Duo<TRIGGER, TRIGGER>> entities, boolean allColumnsStatement) {
    		this.persister.update(Iterables.stream(entities).flatMap(e -> getTargets(e.getLeft(), e.getRight()).stream()).filter(Objects::nonNull)
    				.collect(Collectors.toList()), allColumnsStatement);
    	}

    	/**
    	 * To override for cases where Target instances need to be adapted after their update.
    	 *
    	 * @param entities entities updated by this listener
    	 */
    	protected abstract void postTargetUpdate(Iterable<? extends Duo<? extends TARGET, ? extends TARGET>> entities);

    	/**
    	 * Expected to give the Target instance of a Trigger (should simply give a field value of trigger)
    	 *
    	 * @param modifiedTrigger the source instance from which to take the target
    	 * @param unmodifiedTrigger the source instance from which to take the target
    	 * @return the linked objet or null if there's not (or shouldn't be persisted for whatever reason)
    	 */
    	protected abstract Collection<Duo<TARGET, TARGET>> getTargets(TRIGGER modifiedTrigger, TRIGGER unmodifiedTrigger);

    }