1
2
3
4
5
6
7
8
9
10
11 package org.astrogrid.jes.jobscheduler.impl.groovy;
12
13 import org.astrogrid.component.descriptor.ComponentDescriptor;
14 import org.astrogrid.jes.jobscheduler.impl.groovy.GroovyInterpreterFactory.Pickler;
15
16 import org.apache.commons.logging.Log;
17 import org.apache.commons.logging.LogFactory;
18
19 import com.thoughtworks.xstream.XStream;
20 import com.thoughtworks.xstream.alias.ClassMapper;
21 import com.thoughtworks.xstream.converters.Converter;
22 import com.thoughtworks.xstream.converters.MarshallingContext;
23 import com.thoughtworks.xstream.converters.UnmarshallingContext;
24 import com.thoughtworks.xstream.converters.basic.NullConverter;
25 import com.thoughtworks.xstream.converters.basic.StringConverter;
26 import com.thoughtworks.xstream.converters.collections.MapConverter;
27 import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
28 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
29 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
30 import com.thoughtworks.xstream.io.xml.DomDriver;
31
32 import java.io.Reader;
33 import java.io.Writer;
34 import java.lang.ref.SoftReference;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39
40 import junit.framework.Test;
41
42 /*** pickler implementation.
43 * @modified made the reference to xstream a soft reference, so it gets collected if needed. We can always create another one - and the extra memory might just get us through.
44 * @author Noel Winstanley nw@jb.man.ac.uk 28-Jul-2004
45 *
46 */
47 public class XStreamPickler implements Pickler , ComponentDescriptor{
48 /***
49 * Commons Logger for this class
50 */
51 private static final Log logger = LogFactory.getLog(XStreamPickler.class);
52
53
54 /*** made xstream static, for efficiencies sake - don't know how expensive it is to create this object,
55 * but only one instance is ever needed, and is only ever called from the scheduler thread.
56 *
57 * <p>
58 * but then got concerned about keeping a 3rd part object around indefinately- no idea how big it is, or whether it
59 * leaks. Decided to use a 'pooling' pattern - resuse each instance a few times, and then create a new one.
60 */
61
62 private SoftReference xstream = new SoftReference(createXstream());
63
64 private int useCount = 0;
65
66 private static final int USE_LIMIT = 500;
67 /***
68 * @see org.astrogrid.jes.jobscheduler.impl.groovy.GroovyInterpreterFactory.Pickler#marshallInterpreter(java.io.Writer, org.astrogrid.jes.jobscheduler.impl.groovy.GroovyInterpreter)
69 */
70 public void marshallInterpreter(Writer out, GroovyInterpreter interp) {
71 getXstream().toXML(interp,out);
72 }
73
74 /***
75 * @see org.astrogrid.jes.jobscheduler.impl.groovy.GroovyInterpreterFactory.Pickler#unmarshallInterpreter(java.io.Reader)
76 */
77 public GroovyInterpreter unmarshallInterpreter(Reader in){
78 return (GroovyInterpreter)getXstream().fromXML(in);
79 }
80
81 /***
82 * @see org.astrogrid.jes.jobscheduler.impl.groovy.GroovyInterpreterFactory.Pickler#unmarshallRuleStore(java.io.Reader)
83 */
84 public Map unmarshallRuleStore(Reader reader) {
85 List l = (List )getXstream().fromXML(reader);
86 Map m = new HashMap();
87 for (int i = 0; i < l.size(); i++) {
88 Rule r = (Rule)l.get(i);
89 m.put(r.getName(),r);
90 }
91 return m;
92 }
93
94 XStream getXstream() {
95 XStream x = (XStream)xstream.get();
96 if (useCount++ > USE_LIMIT || x == null) {
97 logger.info("re-creating xstream");
98 useCount = 0;
99 xstream.clear();
100 x = createXstream();
101 xstream = new SoftReference(x);
102 }
103 return x;
104 }
105 private XStream createXstream() {
106 XStream x = new XStream(new PureJavaReflectionProvider(),new DomDriver());
107 x.registerConverter(new RuleStoreConvertor(x.getClassMapper(),"class"));
108 x.alias("interpreter",GroovyInterpreter.class);
109 x.alias("rules",ArrayList.class);
110 x.alias("rule",Rule.class);
111 x.alias("state",ActivityStatus.class);
112 x.alias("states",ActivityStatusStore.class);
113 x.alias("vars",Vars.class);
114 return x;
115 }
116
117 /*** subclass of map convertor, for converting rule stores.
118 * and also serialzes the indexScript.
119 * dunno what I'm doing here really - came up with this via reverse-engineering and trial and error.
120 * @author Noel Winstanley nw@jb.man.ac.uk 05-Nov-2004
121 *
122 */
123 protected static class RuleStoreConvertor extends MapConverter {
124
125 public void marshal(Object o, HierarchicalStreamWriter w, MarshallingContext cxt) {
126 RuleStore rs = (RuleStore)o;
127 w.startNode("indexScript");
128 if (rs.indexScript == null) {
129 n.marshal(rs.indexScript,w,cxt);
130 } else {
131 s.marshal(rs.indexScript,w,cxt);
132 }
133 w.endNode();
134 super.marshal(o, w, cxt);
135 }
136 public Object unmarshal(HierarchicalStreamReader r, UnmarshallingContext cxt) {
137 r.moveDown();
138 String index = (String)cxt.convertAnother(r.getValue(),String.class);
139 r.moveUp();
140 RuleStore rs = (RuleStore) super.unmarshal(r, cxt);
141 if (index.trim().length() > 0) {
142 rs.indexScript = index;
143 }
144 return rs;
145 }
146 public boolean canConvert(Class arg0) {
147 return arg0.equals(RuleStore.class) ;
148 }
149 /*** Construct a new RuleStoreConvertor
150 * @param arg0
151 * @param arg1
152 */
153 public RuleStoreConvertor(ClassMapper arg0, String arg1) {
154 super(arg0, arg1);
155 s = new StringConverter();
156 n = new NullConverter();
157 }
158 private final Converter s;
159 private final Converter n;
160 }
161
162 /***
163 * @see org.astrogrid.component.descriptor.ComponentDescriptor#getName()
164 */
165 public String getName() {
166 return "XStream Pickler";
167 }
168
169 /***
170 * @see org.astrogrid.component.descriptor.ComponentDescriptor#getDescription()
171 */
172 public String getDescription() {
173 return "Pickler for interpreter that uses XStream to serialize interpreter state to xml";
174 }
175
176 /***
177 * @see org.astrogrid.component.descriptor.ComponentDescriptor#getInstallationTest()
178 */
179 public Test getInstallationTest() {
180 return null;
181 }
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229