comparison src/main/gov/nasa/jpf/util/json/JSONObject.java @ 0:61d41facf527

initial v8 import (history reset)
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Fri, 23 Jan 2015 10:14:01 -0800
parents
children db918c531e6d
comparison
equal deleted inserted replaced
-1:000000000000 0:61d41facf527
1 /*
2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
4 * All rights reserved.
5 *
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0.
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package gov.nasa.jpf.util.json;
20
21 import gov.nasa.jpf.JPF;
22 import gov.nasa.jpf.JPFException;
23 import gov.nasa.jpf.util.JPFLogger;
24 import gov.nasa.jpf.util.ObjectConverter;
25 import gov.nasa.jpf.vm.ChoiceGenerator;
26 import gov.nasa.jpf.vm.ClassInfo;
27 import gov.nasa.jpf.vm.ClinitRequired;
28 import gov.nasa.jpf.vm.ElementInfo;
29 import gov.nasa.jpf.vm.FieldInfo;
30 import gov.nasa.jpf.vm.Fields;
31 import gov.nasa.jpf.vm.MJIEnv;
32 import gov.nasa.jpf.vm.ThreadInfo;
33
34 import java.util.HashMap;
35 import java.util.Set;
36
37 /**
38 * Object parsed from JSON document.
39 * @author Ivan Mushketik
40 */
41 public class JSONObject{
42
43 private static final JPFLogger logger = JPF.getLogger("gov.nasa.jpf.util.json.JSONObject");
44
45 private HashMap<String, Value> keyValues = new HashMap<String, Value>();
46 private HashMap<String, CGCall> cgCalls = new HashMap<String, CGCall>();
47
48 void addValue(String key, Value value) {
49 if (keyValues.containsKey(key)) {
50 throw new JPFException("Attempt to add two nodes with the same key in JSON object");
51 }
52
53 keyValues.put(key, value);
54 }
55
56 /**
57 * Get value read from JSON document with specified key.
58 * @param key - value's key.
59 * @return read value.
60 */
61 public Value getValue(String key) {
62 return keyValues.get(key);
63 }
64
65 public String[] getValuesKeys() {
66 Set<String> valuesKeys = keyValues.keySet();
67 String[] result = new String[keyValues.size()];
68
69 valuesKeys.toArray(result);
70 return result;
71 }
72
73 public void addCGCall(String key, CGCall cgCall) {
74 if (cgCalls.containsKey(key)) {
75 throw new JPFException("Attempt to add two CG with the same key in JSON object");
76 }
77
78 cgCalls.put(key, cgCall);
79 }
80
81 public CGCall getCGCall(String key) {
82 return cgCalls.get(key);
83 }
84
85 public String[] getCGCallsKeys() {
86 Set<String> cgKeys = cgCalls.keySet();
87 String[] result = new String[cgKeys.size()];
88
89 cgKeys.toArray(result);
90 return result;
91 }
92
93 /**
94 * check if all required ClassInfos for this object have been initialized so
95 * that the caller can decide if it has to re-execute before proceeding
96 *
97 * NOTE - this currently does not support concrete field types that are subtypes
98 * of the respective field types
99 */
100 public boolean requiresClinitExecution (ClassInfo ci, ThreadInfo ti){
101 while (ci != null){
102 if (ci.pushRequiredClinits(ti)){
103 return true;
104 }
105
106 for (FieldInfo fi : ci.getDeclaredInstanceFields()) {
107 ClassInfo ciField = fi.getTypeClassInfo();
108 if (requiresClinitExecution(ciField, ti)){
109 return true;
110 }
111 }
112
113 ci = ci.getSuperClass();
114 }
115
116 return false;
117 }
118
119 //--- the fillers
120
121 // NOTE - (pcm) before calling this method you have to make sure all required
122 // types are initialized
123
124 public int fillObject (MJIEnv env, ClassInfo ci, ChoiceGenerator<?>[] cgs, String prefix) throws ClinitRequired {
125 int newObjRef = env.newObject(ci);
126 ElementInfo ei = env.getHeap().getModifiable(newObjRef);
127
128 // Fill all fields for this class until it has a super class
129 while (ci != null) {
130 FieldInfo[] fields = ci.getDeclaredInstanceFields();
131
132 for (FieldInfo fi : fields) {
133 String fieldName = fi.getName();
134 Value val = getValue(fieldName);
135 CGCall cgCall = getCGCall(fieldName);
136
137 // If a value was defined in JSON document
138 if (val != null) {
139 fillFromValue(fi, ei, val, env, cgs, prefix);
140
141 } else if (cgCall != null) {
142 // Value of this field should be taken from CG
143 String cgId = prefix + fieldName;
144 ChoiceGenerator<?> cg = getCGByID(cgs, cgId);
145 assert cg != null : "Expected CG with id " + cgId;
146
147 Object cgResult = cg.getNextChoice();
148
149 if (!fi.isReference()) {
150 convertPrimititve(ei, fi, cgResult);
151 } else {
152 int newFieldRef = ObjectConverter.JPFObjectFromJavaObject(env, cgResult);
153 ei.setReferenceField(fi, newFieldRef);
154 }
155 } else {
156 logger.warning("Value for field ", fi.getFullName(), " isn't specified");
157 }
158 }
159
160 ci = ci.getSuperClass();
161 }
162
163 return newObjRef;
164 }
165
166 private void fillFromValue(FieldInfo fi, ElementInfo ei, Value val, MJIEnv env, ChoiceGenerator<?>[] cgs, String prefix) {
167 String fieldName = fi.getName();
168 // Handle primitive types
169 if (!fi.isReference()) {
170 fillPrimitive(ei, fi, val);
171
172 } else {
173 if (isArrayType(fi.getType())) {
174 int newArrRef = createArray(env, fi.getTypeClassInfo(), val, cgs, prefix + fieldName);
175 ei.setReferenceField(fi, newArrRef);
176
177 } else {
178 Creator creator = CreatorsFactory.getCreator(fi.getType());
179 if (creator != null) {
180 int newSubObjRef = creator.create(env, fi.getType(), val);
181 ei.setReferenceField(fi, newSubObjRef);
182
183 } else {
184 // Not a special case. Fill it recursively
185 ClassInfo ciField = fi.getTypeClassInfo();
186 if (ciField.pushRequiredClinits(env.getThreadInfo())){
187 throw new ClinitRequired(ciField);
188 }
189
190 JSONObject jsonObj = val.getObject();
191 int fieldRef = MJIEnv.NULL;
192 if (jsonObj != null) {
193 fieldRef = jsonObj.fillObject(env, ciField, cgs, prefix + fieldName);
194 }
195 ei.setReferenceField(fi.getName(), fieldRef);
196 }
197 }
198 }
199 }
200
201
202 private static void fillPrimitive(ElementInfo ei, FieldInfo fi, Value val) {
203 String primitiveName = fi.getType();
204
205 if (primitiveName.equals("boolean")) {
206 ei.setBooleanField(fi, val.getBoolean());
207
208 } else if (primitiveName.equals("byte")) {
209 ei.setByteField(fi, val.getDouble().byteValue());
210
211 } else if (primitiveName.equals("short")) {
212 ei.setShortField(fi, val.getDouble().shortValue());
213
214 } else if (primitiveName.equals("int")) {
215 ei.setIntField(fi, val.getDouble().intValue());
216
217 } else if (primitiveName.equals("long")) {
218 ei.setLongField(fi, val.getDouble().longValue());
219
220 } else if (primitiveName.equals("float")) {
221 ei.setFloatField(fi, val.getDouble().floatValue());
222
223 } else if (primitiveName.equals("double")) {
224 ei.setDoubleField(fi, val.getDouble());
225 }
226 }
227
228 public int createArray(MJIEnv env, ClassInfo ciArray, Value value, ChoiceGenerator<?>[] cgs, String prefix) {
229 Value vals[] = value.getArray();
230
231 ClassInfo ciElement = ciArray.getComponentClassInfo();
232 String arrayElementType = ciElement.getName();
233 int arrayRef;
234
235 // Handle arrays of primitive types
236 if (arrayElementType.equals("boolean")) {
237 arrayRef = env.newBooleanArray(vals.length);
238 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef);
239 boolean bools[] = arrayEI.asBooleanArray();
240
241 for (int i = 0; i < vals.length; i++) {
242 bools[i] = vals[i].getBoolean();
243 }
244 } else if (arrayElementType.equals("byte")) {
245 arrayRef = env.newByteArray(vals.length);
246 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef);
247 byte bytes[] = arrayEI.asByteArray();
248
249 for (int i = 0; i < vals.length; i++) {
250 bytes[i] = vals[i].getDouble().byteValue();
251 }
252 } else if (arrayElementType.equals("short")) {
253 arrayRef = env.newShortArray(vals.length);
254 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef);
255 short shorts[] = arrayEI.asShortArray();
256
257 for (int i = 0; i < vals.length; i++) {
258 shorts[i] = vals[i].getDouble().shortValue();
259 }
260 } else if (arrayElementType.equals("int")) {
261 arrayRef = env.newIntArray(vals.length);
262 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef);
263 int[] ints = arrayEI.asIntArray();
264
265 for (int i = 0; i < vals.length; i++) {
266 ints[i] = vals[i].getDouble().intValue();
267 }
268 } else if (arrayElementType.equals("long")) {
269 arrayRef = env.newLongArray(vals.length);
270 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef);
271 long[] longs = arrayEI.asLongArray();
272
273 for (int i = 0; i < vals.length; i++) {
274 longs[i] = vals[i].getDouble().longValue();
275 }
276 } else if (arrayElementType.equals("float")) {
277 arrayRef = env.newFloatArray(vals.length);
278 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef);
279 float[] floats = arrayEI.asFloatArray();
280
281 for (int i = 0; i < vals.length; i++) {
282 floats[i] = vals[i].getDouble().floatValue();
283 }
284 } else if (arrayElementType.equals("double")) {
285 arrayRef = env.newDoubleArray(vals.length);
286 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef);
287 double[] doubles = arrayEI.asDoubleArray();
288
289 for (int i = 0; i < vals.length; i++) {
290 doubles[i] = vals[i].getDouble();
291 }
292 } else {
293 // Not an array of primitive types
294 arrayRef = env.newObjectArray(arrayElementType, vals.length);
295 ElementInfo arrayEI = env.getModifiableElementInfo(arrayRef);
296
297 Fields fields = arrayEI.getFields();
298
299 Creator creator = CreatorsFactory.getCreator(arrayElementType);
300 for (int i = 0; i < vals.length; i++) {
301
302 int newObjRef;
303 if (creator != null) {
304 newObjRef = creator.create(env, arrayElementType, vals[i]);
305 } else{
306 if (isArrayType(arrayElementType)) {
307 newObjRef = createArray(env, ciElement, vals[i], cgs, prefix + "[" + i);
308 } else {
309 JSONObject jsonObj = vals[i].getObject();
310 if (jsonObj != null) {
311 newObjRef = jsonObj.fillObject(env, ciElement, cgs, prefix + "[" + i);
312 } else {
313 newObjRef = MJIEnv.NULL;
314 }
315 }
316 }
317
318 fields.setReferenceValue(i, newObjRef);
319 }
320 }
321
322 return arrayRef;
323 }
324
325
326 private boolean isArrayType(String typeName) {
327 return typeName.lastIndexOf('[') >= 0;
328 }
329
330 /**
331 * This is method is used to set field of primitive type from CG result object
332 * @param ei - ElementInfo to set field in
333 * @param fi - FieldInfo of a field we want to set
334 * @param cgResult - result of CG call
335 */
336 private void convertPrimititve(ElementInfo ei, FieldInfo fi, Object cgResult) {
337 String primitiveName = fi.getType();
338
339 if (primitiveName.equals("boolean") && cgResult instanceof Boolean) {
340 Boolean bool = (Boolean) cgResult;
341 ei.setBooleanField(fi, bool.booleanValue());
342 } else if (cgResult instanceof Number) {
343 Number number = (Number) cgResult;
344
345 if (primitiveName.equals("byte")) {
346 ei.setByteField(fi, number.byteValue());
347
348 } else if (primitiveName.equals("short")) {
349 ei.setShortField(fi, number.shortValue());
350
351 } else if (primitiveName.equals("int")) {
352 ei.setIntField(fi, number.intValue());
353
354 } else if (primitiveName.equals("long")) {
355 ei.setLongField(fi, number.longValue());
356
357 } else if (primitiveName.equals("float")) {
358 ei.setFloatField(fi, number.floatValue());
359
360 } else if (primitiveName.equals("double")) {
361 ei.setDoubleField(fi, number.doubleValue());
362 }
363 } else if (cgResult instanceof Character) {
364 Character c = (Character) cgResult;
365 ei.setCharField(fi, c);
366
367 } else {
368 throw new JPFException("Can't convert " + cgResult.getClass().getCanonicalName() +
369 " to " + primitiveName);
370 }
371 }
372
373 /**
374 * Get CG from current state CG list by it's ID
375 * @param cgs - array of CG from current state
376 * @param id - id of the CG that we search for
377 * @return - CG with a specified id or null if no id with such name found
378 */
379 private ChoiceGenerator<?> getCGByID(ChoiceGenerator<?>[] cgs, String id) {
380 if (cgs == null) {
381 return null;
382 }
383
384 for (int i = 0; i < cgs.length; i++) {
385 if (cgs[i].getId().equals(id)) {
386 return cgs[i];
387 }
388 }
389
390 return null;
391 }
392 }