This project has retired. For details please refer to its
Attic page.
001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.oozie.client.rest;
019
020 import org.apache.oozie.client.BulkResponse;
021 import org.apache.oozie.client.BundleJob;
022 import org.apache.oozie.client.CoordinatorAction;
023 import org.apache.oozie.client.CoordinatorJob;
024 import org.apache.oozie.client.WorkflowAction;
025 import org.apache.oozie.client.WorkflowJob;
026 import org.json.simple.JSONArray;
027 import org.json.simple.JSONObject;
028
029 import java.lang.reflect.InvocationHandler;
030 import java.lang.reflect.Method;
031 import java.lang.reflect.Proxy;
032 import java.util.ArrayList;
033 import java.util.Date;
034 import java.util.HashMap;
035 import java.util.List;
036 import java.util.Map;
037
038 /**
039 * JSON to bean converter for {@link WorkflowAction}, {@link WorkflowJob}, {@link CoordinatorAction}
040 * and {@link CoordinatorJob}.
041 * <p/>
042 * It uses JDK dynamic proxy to create bean instances.
043 */
044 public class JsonToBean {
045
046 private static class Property {
047 String label;
048 Class type;
049 boolean isList;
050
051 public Property(String label, Class type) {
052 this(label, type, false);
053 }
054
055 public Property(String label, Class type, boolean isList) {
056 this.label = label;
057 this.type = type;
058 this.isList = isList;
059 }
060 }
061
062 private static final Map<String, Property> WF_JOB = new HashMap<String, Property>();
063 private static final Map<String, Property> WF_ACTION = new HashMap<String, Property>();
064 private static final Map<String, Property> COORD_JOB = new HashMap<String, Property>();
065 private static final Map<String, Property> COORD_ACTION = new HashMap<String, Property>();
066 private static final Map<String, Property> BUNDLE_JOB = new HashMap<String, Property>();
067 private static final Map<String, Property> BULK_RESPONSE = new HashMap<String, Property>();
068
069 static {
070 WF_ACTION.put("getId", new Property(JsonTags.WORKFLOW_ACTION_ID, String.class));
071 WF_ACTION.put("getName", new Property(JsonTags.WORKFLOW_ACTION_NAME, String.class));
072 WF_ACTION.put("getType", new Property(JsonTags.WORKFLOW_ACTION_TYPE, String.class));
073 WF_ACTION.put("getConf", new Property(JsonTags.WORKFLOW_ACTION_CONF, String.class));
074 WF_ACTION.put("getStatus", new Property(JsonTags.WORKFLOW_ACTION_STATUS, WorkflowAction.Status.class));
075 WF_ACTION.put("getRetries", new Property(JsonTags.WORKFLOW_ACTION_RETRIES, Integer.TYPE));
076 WF_ACTION.put("getStartTime", new Property(JsonTags.WORKFLOW_ACTION_START_TIME, Date.class));
077 WF_ACTION.put("getEndTime", new Property(JsonTags.WORKFLOW_ACTION_END_TIME, Date.class));
078 WF_ACTION.put("getTransition", new Property(JsonTags.WORKFLOW_ACTION_TRANSITION, String.class));
079 WF_ACTION.put("getData", new Property(JsonTags.WORKFLOW_ACTION_DATA, String.class));
080 WF_ACTION.put("getStats", new Property(JsonTags.WORKFLOW_ACTION_STATS, String.class));
081 WF_ACTION.put("getExternalChildIDs", new Property(JsonTags.WORKFLOW_ACTION_EXTERNAL_CHILD_IDS, String.class));
082 WF_ACTION.put("getExternalId", new Property(JsonTags.WORKFLOW_ACTION_EXTERNAL_ID, String.class));
083 WF_ACTION.put("getExternalStatus", new Property(JsonTags.WORKFLOW_ACTION_EXTERNAL_STATUS, String.class));
084 WF_ACTION.put("getTrackerUri", new Property(JsonTags.WORKFLOW_ACTION_TRACKER_URI, String.class));
085 WF_ACTION.put("getConsoleUrl", new Property(JsonTags.WORKFLOW_ACTION_CONSOLE_URL, String.class));
086 WF_ACTION.put("getErrorCode", new Property(JsonTags.WORKFLOW_ACTION_ERROR_CODE, String.class));
087 WF_ACTION.put("getErrorMessage", new Property(JsonTags.WORKFLOW_ACTION_ERROR_MESSAGE, String.class));
088 WF_ACTION.put("toString", new Property(JsonTags.TO_STRING, String.class));
089
090 WF_JOB.put("getExternalId", new Property(JsonTags.WORKFLOW_EXTERNAL_ID, String.class));
091 WF_JOB.put("getAppPath", new Property(JsonTags.WORKFLOW_APP_PATH, String.class));
092 WF_JOB.put("getAppName", new Property(JsonTags.WORKFLOW_APP_NAME, String.class));
093 WF_JOB.put("getId", new Property(JsonTags.WORKFLOW_ID, String.class));
094 WF_JOB.put("getConf", new Property(JsonTags.WORKFLOW_CONF, String.class));
095 WF_JOB.put("getStatus", new Property(JsonTags.WORKFLOW_STATUS, WorkflowJob.Status.class));
096 WF_JOB.put("getLastModifiedTime", new Property(JsonTags.WORKFLOW_LAST_MOD_TIME, Date.class));
097 WF_JOB.put("getCreatedTime", new Property(JsonTags.WORKFLOW_CREATED_TIME, Date.class));
098 WF_JOB.put("getStartTime", new Property(JsonTags.WORKFLOW_CREATED_TIME, Date.class));
099 WF_JOB.put("getEndTime", new Property(JsonTags.WORKFLOW_END_TIME, Date.class));
100 WF_JOB.put("getUser", new Property(JsonTags.WORKFLOW_USER, String.class));
101 WF_JOB.put("getGroup", new Property(JsonTags.WORKFLOW_GROUP, String.class));
102 WF_JOB.put("getAcl", new Property(JsonTags.WORKFLOW_ACL, String.class));
103 WF_JOB.put("getRun", new Property(JsonTags.WORKFLOW_RUN, Integer.TYPE));
104 WF_JOB.put("getConsoleUrl", new Property(JsonTags.WORKFLOW_CONSOLE_URL, String.class));
105 WF_JOB.put("getActions", new Property(JsonTags.WORKFLOW_ACTIONS, WorkflowAction.class, true));
106 WF_JOB.put("getParentId", new Property(JsonTags.WORKFLOW_PARENT_ID, String.class));
107 WF_JOB.put("toString", new Property(JsonTags.TO_STRING, String.class));
108
109 COORD_ACTION.put("getId", new Property(JsonTags.COORDINATOR_ACTION_ID, String.class));
110 COORD_ACTION.put("getJobId", new Property(JsonTags.COORDINATOR_JOB_ID, String.class));
111 COORD_ACTION.put("getActionNumber", new Property(JsonTags.COORDINATOR_ACTION_NUMBER, Integer.TYPE));
112 COORD_ACTION.put("getCreatedConf", new Property(JsonTags.COORDINATOR_ACTION_CREATED_CONF, String.class));
113 COORD_ACTION.put("getCreatedTime", new Property(JsonTags.COORDINATOR_ACTION_CREATED_TIME, Date.class));
114 COORD_ACTION.put("getNominalTime", new Property(JsonTags.COORDINATOR_ACTION_NOMINAL_TIME, Date.class));
115 COORD_ACTION.put("getExternalId", new Property(JsonTags.COORDINATOR_ACTION_EXTERNALID, String.class));
116 COORD_ACTION.put("getStatus", new Property(JsonTags.COORDINATOR_ACTION_STATUS, CoordinatorAction.Status.class));
117 COORD_ACTION.put("getRunConf", new Property(JsonTags.COORDINATOR_ACTION_RUNTIME_CONF, String.class));
118 COORD_ACTION
119 .put("getLastModifiedTime", new Property(JsonTags.COORDINATOR_ACTION_LAST_MODIFIED_TIME, Date.class));
120 COORD_ACTION
121 .put("getMissingDependencies", new Property(JsonTags.COORDINATOR_ACTION_MISSING_DEPS, String.class));
122 COORD_ACTION.put("getExternalStatus", new Property(JsonTags.COORDINATOR_ACTION_EXTERNAL_STATUS, String.class));
123 COORD_ACTION.put("getTrackerUri", new Property(JsonTags.COORDINATOR_ACTION_TRACKER_URI, String.class));
124 COORD_ACTION.put("getConsoleUrl", new Property(JsonTags.COORDINATOR_ACTION_CONSOLE_URL, String.class));
125 COORD_ACTION.put("getErrorCode", new Property(JsonTags.COORDINATOR_ACTION_ERROR_CODE, String.class));
126 COORD_ACTION.put("getErrorMessage", new Property(JsonTags.COORDINATOR_ACTION_ERROR_MESSAGE, String.class));
127 COORD_ACTION.put("toString", new Property(JsonTags.TO_STRING, String.class));
128
129 COORD_JOB.put("getAppPath", new Property(JsonTags.COORDINATOR_JOB_PATH, String.class));
130 COORD_JOB.put("getAppName", new Property(JsonTags.COORDINATOR_JOB_NAME, String.class));
131 COORD_JOB.put("getId", new Property(JsonTags.COORDINATOR_JOB_ID, String.class));
132 COORD_JOB.put("getConf", new Property(JsonTags.COORDINATOR_JOB_CONF, String.class));
133 COORD_JOB.put("getStatus", new Property(JsonTags.COORDINATOR_JOB_STATUS, CoordinatorJob.Status.class));
134 COORD_JOB.put("getExecutionOrder",
135 new Property(JsonTags.COORDINATOR_JOB_EXECUTIONPOLICY, CoordinatorJob.Execution.class));
136 COORD_JOB.put("getFrequency", new Property(JsonTags.COORDINATOR_JOB_FREQUENCY, Integer.TYPE));
137 COORD_JOB.put("getTimeUnit", new Property(JsonTags.COORDINATOR_JOB_TIMEUNIT, CoordinatorJob.Timeunit.class));
138 COORD_JOB.put("getTimeZone", new Property(JsonTags.COORDINATOR_JOB_TIMEZONE, String.class));
139 COORD_JOB.put("getConcurrency", new Property(JsonTags.COORDINATOR_JOB_CONCURRENCY, Integer.TYPE));
140 COORD_JOB.put("getTimeout", new Property(JsonTags.COORDINATOR_JOB_TIMEOUT, Integer.TYPE));
141 COORD_JOB.put("getLastActionTime", new Property(JsonTags.COORDINATOR_JOB_LAST_ACTION_TIME, Date.class));
142 COORD_JOB.put("getNextMaterializedTime",
143 new Property(JsonTags.COORDINATOR_JOB_NEXT_MATERIALIZED_TIME, Date.class));
144 COORD_JOB.put("getStartTime", new Property(JsonTags.COORDINATOR_JOB_START_TIME, Date.class));
145 COORD_JOB.put("getEndTime", new Property(JsonTags.COORDINATOR_JOB_END_TIME, Date.class));
146 COORD_JOB.put("getPauseTime", new Property(JsonTags.COORDINATOR_JOB_PAUSE_TIME, Date.class));
147 COORD_JOB.put("getUser", new Property(JsonTags.COORDINATOR_JOB_USER, String.class));
148 COORD_JOB.put("getGroup", new Property(JsonTags.COORDINATOR_JOB_GROUP, String.class));
149 COORD_JOB.put("getAcl", new Property(JsonTags.COORDINATOR_JOB_ACL, String.class));
150 COORD_JOB.put("getConsoleUrl", new Property(JsonTags.COORDINATOR_JOB_CONSOLE_URL, String.class));
151 COORD_JOB.put("getActions", new Property(JsonTags.COORDINATOR_ACTIONS, CoordinatorAction.class, true));
152 COORD_JOB.put("toString", new Property(JsonTags.TO_STRING, String.class));
153
154 BUNDLE_JOB.put("getActions", new Property(JsonTags.COORDINATOR_ACTIONS, CoordinatorAction.class, true));
155
156 BUNDLE_JOB.put("getAppPath",new Property(JsonTags.BUNDLE_JOB_PATH, String.class));
157 BUNDLE_JOB.put("getAppName",new Property(JsonTags.BUNDLE_JOB_NAME, String.class));
158 BUNDLE_JOB.put("getId",new Property(JsonTags.BUNDLE_JOB_ID, String.class));
159 BUNDLE_JOB.put("getExternalId",new Property(JsonTags.BUNDLE_JOB_EXTERNAL_ID, String.class));
160 BUNDLE_JOB.put("getConf",new Property(JsonTags.BUNDLE_JOB_CONF, String.class));
161 BUNDLE_JOB.put("getStatus",new Property(JsonTags.BUNDLE_JOB_STATUS, BundleJob.Status.class));
162 BUNDLE_JOB.put("getTimeUnit",new Property(JsonTags.BUNDLE_JOB_TIMEUNIT, BundleJob.Timeunit.class));
163 BUNDLE_JOB.put("getTimeout",new Property(JsonTags.BUNDLE_JOB_TIMEOUT, Integer.TYPE));
164 BUNDLE_JOB.put("getKickoffTime",new Property(JsonTags.BUNDLE_JOB_KICKOFF_TIME, Date.class));
165 BUNDLE_JOB.put("getStartTime",new Property(JsonTags.BUNDLE_JOB_START_TIME, Date.class));
166 BUNDLE_JOB.put("getEndTime",new Property(JsonTags.BUNDLE_JOB_END_TIME, Date.class));
167 BUNDLE_JOB.put("getPauseTime",new Property(JsonTags.BUNDLE_JOB_PAUSE_TIME, Date.class));
168 BUNDLE_JOB.put("getCreatedTime",new Property(JsonTags.BUNDLE_JOB_CREATED_TIME, Date.class));
169 BUNDLE_JOB.put("getUser",new Property(JsonTags.BUNDLE_JOB_USER, String.class));
170 BUNDLE_JOB.put("getGroup",new Property(JsonTags.BUNDLE_JOB_GROUP, String.class));
171 BUNDLE_JOB.put("getConsoleUrl",new Property(JsonTags.BUNDLE_JOB_CONSOLE_URL, String.class));
172 BUNDLE_JOB.put("getCoordinators",new Property(JsonTags.BUNDLE_COORDINATOR_JOBS, CoordinatorJob.class, true));
173 BUNDLE_JOB.put("toString", new Property(JsonTags.TO_STRING, String.class));
174
175 BULK_RESPONSE.put("getBundle", new Property(JsonTags.BULK_RESPONSE_BUNDLE, BundleJob.class, true));
176 BULK_RESPONSE.put("getCoordinator", new Property(JsonTags.BULK_RESPONSE_COORDINATOR, CoordinatorJob.class, true));
177 BULK_RESPONSE.put("getAction", new Property(JsonTags.BULK_RESPONSE_ACTION, CoordinatorAction.class, true));
178
179 }
180
181 /**
182 * The dynamic proxy invocation handler used to convert JSON values to bean properties using a mapping.
183 */
184 private static class JsonInvocationHandler implements InvocationHandler {
185 private final Map<String, Property> mapping;
186 private final JSONObject json;
187
188 /**
189 * Invocation handler constructor.
190 *
191 * @param mapping property to JSON/type-info mapping.
192 * @param json the json object to back the property values.
193 */
194 public JsonInvocationHandler(Map<String, Property> mapping, JSONObject json) {
195 this.mapping = mapping;
196 this.json = json;
197 }
198
199 @Override
200 public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
201 Property prop = mapping.get(method.getName());
202 if (prop == null) {
203 throw new RuntimeException("Undefined method mapping: " + method.getName());
204 }
205 if (prop.isList) {
206 if (prop.type == WorkflowAction.class) {
207 return createWorkflowActionList((JSONArray) json.get(prop.label));
208 }
209 else if (prop.type == CoordinatorAction.class) {
210 return createCoordinatorActionList((JSONArray) json.get(prop.label));
211 }
212 else if (prop.type == CoordinatorJob.class) {
213 return createCoordinatorJobList((JSONArray) json.get(prop.label));
214 }
215 else {
216 throw new RuntimeException("Unsupported list type : " + prop.type.getSimpleName());
217 }
218 }
219 else {
220 return parseType(prop.type, json.get(prop.label));
221 }
222 }
223
224 @SuppressWarnings("unchecked")
225 private Object parseType(Class type, Object obj) {
226 if (type == String.class) {
227 return obj;
228 }
229 else if (type == Integer.TYPE) {
230 return (obj != null) ? new Integer(((Long) obj).intValue()) : new Integer(0);
231 }
232 else if (type == Long.TYPE) {
233 return (obj != null) ? obj : new Long(0);
234 }
235 else if (type == Date.class) {
236 return JsonUtils.parseDateRfc822((String) obj);
237 }
238 else if (type.isEnum()) {
239 return Enum.valueOf(type, (String) obj);
240 }
241 else if (type == WorkflowAction.class) {
242 return createWorkflowAction((JSONObject) obj);
243 }
244 else {
245 throw new RuntimeException("Unsupported type : " + type.getSimpleName());
246 }
247 }
248 }
249
250 /**
251 * Creates a workflow action bean from a JSON object.
252 *
253 * @param json json object.
254 * @return a workflow action bean populated with the JSON object values.
255 */
256 public static WorkflowAction createWorkflowAction(JSONObject json) {
257 return (WorkflowAction) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
258 new Class[]{WorkflowAction.class},
259 new JsonInvocationHandler(WF_ACTION, json));
260 }
261
262 /**
263 * Creates a list of workflow action beans from a JSON array.
264 *
265 * @param json json array.
266 * @return a list of workflow action beans from a JSON array.
267 */
268 public static List<WorkflowAction> createWorkflowActionList(JSONArray json) {
269 List<WorkflowAction> list = new ArrayList<WorkflowAction>();
270 for (Object obj : json) {
271 list.add(createWorkflowAction((JSONObject) obj));
272 }
273 return list;
274 }
275
276 /**
277 * Creates a workflow job bean from a JSON object.
278 *
279 * @param json json object.
280 * @return a workflow job bean populated with the JSON object values.
281 */
282 public static WorkflowJob createWorkflowJob(JSONObject json) {
283 return (WorkflowJob) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
284 new Class[]{WorkflowJob.class},
285 new JsonInvocationHandler(WF_JOB, json));
286 }
287
288 /**
289 * Creates a list of workflow job beans from a JSON array.
290 *
291 * @param json json array.
292 * @return a list of workflow job beans from a JSON array.
293 */
294 public static List<WorkflowJob> createWorkflowJobList(JSONArray json) {
295 List<WorkflowJob> list = new ArrayList<WorkflowJob>();
296 for (Object obj : json) {
297 list.add(createWorkflowJob((JSONObject) obj));
298 }
299 return list;
300 }
301
302 /**
303 * Creates a coordinator action bean from a JSON object.
304 *
305 * @param json json object.
306 * @return a coordinator action bean populated with the JSON object values.
307 */
308 public static CoordinatorAction createCoordinatorAction(JSONObject json) {
309 return (CoordinatorAction) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
310 new Class[]{CoordinatorAction.class},
311 new JsonInvocationHandler(COORD_ACTION, json));
312 }
313
314 /**
315 * Creates a list of coordinator action beans from a JSON array.
316 *
317 * @param json json array.
318 * @return a list of coordinator action beans from a JSON array.
319 */
320 public static List<CoordinatorAction> createCoordinatorActionList(JSONArray json) {
321 List<CoordinatorAction> list = new ArrayList<CoordinatorAction>();
322 for (Object obj : json) {
323 list.add(createCoordinatorAction((JSONObject) obj));
324 }
325 return list;
326 }
327
328 /**
329 * Creates a coordinator job bean from a JSON object.
330 *
331 * @param json json object.
332 * @return a coordinator job bean populated with the JSON object values.
333 */
334 public static CoordinatorJob createCoordinatorJob(JSONObject json) {
335 return (CoordinatorJob) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
336 new Class[]{CoordinatorJob.class},
337 new JsonInvocationHandler(COORD_JOB, json));
338 }
339
340 /**
341 * Creates a list of coordinator job beans from a JSON array.
342 *
343 * @param json json array.
344 * @return a list of coordinator job beans from a JSON array.
345 */
346 public static List<CoordinatorJob> createCoordinatorJobList(JSONArray json) {
347 List<CoordinatorJob> list = new ArrayList<CoordinatorJob>();
348 for (Object obj : json) {
349 list.add(createCoordinatorJob((JSONObject) obj));
350 }
351 return list;
352 }
353
354 /**
355 * Creates a bundle job bean from a JSON object.
356 *
357 * @param json json object.
358 * @return a bundle job bean populated with the JSON object values.
359 */
360 public static BundleJob createBundleJob(JSONObject json) {
361 return (BundleJob) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
362 new Class[]{BundleJob.class},
363 new JsonInvocationHandler(BUNDLE_JOB, json));
364 }
365
366 /**
367 * Creates a list of bundle job beans from a JSON array.
368 *
369 * @param json json array.
370 * @return a list of bundle job beans from a JSON array.
371 */
372 public static List<BundleJob> createBundleJobList(JSONArray json) {
373 List<BundleJob> list = new ArrayList<BundleJob>();
374 for (Object obj : json) {
375 list.add(createBundleJob((JSONObject) obj));
376 }
377 return list;
378 }
379
380 /**
381 * Creates a list of bulk response beans from a JSON array.
382 *
383 * @param json json array.
384 * @return a list of bulk response beans from a JSON array.
385 */
386 public static List<BulkResponse> createBulkResponseList(JSONArray json) {
387 List<BulkResponse> list = new ArrayList<BulkResponse>();
388 for (Object obj : json) {
389 BulkResponse bulkObj = (BulkResponse) Proxy.newProxyInstance
390 (JsonToBean.class.getClassLoader(), new Class[]{BulkResponse.class},
391 new JsonInvocationHandler(BULK_RESPONSE, (JSONObject) obj));
392 list.add(bulkObj);
393 }
394 return list;
395 }
396 }