View Javadoc

1   package cz.cuni.amis.pogamut.sposh.engine;
2   
3   import cz.cuni.amis.pogamut.sposh.elements.Arguments;
4   import cz.cuni.amis.pogamut.sposh.elements.Arguments.Argument;
5   import cz.cuni.amis.pogamut.sposh.elements.FormalParameters;
6   import cz.cuni.amis.pogamut.sposh.elements.Result;
7   import java.util.Arrays;
8   import java.util.HashMap;
9   import java.util.HashSet;
10  import java.util.Map;
11  import java.util.Map.Entry;
12  import java.util.Set;
13  
14  /**
15   * This class is responsible for storing and passing arguments throught the posh plan.
16   * Unnamed varibales are named as number (e.g. "0", "1"...), named variables
17   * have same name as in plan.
18   * @author Honza
19   */
20  final public class VariableContext {
21      private VariableContext parent;
22      private Map<String, Object> args = new HashMap<String, Object>();
23  
24      public VariableContext() {
25          this.parent = null;
26      }
27  
28      /**
29       * Create argument context from formal parameters.
30       */
31  /*    VariableContext(FormalParameters params) {
32          for (FormalParameters.Parameter param : params) {
33              if (args.put(param.getName(), param.getDefaultValue()) != null) {
34                  throw new IllegalArgumentException(
35                          "Two parameters with same name \"" + param.getName()
36                          + "\", default value \"" + param.getDefaultValue() + "\".");
37              }
38          }
39      }
40  */
41      
42      /**
43       * Create new VariableContext that will contain only variables from call arguments.
44       * @param callArgs
45       */
46      public VariableContext(VariableContext ctx, Arguments callArgs) {
47          this.parent = ctx;
48          for (Arguments.Argument param : callArgs) {
49              String argumentVariable = param.getParameterVariable();
50              if (argumentVariable != null) {
51                  args.put(param.getParameterName(), ctx.getValue(argumentVariable));
52              } else {
53                  args.put(param.getParameterName(), param.getValue());
54              }
55          }
56      }
57  
58      /**
59       * Create new variable context for diving into another function.
60       * New context will contain only variables from formal parameters, and its
61       * values will be values passed from call arguments or (if missing) default value
62       * from formal parametrs.
63       * 
64       * @param ctx
65       * @param callParameters
66       * @param formalParameters
67       */
68      public VariableContext(VariableContext ctx, Arguments callParameters, FormalParameters formalParameters) {
69          this.parent = ctx;
70          HashSet<Argument> unusedArgs = new HashSet<Argument>(callParameters);
71          for (int index = 0; index < formalParameters.size(); ++index) {
72              String ctxVariableName = formalParameters.get(index).getName();
73              Object ctxVariableValue = formalParameters.get(index).getDefaultValue();
74  
75              // if user supplied value, get it and put it into ctxVariableValue instead of default value
76              for (Argument param : callParameters) {
77                  String argumentName = param.getParameterName();
78                  try {
79                      int paramterIndex = Integer.parseInt(argumentName);
80                      if (index != paramterIndex) {
81                          continue;
82                      }
83                  } catch (NumberFormatException ex) {
84                      // nope, this is not a unnamed parametr, this one has a name
85                      // Is name among formal parametrs?
86                      String parameterName = param.getParameterName();
87                      if (!parameterName.equals(ctxVariableName))
88                          continue;
89                  }
90                  
91                  unusedArgs.remove(param);
92                  
93                  String variableName = param.getParameterVariable();
94                  if (variableName != null) {
95                      ctxVariableValue = ctx.getValue(variableName);
96                  } else {
97                      ctxVariableValue = param.getValue();
98                  }
99              }
100 
101             args.put(ctxVariableName, ctxVariableValue);
102         }
103         for (Argument unusedArg : unusedArgs) {
104             String variableName = unusedArg.getParameterVariable();
105             if (variableName != null) {
106                 args.put(unusedArg.getParameterName(), ctx.getValue(variableName));
107             } else {
108                 args.put(unusedArg.getParameterName(), unusedArg.getValue());
109             }
110         }
111     }
112 
113     /**
114      * Put another variable into this context
115      * @param parameterName name of new parameter
116      * @param value value of parameter
117      * @return old value for parameterName or null if it is a new parameter.
118      */
119     public synchronized Object put(String parameterName, Object value) {
120         return args.put(parameterName, value);
121     }
122 
123     /**
124      * Get keys of all variables in this context.
125      * @return
126      */
127     public synchronized String[] getKeys() {
128         Set<String> allKeys = new HashSet<String>();
129         VariableContext currentCtx = this;
130         while (currentCtx != null) {
131             allKeys.addAll(currentCtx.args.keySet());
132             currentCtx = currentCtx.parent;
133         }
134         return allKeys.toArray(new String[allKeys.size()]);
135     }
136 
137     /**
138      * Get value stored in the 
139      * @param variableName
140      * @return
141      * @throws IllegalArgumentException If such variable is not present.
142      */
143     public synchronized Object getValue(String variableName) {
144         if (args.containsKey(variableName)) {
145             return args.get(variableName);
146         }
147         if (this.parent != null) {
148             return parent.getValue(variableName);
149         }
150         throw new IllegalArgumentException("There is no variable in the context with name \"" + variableName + "\".");
151     }
152 
153     @Override
154     public String toString() {
155         StringBuilder sb = new StringBuilder();
156 
157         sb.append('[');
158         String[] list = new String[args.size()];
159         int index = 0;
160         for (Entry entry : args.entrySet()) {
161             list[index++] = entry.getKey() + "=" + Result.toLap(entry.getValue());
162         }
163         Arrays.sort(list);
164         for (int i = 0; i < list.length; ++i) {
165             if (i != 0) {
166                 sb.append(", ");
167             }
168             sb.append(list[i]);
169         }
170 
171         sb.append(']');
172         return sb.toString();
173     }
174 
175     public synchronized int size() {
176         return this.args.size();
177     }
178 
179     public boolean hasVariable(String variableName) {
180         if (args.containsKey(variableName)) {
181             return true;
182         }
183         if (this.parent != null) {
184             return parent.hasVariable(variableName);
185         }
186         return false;
187     }
188 }