View Javadoc

1   /*$Id: RuleStore.java,v 1.6 2005/04/25 12:13:54 clq2 Exp $
2    * Created on 05-Nov-2004
3    *
4    * Copyright (C) AstroGrid. All rights reserved.
5    *
6    * This software is published under the terms of the AstroGrid 
7    * Software License version 1.2, a copy of which has been included 
8    * with this distribution in the LICENSE.txt file.  
9    *
10  **/
11  package org.astrogrid.jes.jobscheduler.impl.groovy;
12  
13  import org.apache.commons.logging.Log;
14  import org.apache.commons.logging.LogFactory;
15  import org.codehaus.groovy.control.CompilationFailedException;
16  
17  import groovy.lang.Script;
18  
19  import java.io.IOException;
20  import java.lang.ref.SoftReference;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.Map;
24  
25  /*** Container for rules.
26   * was previously storing rules in a hashmap. Need to add some extra methods on the side of this - but existing code expects to see a hashmap - hence
27   * this class extends rather than contains a hashmap.
28   * 
29   * @modified optimized selection of next valid rule, by pre-compiling all triggers into a large script that evaluates to the key of the rule to fire next.
30   * so we get to replace a linear traverse and evaluate each with a computation, followed by indexing into a map.
31   * @author Noel Winstanley nw@jb.man.ac.uk 05-Nov-2004
32   *
33   */
34  public class RuleStore extends HashMap {
35      /***
36       * Commons Logger for this class
37       */
38      private static final Log logger = LogFactory.getLog(RuleStore.class);
39  
40      /*** computed script that calculates id of next runnable rule */
41      protected String indexScript;
42      /***
43       * cached compiled up version of this 
44       */
45      protected transient SoftReference cachedIndexScript = null;
46          
47      /*** Construct a new RuleStore
48       * 
49       */
50      public RuleStore() {
51          super();
52      }
53  
54      /*** Construct a new RuleStore
55       * @param m
56       */
57      public RuleStore(Map m) {
58          super(m);
59      }
60  
61      /*** add a rule to the rulestore */
62      public void add( Rule r) {
63          invalidateCache();
64          super.put(r.getName(),r);
65      }
66  
67  
68      
69      /*** called whenever an update occurs, to signify cache has been invalidated.
70       * 
71       */
72      private void invalidateCache() {
73          // invalidates index expression, so remove it.
74          indexScript = null;
75          if (cachedIndexScript != null) {
76              cachedIndexScript.clear();
77          }
78          cachedIndexScript = null;
79      }
80  
81      public void clear() {
82          invalidateCache();
83          super.clear();
84      }
85      public Object put(Object key, Object value) {
86          invalidateCache();
87          return super.put(key, value);
88      }
89      public void putAll(Map m) {
90          invalidateCache();
91          super.putAll(m);
92      }
93      public Object remove(Object key) {
94          invalidateCache();
95          return super.remove(key);
96      }
97      /*** find a  triggered rule that can be validly executed
98       * @param stateMap
99       * 
100      * @return a triggered rule, or null if no rules are currently triggered.
101      * @throws ScriptEngineException if evaluati;on of triggers fails in some way.
102      */
103     public Rule findNext(JesShell shell, ActivityStatusStore stateMap) throws ScriptEngineException {
104         if (indexScript == null) {
105             logger.info("computing index");
106             computeIndexScript();
107         }
108         Script s = null;
109         if (cachedIndexScript != null) {
110             s = (Script)cachedIndexScript.get();
111         }
112         if (s == null) { // no cached script, either because it's been GC'd, or because a rule has been added, invalidating the last one.
113             logger.info("compiling up index");
114             try {
115                 s = shell.compileRuleScript(this.indexScript);
116             } catch (CompilationFailedException e) {
117                 logger.error("failed to compile index",e);
118                 throw new ScriptEngineException("failed to compile index",e);
119             } catch (IOException e) {
120                 logger.error("failed to compile index",e);                
121                 throw new ScriptEngineException("failed to compile index",e);
122             }            
123             cachedIndexScript = new SoftReference(s);
124         }
125         String id = shell.evaluateIndex(s,stateMap);  
126         if (id == null) {
127             return null;
128         }
129         Rule r = (Rule)get(id);
130         if (r == null) {
131             throw new RuleNotFoundException(id);
132         }
133         return r;
134     }
135     
136     /*** generates a function with an if-clause based on each rule's trigger. */
137     protected void computeIndexScript() {
138         StringBuffer script = new StringBuffer();
139         script.append("def index() {");
140         for (Iterator i = values().iterator(); i.hasNext();) {
141             Rule r = (Rule)i.next();
142             script.append("if (\n");
143             script.append(r.getTrigger());
144             script.append("\n){\nreturn '");
145             script.append(r.getName());
146             script.append("';\n}\n");
147         }
148         // otherwise
149         script.append("return null;");
150         script.append("}\nindex()");
151         this.indexScript = script.toString();
152     }
153     
154 
155 }
156 
157 
158 /* 
159 $Log: RuleStore.java,v $
160 Revision 1.6  2005/04/25 12:13:54  clq2
161 jes-nww-776-again
162 
163 Revision 1.5.44.1  2005/04/11 13:56:48  nw
164 no change
165 
166 Revision 1.5  2004/11/29 20:00:24  clq2
167 jes-nww-714
168 
169 Revision 1.4.12.1  2004/11/24 18:49:02  nw
170 sandboxing of script execution - first by a timeout,
171 later by java permissions system.
172 
173 Revision 1.4  2004/11/05 16:52:42  jdt
174 Merges from branch nww-itn07-scratchspace
175 
176 Revision 1.3.2.1  2004/11/05 16:11:26  nw
177 subclassed map to create rulestore.
178 added methods to compute index of triggers,
179 optimization: compiled index is cached in soft reference
180 location of next rule uses index
181  
182 */