001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.scxml2.env.groovy; 018 019import java.io.ByteArrayInputStream; 020import java.io.ByteArrayOutputStream; 021import java.io.IOException; 022import java.io.ObjectInputStream; 023import java.io.ObjectOutputStream; 024import java.io.ObjectStreamClass; 025import java.util.Iterator; 026import java.util.Map; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.apache.commons.scxml2.Context; 031import org.apache.commons.scxml2.env.SimpleContext; 032 033import groovy.lang.Closure; 034 035/** 036 * Groovy Context implementation for Commons SCXML. 037 */ 038public class GroovyContext extends SimpleContext { 039 040 private static final long serialVersionUID = 1L; 041 042 private static final Log log = LogFactory.getLog(GroovyContext.class); 043 044 private String scriptBaseClass; 045 private GroovyEvaluator evaluator; 046 private GroovyContextBinding binding; 047 private Map<String, Object> vars; 048 049 GroovyContextBinding getBinding() { 050 if (binding == null) { 051 binding = new GroovyContextBinding(this); 052 } 053 return binding; 054 } 055 056 /** 057 * Constructor. 058 */ 059 public GroovyContext() { 060 super(); 061 } 062 063 /** 064 * Constructor with initial vars. 065 * 066 * @param initialVars The initial set of variables. 067 */ 068 public GroovyContext(final Context parent, final Map<String, Object> initialVars, GroovyEvaluator evaluator) { 069 super(parent, initialVars); 070 this.evaluator = evaluator; 071 } 072 073 /** 074 * Constructor with parent context. 075 * 076 * @param parent The parent context. 077 */ 078 public GroovyContext(final Context parent, GroovyEvaluator evaluator) { 079 super(parent); 080 this.evaluator = evaluator; 081 } 082 083 protected GroovyEvaluator getGroovyEvaluator() { 084 return evaluator; 085 } 086 087 protected void setGroovyEvaluator(GroovyEvaluator evaluator) { 088 this.evaluator = evaluator; 089 } 090 091 @Override 092 public Map<String, Object> getVars() { 093 return vars; 094 } 095 096 @Override 097 protected void setVars(final Map<String, Object> vars) { 098 this.vars = vars; 099 } 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}