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; 018 019import java.io.Serializable; 020import java.util.HashMap; 021import java.util.Map; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025import org.apache.commons.scxml2.Context; 026import org.apache.commons.scxml2.SCXMLSystemContext; 027 028/** 029 * Simple Context wrapping a map of variables. 030 * 031 */ 032public class SimpleContext implements Context, Serializable { 033 034 /** Serial version UID. */ 035 private static final long serialVersionUID = 1L; 036 /** Implementation independent log category. */ 037 private static final Log DEFAULT_LOG = LogFactory.getLog(Context.class); 038 private Log log = DEFAULT_LOG; 039 /** The parent Context to this Context. */ 040 private Context parent; 041 /** The Map of variables and their values in this Context. */ 042 private Map<String, Object> vars; 043 044 protected final SCXMLSystemContext systemContext; 045 046 /** 047 * Constructor. 048 * 049 */ 050 public SimpleContext() { 051 this(null, null); 052 } 053 054 /** 055 * Constructor. 056 * 057 * @param parent A parent Context, can be null 058 */ 059 public SimpleContext(final Context parent) { 060 this(parent, null); 061 } 062 063 /** 064 * Constructor. 065 * 066 * @param parent A parent Context, can be null 067 * @param initialVars A pre-populated initial variables map 068 */ 069 public SimpleContext(final Context parent, final Map<String, Object> initialVars) { 070 this.parent = parent; 071 this.systemContext = parent instanceof SCXMLSystemContext ? 072 (SCXMLSystemContext) parent : parent != null ? parent.getSystemContext() : null; 073 if (initialVars == null) { 074 setVars(new HashMap<String, Object>()); 075 } else { 076 setVars(this.vars = initialVars); 077 } 078 } 079 080 /** 081 * Assigns a new value to an existing variable or creates a new one. 082 * The method searches the chain of parent Contexts for variable 083 * existence. 084 * 085 * @param name The variable name 086 * @param value The variable value 087 * @see org.apache.commons.scxml2.Context#set(String, Object) 088 */ 089 public void set(final String name, final Object value) { 090 if (getVars().containsKey(name)) { //first try to override local 091 setLocal(name, value); 092 } else if (parent != null && parent.has(name)) { //then check for global 093 parent.set(name, value); 094 } else { //otherwise create a new local variable 095 setLocal(name, value); 096 } 097 } 098 099 /** 100 * Get the value of this variable; delegating to parent. 101 * 102 * @param name The variable name 103 * @return Object The variable value 104 * @see org.apache.commons.scxml2.Context#get(java.lang.String) 105 */ 106 public Object get(final String name) { 107 Object localValue = getVars().get(name); 108 if (localValue != null) { 109 return localValue; 110 } else if (parent != null) { 111 return parent.get(name); 112 } else { 113 return null; 114 } 115 } 116 117 /** 118 * Check if this variable exists, delegating to parent. 119 * 120 * @param name The variable name 121 * @return boolean true if this variable exists 122 * @see org.apache.commons.scxml2.Context#has(java.lang.String) 123 */ 124 public boolean has(final String name) { 125 return (hasLocal(name) || (parent != null && parent.has(name))); 126 } 127 128 /** 129 * Check if this variable exists, only checking this Context 130 * 131 * @param name The variable name 132 * @return boolean true if this variable exists 133 * @see org.apache.commons.scxml2.Context#hasLocal(java.lang.String) 134 */ 135 public boolean hasLocal(final String name) { 136 return (getVars().containsKey(name)); 137 } 138 139 /** 140 * Clear this Context. 141 * 142 * @see org.apache.commons.scxml2.Context#reset() 143 */ 144 public void reset() { 145 getVars().clear(); 146 } 147 148 /** 149 * Get the parent Context, may be null. 150 * 151 * @return Context The parent Context 152 * @see org.apache.commons.scxml2.Context#getParent() 153 */ 154 public Context getParent() { 155 return parent; 156 } 157 158 /** 159 * Get the SCXMLSystemContext for this Context, should not be null unless this is the root Context 160 * 161 * @return The SCXMLSystemContext in a chained Context environment 162 */ 163 public final SCXMLSystemContext getSystemContext() { 164 return systemContext; 165 } 166 167 /** 168 * Assigns a new value to an existing variable or creates a new one. 169 * The method allows to shaddow a variable of the same name up the 170 * Context chain. 171 * 172 * @param name The variable name 173 * @param value The variable value 174 * @see org.apache.commons.scxml2.Context#setLocal(String, Object) 175 */ 176 public void setLocal(final String name, final Object value) { 177 getVars().put(name, value); 178 if (log.isDebugEnabled()) { 179 log.debug(name + " = " + String.valueOf(value)); 180 } 181 } 182 183 /** 184 * Set the variables map. 185 * 186 * @param vars The new Map of variables. 187 */ 188 protected void setVars(final Map<String, Object> vars) { 189 this.vars = vars; 190 } 191 192 /** 193 * Get the Map of all local variables in this Context. 194 * 195 * @return Returns the vars. 196 */ 197 public Map<String, Object> getVars() { 198 return vars; 199 } 200 201 /** 202 * Set the log used by this <code>Context</code> instance. 203 * 204 * @param log The new log. 205 */ 206 protected void setLog(final Log log) { 207 this.log = log; 208 } 209 210 /** 211 * Get the log used by this <code>Context</code> instance. 212 * 213 * @return Log The log being used. 214 */ 215 protected Log getLog() { 216 return log; 217 } 218 219} 220