/** * */ package org.springmodules.jsr94.core; import java.rmi.RemoteException; import java.util.Map; import javax.rules.InvalidHandleException; import javax.rules.InvalidRuleSessionException; import javax.rules.RuleExecutionSetNotFoundException; import javax.rules.RuleRuntime; import javax.rules.RuleSession; import javax.rules.RuleSessionCreateException; import javax.rules.RuleSessionTypeUnsupportedException; import javax.rules.StatefulRuleSession; import javax.rules.StatelessRuleSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springmodules.jsr94.Jsr94InvalidHandleException; import org.springmodules.jsr94.Jsr94InvalidRuleSessionException; import org.springmodules.jsr94.Jsr94RemoteException; import org.springmodules.jsr94.Jsr94RuleExecutionSetNotFoundException; import org.springmodules.jsr94.Jsr94RuleSessionCreateException; import org.springmodules.jsr94.Jsr94RuleSessionTypeUnsupportedException; import org.springmodules.jsr94.rulesource.RuleSource; import org.springmodules.jsr94.support.Jsr94Accessor; import org.springmodules.jsr94.support.StatefulRuleSessionCallback; import org.springmodules.jsr94.support.StatelessRuleSessionCallback; import org.springframework.transaction.support.TransactionSynchronizationManager; /** * Jsr94Template class contains methods for executing stateful and stateless * rule sessions. * * @see org.springmodules.jsr94.support.Jsr94Accessor * @author janm */ public class Jsr94Template extends Jsr94Accessor { /** * Log instance for this class */ protected final Log logger = LogFactory.getLog(Jsr94Template.class); /** * Creates default instance of Jsr94Template; typically used when constructing the template * in a bean factory. Use setRuleSource() to set the RuleSource, which must exist prior to construction * of this class. * * @see Jsr94Accessor#setRuleSource(RuleSource) */ public Jsr94Template() { // noop } /** * Creates instance of Jsr94Template with the specified ruleSource. Typically used outside of * bean factory. * * @param ruleSource The ruleSource to be used for this template */ public Jsr94Template(RuleSource ruleSource) { setRuleSource(ruleSource); afterPropertiesSet(); } /** * Creates instance of RuleSession, maps the checked exceptions and returns a valid RuleSession * * @param uri The uri of the session * @param properties The properties for the session * @param type The type of the session * @return RuleSession instance */ private RuleSession createRuleSession(final String uri, final Map properties, final int type) { try { return getRuleSource().createSession(uri, properties, type); } catch (RuleExecutionSetNotFoundException ex) { throw new Jsr94RuleExecutionSetNotFoundException(ex); } catch (RuleSessionTypeUnsupportedException ex) { throw new Jsr94RuleSessionTypeUnsupportedException(ex); } catch (RuleSessionCreateException ex) { throw new Jsr94RuleSessionCreateException(ex); } catch (RemoteException ex) { throw new Jsr94RemoteException(ex); } } /** * Releases a stateless session * * @param session The session to be released */ private void releaseStatelessSession(final StatelessRuleSession session) { if (session == null) throw new IllegalArgumentException("session must not be null"); try { session.release(); } catch (InvalidRuleSessionException ex) { // this is impossible since we are releasing stateless session! throw new Jsr94InvalidRuleSessionException(ex); } catch (RemoteException ex) { throw new Jsr94RemoteException(ex); } } /** * Releases a stateful session * * @param session The session to be released */ private void releaseStatefulSession(final StatefulRuleSession session) { if (session == null) throw new IllegalArgumentException("session must not be null"); try { session.release(); } catch (InvalidRuleSessionException ex) { // possible throw new Jsr94InvalidRuleSessionException(ex); } catch (RemoteException ex) { throw new Jsr94RemoteException(ex); } } /** * Executes a stateless rule session * * @param uri The ruleset uri * @param properties The proeprties for the session * @param callback The executor callback * @return Value returned by the executor implementation */ public Object executeStateless(final String uri, final Map properties, final StatelessRuleSessionCallback callback) { StatelessRuleSession session = (StatelessRuleSession) createRuleSession(uri, properties, RuleRuntime.STATELESS_SESSION_TYPE); try { return callback.execute(session); } catch (InvalidRuleSessionException ex) { throw new Jsr94InvalidRuleSessionException(ex); } catch (RemoteException ex) { throw new Jsr94RemoteException(ex); } finally { releaseStatelessSession(session); } } /** * Executes a stateful rule session. If called in a transaction, the session will be closed upon * transaction completion; otherwise it will be closed when the callback returns. * @param uri The ruleset uri * @param properties The properties for the stateful rule session * @param callback The callback * @return The result of the callback execution */ public Object executeStateful(final String uri, final Map properties, final StatefulRuleSessionCallback callback) { // get the session boolean synchronize = TransactionSynchronizationManager.isSynchronizationActive(); if (!synchronize) { logger.debug("Not running in transaction; the session will be closed when the callback returns."); } StatefulRuleSession session = (StatefulRuleSession) TransactionSynchronizationManager.getResource(getRuleSource()); if (session == null) { logger.debug("Opening StatefulRuleSession"); session = (StatefulRuleSession) createRuleSession(uri, properties, RuleRuntime.STATEFUL_SESSION_TYPE); if (synchronize) TransactionSynchronizationManager.bindResource(getRuleSource(), session); } try { return callback.execute(session); } catch (InvalidRuleSessionException ex) { throw new Jsr94InvalidRuleSessionException(ex); } catch (RemoteException ex) { throw new Jsr94RemoteException(ex); } catch (InvalidHandleException ex) { throw new Jsr94InvalidHandleException(ex); } finally { if (!synchronize) { releaseStatefulSession(session); logger.debug("Closed session"); } } } }