7a903e9d1f1d1a2c7eb145e1c7aeb53d5ef41170
[policy/apex-pdp.git] /
1 /*-
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.context.impl.schema.java;
22
23 import com.google.gson.Gson;
24 import com.google.gson.JsonElement;
25
26 import java.lang.reflect.Constructor;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 import org.onap.policy.apex.context.ContextRuntimeException;
31 import org.onap.policy.apex.context.impl.schema.AbstractSchemaHelper;
32 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
33 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
34 import org.onap.policy.apex.model.utilities.typeutils.TypeBuilder;
35 import org.slf4j.ext.XLogger;
36 import org.slf4j.ext.XLoggerFactory;
37
38 /**
39  * This class implements translation to and from Apex distributed objects and Java objects when a
40  * Java schema is used. It creates schema items as Java objects and marshals and unmarshals these
41  * objects in various formats. All objects must be of the type of Java class defined in the schema.
42  *
43  * @author Liam Fallon (liam.fallon@ericsson.com)
44  */
45 public class JavaSchemaHelper extends AbstractSchemaHelper {
46     // Get a reference to the logger
47     private static final XLogger LOGGER = XLoggerFactory.getXLogger(JavaSchemaHelper.class);
48
49     // This map defines the built in types in types in Java
50     // @formatter:off
51     private static final Map<String, Class<?>> BUILT_IN_MAP = new HashMap<>();
52
53     static {
54         BUILT_IN_MAP.put("int",    Integer  .TYPE);
55         BUILT_IN_MAP.put("long",   Long     .TYPE);
56         BUILT_IN_MAP.put("double", Double   .TYPE);
57         BUILT_IN_MAP.put("float",  Float    .TYPE);
58         BUILT_IN_MAP.put("bool",   Boolean  .TYPE);
59         BUILT_IN_MAP.put("char",   Character.TYPE);
60         BUILT_IN_MAP.put("byte",   Byte     .TYPE);
61         BUILT_IN_MAP.put("void",   Void     .TYPE);
62         BUILT_IN_MAP.put("short",  Short    .TYPE);
63     }
64     // @formatter:on
65
66     /*
67      * (non-Javadoc)
68      *
69      * @see
70      * org.onap.policy.apex.context.impl.schema.AbstractSchemaHelper#init(org.onap.policy.apex.model
71      * .basicmodel. concepts. AxKey,
72      * org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema)
73      */
74     @Override
75     public void init(final AxKey userKey, final AxContextSchema schema) {
76         super.init(userKey, schema);
77
78         final String javatype = schema.getSchema();
79         // For Java, the schema is the Java class canonical path
80
81         try {
82             setSchemaClass(TypeBuilder.getJavaTypeClass(schema.getSchema()));
83         } catch (final IllegalArgumentException e) {
84
85             String resultSting = userKey.getId() + ": class/type " + schema.getSchema() + " for context schema \""
86                     + schema.getId() + "\" not found.";
87             if (JavaSchemaHelper.BUILT_IN_MAP.get(javatype) != null) {
88                 resultSting += " Primitive types are not supported. Use the appropriate Java boxing type instead.";
89             } else {
90                 resultSting += " Check the class path of the JVM";
91             }
92             LOGGER.warn(resultSting);
93             throw new ContextRuntimeException(resultSting, e);
94         }
95     }
96
97     /*
98      * (non-Javadoc)
99      *
100      * @see org.onap.policy.apex.context.SchemaHelper#createNewInstance(java.lang.Object)
101      */
102     @Override
103     public Object createNewInstance(final Object incomingObject) {
104         if (incomingObject == null) {
105             return null;
106         }
107
108         if (getSchemaClass() == null) {
109             final String returnString =
110                     getUserKey().getId() + ": could not create an instance, schema class for the schema is null";
111             LOGGER.warn(returnString);
112             throw new ContextRuntimeException(returnString);
113         }
114
115         if (incomingObject instanceof JsonElement) {
116             final String elementJsonString = new Gson().toJson((JsonElement) incomingObject);
117             return new Gson().fromJson(elementJsonString, this.getSchemaClass());
118         }
119
120         if (getSchemaClass().isAssignableFrom(incomingObject.getClass())) {
121             return incomingObject;
122         }
123
124         final String returnString = getUserKey().getId() + ": the object \"" + incomingObject + "\" of type \""
125                 + incomingObject.getClass().getCanonicalName()
126                 + "\" is not an instance of JsonObject and is not assignable to \""
127                 + getSchemaClass().getCanonicalName() + "\"";
128         LOGGER.warn(returnString);
129         throw new ContextRuntimeException(returnString);
130     }
131
132     /*
133      * (non-Javadoc)
134      *
135      * @see org.onap.policy.apex.context.SchemaHelper#object2SchemaObject(java.lang.Object)
136      */
137     @Override
138     public Object unmarshal(final Object object) {
139         if (object == null) {
140             return null;
141         }
142
143         // If the object is an instance of the incoming object, carry on
144         if (object.getClass().equals(getSchemaClass())) {
145             return object;
146         }
147
148         // For numeric types, do a numeric conversion
149         if (Number.class.isAssignableFrom(getSchemaClass())) {
150             return numericConversion(object);
151         }
152
153         if (getSchemaClass().isAssignableFrom(object.getClass())) {
154             return object;
155         } else {
156             return stringConversion(object);
157         }
158     }
159
160     /*
161      * (non-Javadoc)
162      *
163      * @see org.onap.policy.apex.context.SchemaHelper#schemaObject2Json(java.lang.Object)
164      */
165     @Override
166     public String marshal2String(final Object schemaObject) {
167         if (schemaObject == null) {
168             return "null";
169         }
170
171         // Check the incoming object is of a correct class
172         if (getSchemaClass().isAssignableFrom(schemaObject.getClass())) {
173             // Use Gson to translate the object
174             return new Gson().toJson(schemaObject);
175         } else {
176             final String returnString = getUserKey().getId() + ": object \"" + schemaObject.toString()
177                     + "\" of class \"" + schemaObject.getClass().getCanonicalName() + "\" not compatible with class \""
178                     + getSchemaClass().getCanonicalName() + "\"";
179             LOGGER.warn(returnString);
180             throw new ContextRuntimeException(returnString);
181         }
182     }
183
184     /*
185      * (non-Javadoc)
186      *
187      * @see org.onap.policy.apex.context.SchemaHelper#marshal2JsonElement(java.lang.Object)
188      */
189     @Override
190     public Object marshal2Object(final Object schemaObject) {
191         // Use Gson to marshal the schema object into a Json element to return
192         return new Gson().toJsonTree(schemaObject, getSchemaClass());
193     }
194
195     /**
196      * Do a numeric conversion between numeric types.
197      *
198      * @param object The incoming numeric object
199      * @return The converted object
200      */
201     private Object numericConversion(final Object object) {
202         // Check if the incoming object is a number, if not do a string conversion
203         if (object instanceof Number) {
204             if (getSchemaClass().isAssignableFrom(Byte.class)) {
205                 return ((Number) object).byteValue();
206             } else if (getSchemaClass().isAssignableFrom(Short.class)) {
207                 return ((Number) object).shortValue();
208             } else if (getSchemaClass().isAssignableFrom(Integer.class)) {
209                 return ((Number) object).intValue();
210             } else if (getSchemaClass().isAssignableFrom(Long.class)) {
211                 return ((Number) object).longValue();
212             } else if (getSchemaClass().isAssignableFrom(Float.class)) {
213                 return ((Number) object).floatValue();
214             } else if (getSchemaClass().isAssignableFrom(Double.class)) {
215                 return ((Number) object).doubleValue();
216             }
217         }
218
219         // OK, we'll try and convert from a string representation of the incoming object
220         return stringConversion(object);
221     }
222
223     /**
224      * Do a string conversion to the class type.
225      *
226      * @param object The incoming numeric object
227      * @return The converted object
228      */
229     private Object stringConversion(final Object object) {
230         // OK, we'll try and convert from a string representation of the incoming object
231         try {
232             final Constructor<?> stringConstructor = getSchemaClass().getConstructor(String.class);
233             return stringConstructor.newInstance(object.toString());
234         } catch (final Exception e) {
235             final String returnString = getUserKey().getId() + ": object \"" + object.toString() + "\" of class \""
236                     + object.getClass().getCanonicalName() + "\" not compatible with class \""
237                     + getSchemaClass().getCanonicalName() + "\"";
238             LOGGER.warn(returnString, e);
239             throw new ContextRuntimeException(returnString);
240         }
241     }
242 }