/******************************************************************************* * Copyright © 2011, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package eglx.json; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import org.eclipse.edt.javart.AnyBoxedObject; import org.eclipse.edt.javart.json.ArrayNode; import org.eclipse.edt.javart.json.NameValuePairNode; import org.eclipse.edt.javart.json.ObjectNode; import org.eclipse.edt.javart.json.StringNode; import org.eclipse.edt.javart.json.ValueNode; import org.eclipse.edt.javart.resources.ExecutableBase; import org.eclipse.edt.javart.services.FunctionParameter; import org.eclipse.edt.javart.services.FunctionParameterKind; import org.eclipse.edt.javart.services.FunctionSignature; import org.eclipse.edt.javart.services.ServiceUtilities; import org.eclipse.edt.javart.util.DateTimeUtil; import org.eclipse.edt.javart.util.JavartUtil; import org.eclipse.edt.runtime.java.eglx.lang.AnyValue; import org.eclipse.edt.runtime.java.eglx.lang.EAny; import org.eclipse.edt.runtime.java.eglx.lang.EBigint; import org.eclipse.edt.runtime.java.eglx.lang.EBoolean; import org.eclipse.edt.runtime.java.eglx.lang.EDate; import org.eclipse.edt.runtime.java.eglx.lang.EDecimal; import org.eclipse.edt.runtime.java.eglx.lang.EFloat; import org.eclipse.edt.runtime.java.eglx.lang.EInt; import org.eclipse.edt.runtime.java.eglx.lang.EList; import org.eclipse.edt.runtime.java.eglx.lang.ESmallfloat; import org.eclipse.edt.runtime.java.eglx.lang.ESmallint; import org.eclipse.edt.runtime.java.eglx.lang.EString; import org.eclipse.edt.runtime.java.eglx.lang.ETime; import org.eclipse.edt.runtime.java.eglx.lang.ETimestamp; import eglx.lang.AnyException; public class JsonUtilities { private static String JSON_RPC_ERROR_ID = "error"; private static String JSON_RPC_ERROR_NAME_ID = "name"; public static String JSON_RPC_ERROR_NAME_VALUE = "JSONRPCError"; private static String JSON_RPC_ERROR_MESSAGE_ID = "message"; private static String JSON_RPC_ERROR_CODE_ID = "code"; private JsonUtilities() { } public static String trimJSON(String json) { if ( json == null || json.equals( "" ) ) { //this was causing a defect: RATLC01169730, part 2 //charAt() was called without checking if the string were null first //used to throw a StringIndexOutOfBoundsException //don't know if it's better to return "" or null //right now, setting it to return itself; garbage in, garbage out return json; } else if (json.charAt(0) == '{') { int curlyCount = 1; //don't look at { or } if it's inside "'s because //that is data and it's legal to have them in quotes, but that will throw off the actual {} counting boolean ignoreCurlyBraces = false; for (int n=1; n<json.length(); n++) { switch (json.charAt(n)) { case '"': if( !ignoreCurlyBraces ){ ignoreCurlyBraces = true; } else if( json.charAt(n-1) != '\\' ){ // if it's a \ then it's a quote within the data // so this is the end of a data block start looking at the {} again ignoreCurlyBraces = false; } break; case '{': if( !ignoreCurlyBraces ){ curlyCount++; } break; case '}': if( !ignoreCurlyBraces ){ curlyCount--; } break; } if (curlyCount == 0) json = json.substring(0,n+1); } } return json; } public static String createJsonAnyException(AnyException jrte ) { /* { "error" : { "name" : "JSONRPCError" "code" : ""egl message ID"", "message" : "egl exception message" "error" : { "name" : "fully qualified egl exception type", i.e. "egl.core.ServiceInvocationException" "messageID" : "egl message ID", "message" : "egl exception message", //other fields defined by the individual exception record //ie service invocation exception "source" : "egl" or "web", "detail1" : "detail1 text", "detail2" : "detail2 text", "detail3" : "detail3 text" } } } */ ObjectNode wrapper = new ObjectNode(); ObjectNode error = new ObjectNode(); error.addPair( new NameValuePairNode( new StringNode( JSON_RPC_ERROR_NAME_ID, true ), new StringNode(JSON_RPC_ERROR_NAME_VALUE, false ) ) ); error.addPair( new NameValuePairNode( new StringNode( JSON_RPC_ERROR_CODE_ID, true ), new StringNode(jrte.getMessageID(), false ) ) ); error.addPair( new NameValuePairNode( new StringNode( JSON_RPC_ERROR_MESSAGE_ID, true ), new StringNode( ServiceUtilities.getMessage( jrte ), false ) ) ); wrapper.addPair( new NameValuePairNode( new StringNode( JSON_RPC_ERROR_ID, true ), error ) ); if( jrte instanceof AnyException ) { AnyException record = (AnyException)jrte; ObjectNode eglException; try { eglException = (ObjectNode)JsonLib.convertToJsonNode(record); } catch( AnyException j ) { eglException = new ObjectNode(); } error.addPair( new NameValuePairNode( new StringNode( JSON_RPC_ERROR_ID, true ), eglException ) ); eglException.addPair( new NameValuePairNode( new StringNode( JSON_RPC_ERROR_NAME_ID, true ), new StringNode( record.getClass().getName(), false ) ) ); } return wrapper.toJson(); } public static Object[] getParameters(Method method, ArrayNode jsonParameters){ FunctionSignature signature = method.getAnnotation(FunctionSignature.class); List<Object> parameters = new ArrayList<Object>(); int jsonIdx = 0; for(int idx = 0; idx < method.getParameterTypes().length; idx++ ){ FunctionParameter functionParameter = signature.parameters()[idx]; if(functionParameter.kind().equals(FunctionParameterKind.OUT)){ try { Class<?> fieldType = functionParameter.jsonInfo().clazz(); Object newValue = null; if(functionParameter.arrayDimensions() > 0){ newValue = EList.ezeNew(fieldType); } else if(fieldType.equals(EBigint.class)){ newValue = EBigint.asBigint(0); } else if(fieldType.equals(EBoolean.class)){ newValue = EBoolean.asBoolean(false); } else if(fieldType.equals(EDate.class)){ Calendar cal = DateTimeUtil.getBaseCalendar(); cal.get(Calendar.YEAR); newValue = EDate.asDate(cal); } else if(fieldType.equals(EDecimal.class)){ if(functionParameter.jsonInfo().asOptions() != null && functionParameter.jsonInfo().asOptions().length > 1){ int length = Integer.parseInt(functionParameter.jsonInfo().asOptions()[0]); int decimal = Integer.parseInt(functionParameter.jsonInfo().asOptions()[1]); newValue = EDecimal.asDecimal(0, length, decimal); } else{ newValue = EDecimal.asDecimal(0); } } else if(fieldType.equals(EFloat.class)){ newValue = EFloat.asFloat(0); } else if(fieldType.equals(EInt.class)){ newValue = EInt.asInt(0); } else if(fieldType.equals(ESmallfloat.class)){ newValue = ESmallfloat.asSmallfloat(0); } else if(fieldType.equals(ESmallint.class)){ newValue = ESmallint.asSmallint(0); } else if(fieldType.equals(EString.class)){ newValue = ""; } else if(fieldType.equals(ETime.class)){ Calendar cal = DateTimeUtil.getBaseCalendar(); cal.get(Calendar.YEAR); newValue = ETime.asTime(cal); } else if(fieldType.equals(ETimestamp.class)){ int start = ETimestamp.YEAR_CODE; int end = ETimestamp.SECOND_CODE; if(functionParameter.jsonInfo().asOptions() != null && functionParameter.jsonInfo().asOptions().length > 1){ start = getETimestampStaticField(functionParameter.jsonInfo().asOptions()[0]); end = getETimestampStaticField(functionParameter.jsonInfo().asOptions()[1]); } Calendar cal = DateTimeUtil.getBaseCalendar(); cal.get(Calendar.YEAR); newValue = ETimestamp.asTimestamp(cal, start, end); } else if(AnyValue.class.isAssignableFrom(fieldType)){ newValue = fieldType.newInstance(); } else if(ExecutableBase.class.isAssignableFrom(fieldType)){ newValue = fieldType.newInstance(); } else if(fieldType.equals(Enum.class)){ for(Object enumConstant : fieldType.getEnumConstants()){ if(enumConstant instanceof Enum){ newValue = enumConstant; break; } } } if(method.getParameterTypes()[idx].equals(AnyBoxedObject.class)){ newValue = EAny.ezeWrap(newValue); } parameters.add(newValue); } catch (Exception e) { JavartUtil.makeEglException(e); } } else{ Object obj = JsonLib.convertToEgl(functionParameter.jsonInfo().clazz(), functionParameter.jsonInfo().asOptions(), null, (ValueNode)jsonParameters.getValues().get(jsonIdx++)); if(method.getParameterTypes()[idx].equals(AnyBoxedObject.class)){ obj = EAny.ezeWrap(obj); } parameters.add(obj); } } return parameters.toArray(new Object[parameters.size()]); } public static int getETimestampStaticField(String fieldName){ if("YEAR_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.YEAR_CODE; } else if("SECOND_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.SECOND_CODE; } else if("MONTH_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.MONTH_CODE; } else if("MINUTE_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.MINUTE_CODE; } else if("HOUR_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.HOUR_CODE; } else if("FRACTION6_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.FRACTION6_CODE; } else if("FRACTION5_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.FRACTION5_CODE; } else if("FRACTION4_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.FRACTION4_CODE; } else if("FRACTION3_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.FRACTION3_CODE; } else if("FRACTION2_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.FRACTION2_CODE; } else if("FRACTION1_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.FRACTION1_CODE; } else if("DAY_CODE".equalsIgnoreCase(fieldName)){ return ETimestamp.DAY_CODE; } return 0; } public static Object wrapCalendar(Object field, Class<?> type, String[] asOptions){ if(field instanceof AnyBoxedObject<?>){ field = ((AnyBoxedObject<?>)field).ezeUnbox(); } if(field instanceof List){ List<Object> wrappedList = new ArrayList<Object>(); for(Object obj : ((List<?>)field)){ wrappedList.add(wrapCalendar(obj, type, asOptions)); } return wrappedList; } else if(type != null && type.equals(EDate.class)){ return new EDate((Calendar)field); } else if(type != null && type.equals(ETime.class)){ return new ETime((Calendar)field); } else if(type != null && type.equals(ETimestamp.class)){ int start = ETimestamp.YEAR_CODE; int end = ETimestamp.SECOND_CODE; if(asOptions != null && asOptions.length > 1){ start = eglx.json.JsonUtilities.getETimestampStaticField(asOptions[0]); end = eglx.json.JsonUtilities.getETimestampStaticField(asOptions[1]); } return new ETimestamp((Calendar)field, start, end); } else{ return field; } } }