View Javadoc
1   package com.exsoinn.util.epf;
2   
3   import com.google.gson.JsonElement;
4   import com.google.gson.JsonParseException;
5   import com.google.gson.JsonParser;
6   import org.json.JSONObject;
7   import org.json.XML;
8   import java.lang.reflect.Constructor;
9   import java.lang.reflect.InvocationTargetException;
10  import java.util.List;
11  
12  /**
13   * Factory for building {@link Context}'s from passed in data. Currently any valid JSON or XML string can be
14   * converted to a Context.
15   * TODO: Enhance to suppert Nashorn ECMA JSON objects, do what client code does not have to do JSON.stringify() on those???
16   * Created by QuijadaJ on 5/3/2017.
17   */
18  public enum ContextFactory {
19      INSTANCE;
20      private static final String CLASS_NAME_JSON_CTX = "com.exsoinn.util.epf.JsonContext";
21      private static final String CLASS_NAME_MUT_JSON_CTX = "com.exsoinn.util.epf.MutableJsonContext";
22  
23  
24      /**
25       * Factory method which will attempt to return a {@link Context} by inspecting the passed in pData. The
26       * pData passed in must be in a format that will be recognized, otherwise {@link IllegalArgumentException}
27       * exception gets thrown. At this time only JSON format is supported, and the JSON is built by relying
28       * on <a href="https://google.github.io">Google JSON API</a>. Plans are to add support for XML format using a similar,
29       * already existing 3rd party XML API.
30       *
31       * @param pData - The data from which a {@code Context} will be constructed.
32       * @return - Data of some format wrapped inside a {@link Context} object.
33       * @throws IllegalArgumentException - TODO
34       */
35      public static Context obtainContext(Object pData) throws IllegalArgumentException {
36          return obtainContext(pData, CLASS_NAME_JSON_CTX);
37      }
38  
39  
40      /**
41       * Sames as {@link ContextFactory#obtainContext(Object)}, but returns ab object of type {@link MutableContext}.
42       * @param pData - pData
43       * @return - TODO
44       * @throws IllegalArgumentException - TODO
45       */
46      public static MutableContext obtainMutableContext(Object pData) throws IllegalArgumentException {
47          return (MutableContext) obtainContext(pData, CLASS_NAME_MUT_JSON_CTX);
48      }
49  
50  
51      private static Context obtainContext(Object pData, String pClassName)
52              throws IllegalArgumentException {
53          JsonElement je = convertToJson(pData);
54          String xmlToJsonStr;
55  
56          boolean formatIsSupported = false;
57          try {
58              Class<? extends JsonContext> jsonCtxClass = (Class<? extends JsonContext>) Class.forName(pClassName);
59              Constructor<? extends JsonContext> jsonCtxClassConstructor =
60                      jsonCtxClass.getDeclaredConstructor(JsonElement.class);
61              jsonCtxClassConstructor.setAccessible(true);
62              if (null != je) {
63                  formatIsSupported = true;
64              } else if (pData instanceof List && null != (je = convertToJson(pData.toString()))) {
65                  formatIsSupported = true;
66              } else if (pData instanceof String && null != (xmlToJsonStr = tryXml((String) pData))
67                      && null != (je = convertToJson(xmlToJsonStr))) {
68                  /*
69                   * Because we got XML, (I.e. the tryXml() method call did not return NULL), check if we still
70                   * ended up with empty JSON, in which case we will throw error
71                   */
72                  if (je.isJsonPrimitive() || (je.isJsonArray() && je.getAsJsonArray().size() != 0)
73                          || (je.isJsonObject() && je.getAsJsonObject().size() != 0)) {
74                      formatIsSupported = true;
75                  }
76  
77              }
78              if (formatIsSupported) {
79                  return jsonCtxClassConstructor.newInstance(je);
80              } else {
81                  throw new IllegalArgumentException("Passed in argument not recognized as one of the supported formats: "
82                          + pData + "\nIf format is supported, check that it is valid.");
83              }
84          } catch (NoSuchMethodException e) {
85              throw new IllegalArgumentException(e);
86          } catch (IllegalAccessException e) {
87              throw new IllegalArgumentException(e);
88          } catch (InstantiationException e) {
89              throw new IllegalArgumentException(e);
90          } catch (InvocationTargetException e) {
91              throw new IllegalArgumentException(e);
92          } catch (ClassNotFoundException e) {
93              throw new IllegalArgumentException(e);
94          }
95      }
96  
97  
98      /*
99       * See if we get lucky and this is XML
100      */
101     private static String tryXml(String pData) {
102         try {
103             JSONObject jo = XML.toJSONObject(pData);
104             if (null != jo) {
105                 return jo.toString();
106             }
107         } catch (Exception e) {
108             return null;
109         }
110 
111         return null;
112     }
113 
114     /*
115      * This could have been made to return a boolean, but then the calling code would have to again
116      * do a JsonParser.parse() operation, which is unnecessary.
117      */
118     private static JsonElement convertToJson(Object pData) {
119         try {
120             JsonParser jp = new JsonParser();
121             if (pData instanceof JsonElement) {
122                 return JsonContext.generateBrandNewJsonElementObject((JsonElement) pData);
123             } else if (pData instanceof String) {
124                 return jp.parse((String) pData);
125             }
126         } catch (JsonParseException e) {
127             return null;
128         }
129 
130         return null;
131     }
132 
133 }