All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openbp.server.context.TransientTokenContextService Maven / Gradle / Ivy

There is a newer version: 0.9.11
Show newest version
/*
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package org.openbp.server.context;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

import org.openbp.common.CollectionUtil;
import org.openbp.common.CommonUtil;
import org.openbp.common.property.PropertyAccessUtil;
import org.openbp.common.property.PropertyException;
import org.openbp.core.engine.EngineException;

/**
 * This token context service will keept its contexts entirely in memory.
 * The {@link #addContext} method will add the contexts to execute to the internal context list.
 * The {@link #getExecutableContexts} method will check this internal list for pending contexts.
 * The contexts are not persisted by the service.
 *
 * @author Author: Heiko Erhardt
 */
public class TransientTokenContextService extends TokenContextServiceBase
{
	// Note that we use maps instead of lists in order to prevent the situation that a context is being schedulded for execution multiple times.
	// This might lead to unexpected results otherwise.

	/** Map of managed contexts */
	private final HashMap contexts;

	/** Map of managed workflows */
	private final HashMap workflowTasks;

	/**
	 * Default constructor.
	 */
	public TransientTokenContextService()
	{
		contexts = new LinkedHashMap();
		workflowTasks = new HashMap();
	}

	//////////////////////////////////////////////////
	// @@ General
	//////////////////////////////////////////////////

	/**
	 * Begins the transaction.
	 */
	public void begin()
	{
		// No begin
	}

	/**
	 * Flushes the recent changes (if supported).
	 * Does nothing for this implementation.
	 */
	public void flush()
	{
		// No flushing
	}

	/**
	 * Commits the recent changes (if supported).
	 * Does nothing for this implementation.
	 */
	public void commit()
	{
		// No commit/rollback support
	}

	/**
	 * Rolls back the recent changes (if supported).
	 * Does nothing for this implementation.
	 */
	public void rollback()
	{
		// No commit/rollback support
	}

	/**
	 * Clears any this token context service might have.
	 */
	public void clearCache()
	{
		// No cache
	}

	//////////////////////////////////////////////////
	// @@ Context management
	//////////////////////////////////////////////////

	/**
	 * Adds a context to the service.
	 *
	 * @param context Context to add
	 * @return The saved object
	 */
	public TokenContext addContext(final TokenContext context)
	{
		synchronized (contexts)
		{
			contexts.put(context, context);
		}
		return context;
	}

	/**
	 * Save the changes to a context.
	 *
	 * @param context Context to save
	 * @return The saved object
	 */
	public TokenContext saveContext(final TokenContext context)
	{
		return context;
	}

	/**
	 * Remvoes a context from the service.
	 *
	 * @param context Context to remove
	 */
	public void deleteContext(final TokenContext context)
	{
		synchronized (contexts)
		{
			contexts.remove(context);
		}
	}

	/**
	 * Evicts the context from the cache of the underlying persistence layer, if any.
	 *
	 * @param context Context to evict
	 */
	public void evictContext(final TokenContext context)
	{
		// Do nothing
	}

	/**
	 * Returns an iterator of token contexts that match the given selection criteria.
	 *
	 * @param criteria Criteria to match
	 * @param maxResults Maximum number of result records or 0 for all (ignored)
	 * @return An iterator of {@link TokenContext} objects
	 */
	public Iterator getContexts(final TokenContextCriteria criteria, final int maxResults)
	{
		ArrayList ret = new ArrayList();

		synchronized (contexts)
		{
			// Copy due to ConcurrentModificationException 
			for (Iterator it = contexts.keySet().iterator(); it.hasNext();)
			{
				TokenContext context = (TokenContext) it.next();

				if (match(context, criteria))
					ret.add(context);
			}
		}

		return ret.iterator();
	}

	/**
	 * Gets the token context objects that are ready to execute.
	 *
	 * @param maxResults Maximum number of result records or 0 for all (ignored)
	 * @return An iterator of {@link TokenContext} objects
	 */
	public Iterator getExecutableContexts(final int maxResults)
	{
		ArrayList ret = new ArrayList();

		synchronized (contexts)
		{
			for (Iterator it = contexts.keySet().iterator(); it.hasNext();)
			{
				TokenContext context = (TokenContext) it.next();

				if (context.getLifecycleRequest() == LifecycleRequest.RESUME)
					ret.add(context);
			}
		}

		// Sort by priority
		Collections.sort(ret, new Comparator()
		{
			public int compare(Object o1, Object o2)
			{
				int p1 = ((TokenContext) o1).getPriority();
				int p2 = ((TokenContext) o2).getPriority();
				return p1 - p2;
			}
		});

		return ret.iterator();
	}

	private boolean match(final TokenContext context, final TokenContextCriteria criteria)
	{
		if (criteria != null)
		{
			if (criteria.getId() != null)
			{
				if (! criteria.getId().equals(context.getId()))
					return false;
			}

			if (criteria.getLifecycleState() != null)
			{
				if (! criteria.getLifecycleState().equals(new Integer(context.getLifecycleState())))
					return false;
			}

			if (criteria.getModel() != null)
			{
				if (! criteria.getModel().equals(context.getExecutingModel()))
					return false;
			}

			if (! matchCriterionBase(context, criteria))
				return false;
		}

		return true;
	}

	/**
	 * Gets the child contexts of the specified context.
	 *
	 * @param context Context
	 * @return An iterator of child contexts
	 */
	public Iterator getChildContexts(TokenContext context)
	{
		ArrayList children = new ArrayList();
		CollectionUtil.addAll(children, context.getChildContexts());
		return children.iterator();
	}

	/**
	 * Changes the state of all matching token context objects in the context store.
	 * This method can be used to fix the state and request of selected or running contexts after a system crash.
	 *
	 * @param fromLifecycleState Lifecycle state to search for
	 * @param toLifecycleState New lifecycle state for matching context objects
	 * @param toLifecycleRequest New lifecycle request for matching context objects
	 * @param nodeId System name of the system these contexts have been assigned to or null for all context objects
	 * @return The number of tokens that have been updated
	 */
	public int changeContextState(int fromLifecycleState, int toLifecycleState, int toLifecycleRequest, String nodeId)
	{
		int ret = 0;
		synchronized (contexts)
		{
			// Copy due to ConcurrentModificationException 
			for (Iterator it = contexts.keySet().iterator(); it.hasNext();)
			{
				TokenContext context = (TokenContext) it.next();

				if (context.getLifecycleState() != fromLifecycleState)
				{
					continue;
				}

				if (nodeId != null)
				{
					if (! nodeId.equals(context.getNodeId()))
					{
						continue;
					}
				}

				context.setLifecycleState(toLifecycleState);
				context.setLifecycleRequest(toLifecycleRequest);
				++ret;
			}
		}
		return ret;
	}

	//////////////////////////////////////////////////
	// @@ Workflow task management
	//////////////////////////////////////////////////

	/**
	 * Adds a workflow task to the service.
	 *
	 * @param workflowTask workflow task to add
	 * @return The saved object
	 */
	public WorkflowTask addWorkflowTask(final WorkflowTask workflowTask)
	{
		synchronized (workflowTasks)
		{
			workflowTasks.put(workflowTask, workflowTask);
		}
		return workflowTask;
	}

	/**
	 * Save the changes to a workflow task.
	 *
	 * @param workflowTask workflow task to save
	 * @return The saved object
	 */
	public WorkflowTask saveWorkflowTask(final WorkflowTask workflowTask)
	{
		return workflowTask;
	}

	/**
	 * Removes a workflow task from the service.
	 *
	 * @param workflowTask workflow task to remove
	 */
	public void deleteWorkflowTask(final WorkflowTask workflowTask)
	{
		synchronized (workflowTasks)
		{
			workflowTasks.remove(workflowTask);
		}
	}

	/**
	 * Returns an iterator of workflow tasks that match the given selection criteria.
	 *
	 * @param criteria Criteria to match
	 * @return An iterator of {@link WorkflowTask} objects
	 */
	public Iterator getworkflowTasks(final WorkflowTaskCriteria criteria)
	{
		ArrayList ret = new ArrayList();

		synchronized (workflowTasks)
		{
			// Copy due to ConcurrentModificationException 
			for (Iterator it = workflowTasks.keySet().iterator(); it.hasNext();)
			{
				WorkflowTask workflowTask = (WorkflowTask) it.next();

				if (match(workflowTask, criteria))
					ret.add(workflowTask);
			}
		}

		return ret.iterator();
	}

	private boolean match(final WorkflowTask task, final WorkflowTaskCriteria criteria)
	{
		if (criteria.getId() != null)
		{
			if (! criteria.getId().equals(task.getId()))
				return false;
		}

		if (criteria.getStatus() != null)
		{
			if (! criteria.getStatus().equals(new Integer(task.getStatus())))
				return false;
		}

		if (criteria.getModel() != null)
		{
			if (! criteria.getModel().equals(task.getTokenContext().getExecutingModel()))
				return false;
		}

		if (criteria.getName() != null)
		{
			if (! criteria.getName().equals(task.getName()))
				return false;
		}

		if (criteria.getStepName() != null)
		{
			if (! criteria.getStepName().equals(task.getStepName()))
				return false;
		}

		if (criteria.getRoleId() != null)
		{
			if (! criteria.getRoleId().equals(task.getRoleId()))
				return false;
		}

		if (criteria.getUserId() != null)
		{
			if (! criteria.getUserId().equals(task.getUserId()))
				return false;
		}

		if (! matchCriterionBase(task, criteria))
			return false;

		return true;
	}

	private boolean matchCriterionBase(final Object obj, final CriteriaBase criteria)
	{
		for (Iterator it = criteria.getCustomCriteriaKeys(); it.hasNext();)
		{
			String key = (String) it.next();
			Object value = criteria.getCustomCriteriaValue(key);
			if (value != null)
			{
				try
				{
					Object actualValue = PropertyAccessUtil.getProperty(obj, key);
					if (! CommonUtil.equalsNull(value, actualValue))
						return false;
				}
				catch (PropertyException e)
				{
					throw new EngineException("Expression.CustomCriteriumPropertyAccessFailed", e);
				}
			}
		}
		return true;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy