2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2016-2018 Ericsson. All rights reserved.
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.apex.context.impl.schema.java;
23 import com.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25 import com.google.gson.JsonElement;
27 import java.lang.reflect.Constructor;
28 import java.util.HashMap;
31 import org.onap.policy.apex.context.ContextRuntimeException;
32 import org.onap.policy.apex.context.impl.schema.AbstractSchemaHelper;
33 import org.onap.policy.apex.context.parameters.ContextParameterConstants;
34 import org.onap.policy.apex.context.parameters.SchemaParameters;
35 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
36 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
37 import org.onap.policy.apex.model.utilities.typeutils.TypeBuilder;
38 import org.onap.policy.common.parameters.ParameterService;
39 import org.slf4j.ext.XLogger;
40 import org.slf4j.ext.XLoggerFactory;
43 * This class implements translation to and from Apex distributed objects and Java objects when a Java schema is used.
44 * It creates schema items as Java objects and marshals and unmarshals these objects in various formats. All objects
45 * must be of the type of Java class defined in the schema.
47 * @author Liam Fallon (liam.fallon@ericsson.com)
49 public class JavaSchemaHelper extends AbstractSchemaHelper {
50 // Get a reference to the logger
51 private static final XLogger LOGGER = XLoggerFactory.getXLogger(JavaSchemaHelper.class);
53 // This map defines the built in types in types in Java
55 private static final Map<String, Class<?>> BUILT_IN_MAP = new HashMap<>();
58 BUILT_IN_MAP.put("int", Integer .TYPE);
59 BUILT_IN_MAP.put("long", Long .TYPE);
60 BUILT_IN_MAP.put("double", Double .TYPE);
61 BUILT_IN_MAP.put("float", Float .TYPE);
62 BUILT_IN_MAP.put("bool", Boolean .TYPE);
63 BUILT_IN_MAP.put("char", Character.TYPE);
64 BUILT_IN_MAP.put("byte", Byte .TYPE);
65 BUILT_IN_MAP.put("void", Void .TYPE);
66 BUILT_IN_MAP.put("short", Short .TYPE);
73 * @see org.onap.policy.apex.context.impl.schema.AbstractSchemaHelper#init(org.onap.policy.apex.model .basicmodel.
74 * concepts. AxKey, org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema)
77 public void init(final AxKey userKey, final AxContextSchema schema) {
78 super.init(userKey, schema);
80 final String javatype = schema.getSchema();
81 // For Java, the schema is the Java class canonical path
84 setSchemaClass(TypeBuilder.getJavaTypeClass(schema.getSchema()));
85 } catch (final IllegalArgumentException e) {
87 String resultSting = userKey.getId() + ": class/type " + schema.getSchema() + " for context schema \""
88 + schema.getId() + "\" not found.";
89 if (JavaSchemaHelper.BUILT_IN_MAP.get(javatype) != null) {
90 resultSting += " Primitive types are not supported. Use the appropriate Java boxing type instead.";
92 resultSting += " Check the class path of the JVM";
94 LOGGER.warn(resultSting);
95 throw new ContextRuntimeException(resultSting, e);
102 * @see org.onap.policy.apex.context.SchemaHelper#createNewInstance(java.lang.Object)
105 public Object createNewInstance(final Object incomingObject) {
106 if (incomingObject == null) {
110 if (getSchemaClass() == null) {
111 final String returnString = getUserKey().getId()
112 + ": could not create an instance, schema class for the schema is null";
113 LOGGER.warn(returnString);
114 throw new ContextRuntimeException(returnString);
117 if (incomingObject instanceof JsonElement) {
118 final String elementJsonString = getGson().toJson((JsonElement) incomingObject);
119 return getGson().fromJson(elementJsonString, this.getSchemaClass());
122 if (getSchemaClass().isAssignableFrom(incomingObject.getClass())) {
123 return incomingObject;
126 final String returnString = getUserKey().getId() + ": the object \"" + incomingObject + "\" of type \""
127 + incomingObject.getClass().getCanonicalName()
128 + "\" is not an instance of JsonObject and is not assignable to \""
129 + getSchemaClass().getCanonicalName() + "\"";
130 LOGGER.warn(returnString);
131 throw new ContextRuntimeException(returnString);
137 * @see org.onap.policy.apex.context.SchemaHelper#object2SchemaObject(java.lang.Object)
140 public Object unmarshal(final Object object) {
141 if (object == null) {
145 // If the object is an instance of the incoming object, carry on
146 if (object.getClass().equals(getSchemaClass())) {
150 // For numeric types, do a numeric conversion
151 if (Number.class.isAssignableFrom(getSchemaClass())) {
152 return numericConversion(object);
155 if (getSchemaClass().isAssignableFrom(object.getClass())) {
158 return stringConversion(object);
165 * @see org.onap.policy.apex.context.SchemaHelper#schemaObject2Json(java.lang.Object)
168 public String marshal2String(final Object schemaObject) {
169 if (schemaObject == null) {
173 // Check the incoming object is of a correct class
174 if (getSchemaClass().isAssignableFrom(schemaObject.getClass())) {
175 // Use Gson to translate the object
176 return getGson().toJson(schemaObject);
178 final String returnString = getUserKey().getId() + ": object \"" + schemaObject.toString()
179 + "\" of class \"" + schemaObject.getClass().getCanonicalName()
180 + "\" not compatible with class \"" + getSchemaClass().getCanonicalName() + "\"";
181 LOGGER.warn(returnString);
182 throw new ContextRuntimeException(returnString);
189 * @see org.onap.policy.apex.context.SchemaHelper#marshal2JsonElement(java.lang.Object)
192 public Object marshal2Object(final Object schemaObject) {
193 // Use Gson to marshal the schema object into a Json element to return
194 return getGson().toJsonTree(schemaObject, getSchemaClass());
198 * Do a numeric conversion between numeric types.
200 * @param object The incoming numeric object
201 * @return The converted object
203 private Object numericConversion(final Object object) {
204 // Check if the incoming object is a number, if not do a string conversion
205 if (object instanceof Number) {
206 if (getSchemaClass().isAssignableFrom(Byte.class)) {
207 return ((Number) object).byteValue();
208 } else if (getSchemaClass().isAssignableFrom(Short.class)) {
209 return ((Number) object).shortValue();
210 } else if (getSchemaClass().isAssignableFrom(Integer.class)) {
211 return ((Number) object).intValue();
212 } else if (getSchemaClass().isAssignableFrom(Long.class)) {
213 return ((Number) object).longValue();
214 } else if (getSchemaClass().isAssignableFrom(Float.class)) {
215 return ((Number) object).floatValue();
216 } else if (getSchemaClass().isAssignableFrom(Double.class)) {
217 return ((Number) object).doubleValue();
221 // OK, we'll try and convert from a string representation of the incoming object
222 return stringConversion(object);
226 * Do a string conversion to the class type.
228 * @param object The incoming numeric object
229 * @return The converted object
231 private Object stringConversion(final Object object) {
232 // OK, we'll try and convert from a string representation of the incoming object
234 final Constructor<?> stringConstructor = getSchemaClass().getConstructor(String.class);
235 return stringConstructor.newInstance(object.toString());
236 } catch (final Exception e) {
237 final String returnString = getUserKey().getId() + ": object \"" + object.toString() + "\" of class \""
238 + object.getClass().getCanonicalName() + "\" not compatible with class \""
239 + getSchemaClass().getCanonicalName() + "\"";
240 LOGGER.warn(returnString, e);
241 throw new ContextRuntimeException(returnString);
246 * Get a GSON instance that has the correct adaptation included.
248 * @return the GSON instance
250 private Gson getGson() {
251 GsonBuilder gsonBuilder = new GsonBuilder().setPrettyPrinting();
253 // Get the Java schema helper parameters from the parameter service
254 SchemaParameters schemaParameters = ParameterService.get(ContextParameterConstants.SCHEMA_GROUP_NAME);
256 JavaSchemaHelperParameters javaSchemaHelperParmeters = (JavaSchemaHelperParameters) schemaParameters
257 .getSchemaHelperParameterMap().get("Java");
259 if (javaSchemaHelperParmeters == null) {
260 javaSchemaHelperParmeters = new JavaSchemaHelperParameters();
263 for (JavaSchemaHelperJsonAdapterParameters jsonAdapterEntry : javaSchemaHelperParmeters.getJsonAdapters()
266 Object adapterObject;
268 adapterObject = jsonAdapterEntry.getAdaptorClazz().newInstance();
269 } catch (InstantiationException | IllegalAccessException e) {
270 final String returnString = getUserKey().getId() + ": instantiation of adapter class \""
271 + jsonAdapterEntry.getAdaptorClass() + "\" to decode and encode class \""
272 + jsonAdapterEntry.getAdaptedClass() + "\" failed: " + e.getMessage();
273 LOGGER.warn(returnString, e);
274 throw new ContextRuntimeException(returnString);
277 gsonBuilder.registerTypeAdapter(jsonAdapterEntry.getAdaptedClazz(), adapterObject);
280 return gsonBuilder.create();