2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2016-2018 Ericsson. All rights reserved.
4 * Modifications Copyright (C) 2019-2020 Nordix Foundation.
5 * Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.policy.apex.context.impl.schema.java;
25 import com.google.gson.Gson;
26 import com.google.gson.GsonBuilder;
27 import com.google.gson.JsonElement;
28 import java.lang.reflect.Constructor;
29 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.common.parameters.ParameterService;
38 import org.slf4j.ext.XLogger;
39 import org.slf4j.ext.XLoggerFactory;
42 * This class implements translation to and from Apex distributed objects and Java objects when a Java schema is used.
43 * It creates schema items as Java objects and marshals and unmarshals these objects in various formats. All objects
44 * must be of the type of Java class defined in the schema.
46 * @author Liam Fallon (liam.fallon@ericsson.com)
48 public class JavaSchemaHelper extends AbstractSchemaHelper {
49 // Get a reference to the logger
50 private static final XLogger LOGGER = XLoggerFactory.getXLogger(JavaSchemaHelper.class);
52 // This map defines the built in types in types in Java
54 private static final Map<String, Class<?>> BUILT_IN_MAP = new HashMap<>();
57 BUILT_IN_MAP.put("int", Integer.TYPE);
58 BUILT_IN_MAP.put("long", Long.TYPE);
59 BUILT_IN_MAP.put("double", Double.TYPE);
60 BUILT_IN_MAP.put("float", Float.TYPE);
61 BUILT_IN_MAP.put("bool", Boolean.TYPE);
62 BUILT_IN_MAP.put("char", Character.TYPE);
63 BUILT_IN_MAP.put("byte", Byte.TYPE);
64 BUILT_IN_MAP.put("void", Void.TYPE);
65 BUILT_IN_MAP.put("short", Short.TYPE);
73 public void init(final AxKey userKey, final AxContextSchema schema) {
74 super.init(userKey, schema);
76 final String javatype = schema.getSchema();
77 // For Java, the schema is the Java class canonical path
80 setSchemaClass(Class.forName(schema.getSchema()));
81 } catch (final Exception e) {
83 String resultSting = userKey.getId() + ": class/type " + schema.getSchema() + " for context schema \""
84 + schema.getId() + "\" not found.";
85 if (JavaSchemaHelper.BUILT_IN_MAP.get(javatype) != null) {
86 resultSting += " Primitive types are not supported. Use the appropriate Java boxing type instead.";
88 resultSting += " Check the class path of the JVM";
90 LOGGER.warn(resultSting);
91 throw new ContextRuntimeException(resultSting, e);
99 public Object createNewInstance(final Object incomingObject) {
100 if (incomingObject == null) {
104 if (getSchemaClass() == null) {
105 final var returnString =
106 getUserKey().getId() + ": could not create an instance, schema class for the schema is null";
107 LOGGER.warn(returnString);
108 throw new ContextRuntimeException(returnString);
111 if (incomingObject instanceof JsonElement) {
112 final var elementJsonString = getGson().toJson((JsonElement) incomingObject);
113 return getGson().fromJson(elementJsonString, this.getSchemaClass());
116 if (getSchemaClass().isAssignableFrom(incomingObject.getClass())) {
117 return incomingObject;
120 final var returnString = getUserKey().getId() + ": the object \"" + incomingObject + "\" of type \""
121 + incomingObject.getClass().getName()
122 + "\" is not an instance of JsonObject and is not assignable to \"" + getSchemaClass().getName() + "\"";
123 LOGGER.warn(returnString);
124 throw new ContextRuntimeException(returnString);
131 public Object unmarshal(final Object object) {
132 if (object == null) {
136 // If the object is an instance of the incoming object, carry on
137 if (object.getClass().equals(getSchemaClass())) {
141 // For numeric types, do a numeric conversion
142 if (Number.class.isAssignableFrom(getSchemaClass())) {
143 return numericConversion(object);
146 if (getSchemaClass().isAssignableFrom(object.getClass())) {
149 return stringConversion(object);
157 public String marshal2String(final Object schemaObject) {
158 if (schemaObject == null) {
162 // Check the incoming object is of a correct class
163 if (getSchemaClass().isAssignableFrom(schemaObject.getClass())) {
164 // Use Gson to translate the object
165 return getGson().toJson(schemaObject);
167 final var returnString = getUserKey().getId() + ": object \"" + schemaObject.toString()
168 + "\" of class \"" + schemaObject.getClass().getName() + "\" not compatible with class \""
169 + getSchemaClass().getName() + "\"";
170 LOGGER.warn(returnString);
171 throw new ContextRuntimeException(returnString);
179 public Object marshal2Object(final Object schemaObject) {
180 // Use Gson to marshal the schema object into a Json element to return
181 return getGson().toJsonTree(schemaObject, getSchemaClass());
185 * Do a numeric conversion between numeric types.
187 * @param object The incoming numeric object
188 * @return The converted object
190 private Object numericConversion(final Object object) {
191 // Check if the incoming object is a number, if not do a string conversion
192 if (object instanceof Number) {
193 if (getSchemaClass().isAssignableFrom(Byte.class)) {
194 return ((Number) object).byteValue();
195 } else if (getSchemaClass().isAssignableFrom(Short.class)) {
196 return ((Number) object).shortValue();
197 } else if (getSchemaClass().isAssignableFrom(Integer.class)) {
198 return ((Number) object).intValue();
199 } else if (getSchemaClass().isAssignableFrom(Long.class)) {
200 return ((Number) object).longValue();
201 } else if (getSchemaClass().isAssignableFrom(Float.class)) {
202 return ((Number) object).floatValue();
203 } else if (getSchemaClass().isAssignableFrom(Double.class)) {
204 return ((Number) object).doubleValue();
208 // OK, we'll try and convert from a string representation of the incoming object
209 return stringConversion(object);
213 * Do a string conversion to the class type.
215 * @param object The incoming numeric object
216 * @return The converted object
218 private Object stringConversion(final Object object) {
219 // OK, we'll try and convert from a string representation of the incoming object
221 final Constructor<?> stringConstructor = getSchemaClass().getConstructor(String.class);
222 return stringConstructor.newInstance(object.toString());
223 } catch (final Exception e) {
224 final var returnString = getUserKey().getId() + ": object \"" + object.toString() + "\" of class \""
225 + object.getClass().getName() + "\" not compatible with class \"" + getSchemaClass().getName()
227 LOGGER.warn(returnString, e);
228 throw new ContextRuntimeException(returnString);
233 * Get a GSON instance that has the correct adaptation included.
235 * @return the GSON instance
237 private Gson getGson() {
238 var gsonBuilder = new GsonBuilder().setPrettyPrinting();
240 // Get the Java schema helper parameters from the parameter service
241 var schemaParameters = (SchemaParameters) ParameterService.get(ContextParameterConstants.SCHEMA_GROUP_NAME);
243 JavaSchemaHelperParameters javaSchemaHelperParmeters =
244 (JavaSchemaHelperParameters) schemaParameters.getSchemaHelperParameterMap().get("Java");
246 if (javaSchemaHelperParmeters == null) {
247 javaSchemaHelperParmeters = new JavaSchemaHelperParameters();
250 for (JavaSchemaHelperJsonAdapterParameters jsonAdapterEntry : javaSchemaHelperParmeters.getJsonAdapters()
253 Object adapterObject;
255 adapterObject = jsonAdapterEntry.getAdaptorClazz().getDeclaredConstructor().newInstance();
256 } catch (Exception e) {
257 final var returnString = getUserKey().getId() + ": instantiation of adapter class \""
258 + jsonAdapterEntry.getAdaptorClass() + "\" to decode and encode class \""
259 + jsonAdapterEntry.getAdaptedClass() + "\" failed: " + e.getMessage();
260 LOGGER.warn(returnString, e);
261 throw new ContextRuntimeException(returnString);
264 gsonBuilder.registerTypeAdapter(jsonAdapterEntry.getAdaptedClazz(), adapterObject);
267 return gsonBuilder.create();