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