View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.scxml2.env.groovy;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.ObjectInputStream;
23  import java.io.ObjectOutputStream;
24  import java.io.ObjectStreamClass;
25  import java.util.Iterator;
26  import java.util.Map;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.commons.scxml2.Context;
31  import org.apache.commons.scxml2.env.SimpleContext;
32  
33  import groovy.lang.Closure;
34  
35  /**
36   * Groovy Context implementation for Commons SCXML.
37   */
38  public class GroovyContext extends SimpleContext {
39  
40      private static final long serialVersionUID = 1L;
41  
42      private static final Log log = LogFactory.getLog(GroovyContext.class);
43  
44      private String scriptBaseClass;
45      private GroovyEvaluator evaluator;
46      private GroovyContextBinding binding;
47      private Map<String, Object> vars;
48  
49      GroovyContextBinding getBinding() {
50          if (binding == null) {
51              binding = new GroovyContextBinding(this);
52          }
53          return  binding;
54      }
55  
56      /**
57       * Constructor.
58       */
59      public GroovyContext() {
60          super();
61      }
62  
63      /**
64       * Constructor with initial vars.
65       *
66       * @param initialVars The initial set of variables.
67       */
68      public GroovyContext(final Context parent, final Map<String, Object> initialVars, GroovyEvaluator evaluator) {
69          super(parent, initialVars);
70          this.evaluator = evaluator;
71      }
72  
73      /**
74       * Constructor with parent context.
75       *
76       * @param parent The parent context.
77       */
78      public GroovyContext(final Context parent, GroovyEvaluator evaluator) {
79          super(parent);
80          this.evaluator = evaluator;
81      }
82  
83      protected GroovyEvaluator getGroovyEvaluator() {
84          return evaluator;
85      }
86  
87      protected void setGroovyEvaluator(GroovyEvaluator evaluator) {
88          this.evaluator = evaluator;
89      }
90  
91      @Override
92      public Map<String, Object> getVars() {
93          return vars;
94      }
95  
96      @Override
97      protected void setVars(final Map<String, Object> vars) {
98          this.vars = vars;
99      }
100 
101     protected void setScriptBaseClass(String scriptBaseClass) {
102         this.scriptBaseClass = scriptBaseClass;
103     }
104 
105     protected String getScriptBaseClass() {
106         if (scriptBaseClass != null) {
107             return scriptBaseClass;
108         }
109         if (getParent() instanceof GroovyContext) {
110             return ((GroovyContext)getParent()).getScriptBaseClass();
111         }
112         return null;
113     }
114 
115     private void writeObject(ObjectOutputStream out) throws IOException {
116         boolean closureErased = false;
117         if (vars != null) {
118             Iterator<Map.Entry<String, Object>> iterator = getVars().entrySet().iterator();
119             while (iterator.hasNext()) {
120                 Map.Entry<String, Object> entry = iterator.next();
121                 if (entry.getValue() != null && entry.getValue() instanceof Closure) {
122                     iterator.remove();
123                     closureErased = true;
124                 }
125             }
126             if (closureErased) {
127                 log.warn("Encountered and removed Groovy Closure(s) in the GroovyContext during serialization: these are not supported for (de)serialization");
128             }
129         }
130         out.writeObject(this.scriptBaseClass);
131         out.writeObject(this.evaluator);
132         out.writeObject(this.binding);
133         ByteArrayOutputStream bout = new ByteArrayOutputStream();
134         new ObjectOutputStream(bout).writeObject(this.vars);
135         out.writeObject(bout.toByteArray());
136     }
137 
138     @SuppressWarnings("unchecked")
139     private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {
140         this.scriptBaseClass = (String)in.readObject();
141         this.evaluator = (GroovyEvaluator)in.readObject();
142         this.binding = (GroovyContextBinding)in.readObject();
143         byte[] bytes  = (byte[])in.readObject();
144         if (evaluator != null) {
145             this.vars = (Map<String, Object>)
146                     new ObjectInputStream(new ByteArrayInputStream(bytes)) {
147                         protected Class resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {
148                             return Class.forName(osc.getName(), true, evaluator.getGroovyClassLoader());
149                         }
150                     }.readObject();
151         }
152         else {
153             this.vars = (Map<String, Object>)new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
154         }
155     }
156 }