001: package org.drools.jsr94.rules;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.LinkedList;
022: import java.util.List;
023: import java.util.Map;
024:
025: import javax.rules.Handle;
026: import javax.rules.InvalidHandleException;
027: import javax.rules.InvalidRuleSessionException;
028: import javax.rules.ObjectFilter;
029: import javax.rules.RuleExecutionSetNotFoundException;
030: import javax.rules.RuleRuntime;
031: import javax.rules.StatefulRuleSession;
032:
033: import org.drools.FactException;
034: import org.drools.FactHandle;
035: import org.drools.StatefulSession;
036: import org.drools.WorkingMemory;
037: import org.drools.jsr94.rules.admin.RuleExecutionSetImpl;
038: import org.drools.jsr94.rules.admin.RuleExecutionSetRepository;
039:
040: /**
041: * The Drools implementation of the <code>StatefulRuleSession</code> interface
042: * which is a representation of a stateful rules engine session. A stateful
043: * rules engine session exposes a stateful rule execution API to an underlying
044: * rules engine. The session allows arbitrary objects to be added and removed to
045: * and from the rule session state. Additionally, objects currently part of the
046: * rule session state may be updated. <p/> There are inherently side-effects to
047: * adding objects to the rule session state. The execution of a RuleExecutionSet
048: * can add, remove and update objects in the rule session state. The objects in
049: * the rule session state are therefore dependent on the rules within the
050: * <code>RuleExecutionSet</code> as well as the rule engine vendor's specific
051: * rule engine behavior. <p/> <code>Handle</code> instances are used by the
052: * rule engine vendor to track <code>Object</code>s added to the rule session
053: * state. This allows multiple instances of equivalent <code>Object</code>s
054: * to be added to the session state and identified, even after serialization.
055: *
056: * @see StatefulRuleSession
057: *
058: * @author N. Alex Rupp (n_alex <at>codehaus.org)
059: * @author <a href="mailto:thomas.diesler@softcon-itec.de">thomas diesler </a>
060: */
061: public class StatefulRuleSessionImpl extends AbstractRuleSessionImpl
062: implements StatefulRuleSession {
063: // ----------------------------------------------------------------------
064: // Constructors
065: // ----------------------------------------------------------------------
066:
067: /**
068: *
069: */
070: private static final long serialVersionUID = 400L;
071:
072: private StatefulSession session;
073:
074: /**
075: * Gets the <code>RuleExecutionSet</code> for this URI and associates it
076: * with a RuleBase.
077: *
078: * @param bindUri
079: * the URI the <code>RuleExecutionSet</code> has been bound to
080: * @param properties
081: * additional properties used to create the
082: * <code>RuleSession</code> implementation.
083: *
084: * @throws RuleExecutionSetNotFoundException
085: * if there is no rule set under the given URI
086: */
087: StatefulRuleSessionImpl(final String bindUri, final Map properties,
088: final RuleExecutionSetRepository repository)
089: throws RuleExecutionSetNotFoundException {
090: super (repository);
091: setProperties(properties);
092:
093: final RuleExecutionSetImpl ruleSet = (RuleExecutionSetImpl) repository
094: .getRuleExecutionSet(bindUri);
095:
096: if (ruleSet == null) {
097: throw new RuleExecutionSetNotFoundException(
098: "no execution set bound to: " + bindUri);
099: }
100:
101: this .setRuleExecutionSet(ruleSet);
102:
103: initSession(true);
104: }
105:
106: /**
107: * Initialize this <code>RuleSession</code>
108: * with a new <code>WorkingMemory</code>.
109: */
110: protected void initSession(boolean keepReference) {
111: this .session = this .getRuleExecutionSet().newStatefulSession(
112: keepReference);
113:
114: final Map props = this .getProperties();
115: if (props != null) {
116: for (final Iterator iterator = props.entrySet().iterator(); iterator
117: .hasNext();) {
118: final Map.Entry entry = (Map.Entry) iterator.next();
119: this .session.setGlobal((String) entry.getKey(), entry
120: .getValue());
121: }
122: }
123: }
124:
125: // ----------------------------------------------------------------------
126: // Instance methods
127: // ----------------------------------------------------------------------
128:
129: /**
130: * Returns <code>true</code> if the given object is contained within
131: * rulesession state of this rule session.
132: *
133: * @param objectHandle
134: * the handle to the target object.
135: *
136: * @return <code>true</code> if the given object is contained within the
137: * rule session state of this rule session.
138: */
139: public boolean containsObject(final Handle objectHandle) {
140: if (objectHandle instanceof FactHandle) {
141: return this .session.getObject((FactHandle) objectHandle) != null;
142: }
143:
144: return false;
145: }
146:
147: /**
148: * Adds a given object to the rule session state of this rule session. The
149: * argument to this method is Object because in the non-managed env. not all
150: * objects should have to implement Serializable. If the
151: * <code>RuleSession</code> is <code>Serializable</code> and it contains
152: * non-serializable fields a runtime exception will be thrown.
153: *
154: * @param object
155: * the object to be added.
156: *
157: * @return the Handle for the newly added Object
158: *
159: * @throws InvalidRuleSessionException
160: * on illegal rule session state.
161: */
162: public Handle addObject(final Object object)
163: throws InvalidRuleSessionException {
164: checkRuleSessionValidity();
165: return (Handle) this .session.insert(object);
166: }
167:
168: /**
169: * Adds a <code>List</code> of <code>Object</code>s to the rule session
170: * state of this rule session.
171: *
172: * @param objList
173: * the objects to be added.
174: *
175: * @return a <code>List</code> of <code>Handle</code>s, one for each
176: * added <code>Object</code>. The <code>List</code> must be
177: * ordered in the same order as the input <code>objList</code>.
178: *
179: * @throws InvalidRuleSessionException
180: * on illegal rule session state.
181: */
182: public List addObjects(final List objList)
183: throws InvalidRuleSessionException {
184: checkRuleSessionValidity();
185:
186: final List handles = new ArrayList();
187:
188: for (final Iterator objectIter = objList.iterator(); objectIter
189: .hasNext();) {
190: handles.add(addObject(objectIter.next()));
191: }
192: return handles;
193: }
194:
195: /**
196: * Notifies the rules engine that a given object in the rule session state
197: * has changed. <p/> The semantics of this call are equivalent to calling
198: * <code>removeObject</code> followed by <code>addObject</code>. The
199: * original <code>Handle</code> is rebound to the new value for the
200: * <code>Object</code> however.
201: *
202: * @param objectHandle
203: * the handle to the original object.
204: * @param newObject
205: * the new object to bind to the handle.
206: *
207: * @throws InvalidRuleSessionException
208: * on illegal rule session state.
209: * @throws InvalidHandleException
210: * if the input <code>Handle</code> is no longer valid
211: */
212: public void updateObject(final Handle objectHandle,
213: final Object newObject) throws InvalidRuleSessionException,
214: InvalidHandleException {
215: checkRuleSessionValidity();
216:
217: if (objectHandle instanceof FactHandle) {
218: this .session.update((FactHandle) objectHandle, newObject);
219: } else {
220: throw new InvalidHandleException("invalid handle");
221:
222: }
223: }
224:
225: /**
226: * Removes a given object from the rule session state of this rule session.
227: *
228: * @param handleObject
229: * the handle to the object to be removed from the rule session
230: * state.
231: *
232: * @throws InvalidRuleSessionException
233: * on illegal rule session state.
234: * @throws InvalidHandleException
235: * if the input <code>Handle</code> is no longer valid
236: */
237: public void removeObject(final Handle handleObject)
238: throws InvalidRuleSessionException, InvalidHandleException {
239: checkRuleSessionValidity();
240:
241: if (handleObject instanceof FactHandle) {
242: this .session.retract((FactHandle) handleObject);
243: } else {
244: throw new InvalidHandleException("invalid handle");
245: }
246: }
247:
248: /**
249: * Executes the rules in the bound rule execution set using the objects
250: * present in the rule session state. This will typically modify the rule
251: * session state - and may add, remove or update <code>Object</code>s
252: * bound to <code>Handle</code>s.
253: *
254: * @throws InvalidRuleSessionException
255: * on illegal rule session state.
256: */
257: public void executeRules() throws InvalidRuleSessionException {
258: checkRuleSessionValidity();
259: this .session.fireAllRules();
260: }
261:
262: /**
263: * @see StatefulRuleSessionImpl
264: */
265: public Object getObject(final Handle handle)
266: throws InvalidRuleSessionException, InvalidHandleException {
267: checkRuleSessionValidity();
268:
269: if (handle instanceof FactHandle) {
270: return this .session.getObject((FactHandle) handle);
271: } else {
272: throw new InvalidHandleException("invalid handle");
273: }
274: }
275:
276: /**
277: * Returns a <code>List</code> of the <code>Handle</code>s being used
278: * for object identity.
279: *
280: * @return a <code>List</code> of <code>Handle</code>s present in the
281: * currect state of the rule session.
282: */
283: public List getHandles() {
284: return IteratorToList
285: .convert(this .session.iterateFactHandles());
286: }
287:
288: /**
289: * Returns a List of all objects in the rule session state of this rule
290: * session. The objects should pass the default filter test of the default
291: * <code>RuleExecutionSet</code> filter (if present). <p/> This may not
292: * neccessarily include all objects added by calls to <code>addObject</code>,
293: * and may include <code>Object</code>s created by side-effects. The
294: * execution of a <code>RuleExecutionSet</code> can add, remove and update
295: * objects as part of the rule session state. Therefore the rule session
296: * state is dependent on the rules that are part of the executed
297: * <code>RuleExecutionSet</code> as well as the rule vendor's specific
298: * rule engine behavior.
299: *
300: * @return a <code>List</code> of all objects part of the rule session
301: * state.
302: *
303: * @throws InvalidRuleSessionException
304: * on illegal rule session state.
305: */
306: public List getObjects() throws InvalidRuleSessionException {
307: checkRuleSessionValidity();
308: return getObjects(getRuleExecutionSet().getObjectFilter());
309: }
310:
311: /**
312: * Returns a <code>List</code> over the objects in rule session state of
313: * this rule session. The objects should pass the filter test on the
314: * specified <code>ObjectFilter</code>. <p/> This may not neccessarily
315: * include all objects added by calls to <code>addObject</code>, and may
316: * include <code>Object</code>s created by side-effects. The execution of
317: * a <code>RuleExecutionSet</code> can add, remove and update objects as
318: * part of the rule session state. Therefore the rule session state is
319: * dependent on the rules that are part of the executed
320: * <code>RuleExecutionSet</code> as well as the rule vendor's specific
321: * rule engine behavior.
322: *
323: * @param filter
324: * the object filter.
325: *
326: * @return a <code>List</code> of all the objects in the rule session
327: * state of this rule session based upon the given object filter.
328: *
329: * @throws InvalidRuleSessionException
330: * on illegal rule session state.
331: */
332: public List getObjects(final ObjectFilter filter)
333: throws InvalidRuleSessionException {
334: checkRuleSessionValidity();
335:
336: return IteratorToList.convert(this .session
337: .iterateObjects(new ObjectFilterAdapter(filter)));
338: }
339:
340: /**
341: * Resets this rule session. Calling this method will bring the rule session
342: * state to its initial state for this rule session and will reset any other
343: * state associated with this rule session.
344: * <p/>
345: * A reset will not reset the state on the default object filter for a
346: * <code>RuleExecutionSet</code>.
347: */
348: public void reset() {
349: // stateful rule sessions should not be high load, thus safe to keep references
350: initSession(true);
351: }
352:
353: public int getType() throws InvalidRuleSessionException {
354: return RuleRuntime.STATEFUL_SESSION_TYPE;
355: }
356:
357: /**
358: * Releases all resources used by this rule session.
359: * This method renders this rule session unusable until
360: * it is reacquired through the <code>RuleRuntime</code>.
361: */
362: public void release() {
363: if (this .session != null) {
364: this .session.dispose();
365: }
366: this .session = null;
367: super .release();
368: }
369:
370: /**
371: * Ensures this <code>RuleSession</code> is not
372: * in an illegal rule session state.
373: *
374: * @throws InvalidRuleSessionException on illegal rule session state.
375: */
376: protected void checkRuleSessionValidity()
377: throws InvalidRuleSessionException {
378: if (this .session == null) {
379: throw new InvalidRuleSessionException(
380: "invalid rule session");
381: }
382: }
383: }
|