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
019package org.apache.oozie.client.rest;
020
021import com.google.common.annotations.VisibleForTesting;
022import org.apache.oozie.client.BulkResponse;
023import org.apache.oozie.client.BundleJob;
024import org.apache.oozie.client.CoordinatorAction;
025import org.apache.oozie.client.CoordinatorJob;
026import org.apache.oozie.client.JMSConnectionInfo;
027import org.apache.oozie.client.JMSConnectionInfoWrapper;
028import org.apache.oozie.client.WorkflowAction;
029import org.apache.oozie.client.WorkflowJob;
030import org.apache.oozie.AppType;
031import org.json.simple.JSONArray;
032import org.json.simple.JSONObject;
033import org.json.simple.JSONValue;
034
035import java.lang.reflect.InvocationHandler;
036import java.lang.reflect.Method;
037import java.lang.reflect.Proxy;
038import java.util.ArrayList;
039import java.util.Date;
040import java.util.HashMap;
041import java.util.List;
042import java.util.Map;
043import java.util.Properties;
044import java.util.Set;
045
046/**
047 * JSON to bean converter for {@link WorkflowAction}, {@link WorkflowJob}, {@link CoordinatorAction}
048 * and {@link CoordinatorJob}.
049 * <p>
050 * It uses JDK dynamic proxy to create bean instances.
051 */
052@SuppressWarnings("rawtypes")
053public class JsonToBean {
054
055    @VisibleForTesting
056    static class Property {
057        String label;
058        Class type;
059        boolean isList;
060
061        public Property(String label, Class type) {
062            this(label, type, false);
063        }
064
065        public Property(String label, Class type, boolean isList) {
066            this.label = label;
067            this.type = type;
068            this.isList = isList;
069        }
070    }
071
072    @VisibleForTesting
073    static final Map<String, Property> WF_JOB = new HashMap<String, Property>();
074    @VisibleForTesting
075    static final Map<String, Property> WF_ACTION = new HashMap<String, Property>();
076    @VisibleForTesting
077    static final Map<String, Property> COORD_JOB = new HashMap<String, Property>();
078    @VisibleForTesting
079    static final Map<String, Property> COORD_ACTION = new HashMap<String, Property>();
080    @VisibleForTesting
081    static final Map<String, Property> BUNDLE_JOB = new HashMap<String, Property>();
082    @VisibleForTesting
083    static final Map<String, Property> BULK_RESPONSE = new HashMap<String, Property>();
084    @VisibleForTesting
085    static final Map<String, Property> JMS_CONNECTION_INFO = new HashMap<String, Property>();
086
087    static {
088        WF_ACTION.put("getId", new Property(JsonTags.WORKFLOW_ACTION_ID, String.class));
089        WF_ACTION.put("getName", new Property(JsonTags.WORKFLOW_ACTION_NAME, String.class));
090        WF_ACTION.put("getType", new Property(JsonTags.WORKFLOW_ACTION_TYPE, String.class));
091        WF_ACTION.put("getConf", new Property(JsonTags.WORKFLOW_ACTION_CONF, String.class));
092        WF_ACTION.put("getStatus", new Property(JsonTags.WORKFLOW_ACTION_STATUS, WorkflowAction.Status.class));
093        WF_ACTION.put("getRetries", new Property(JsonTags.WORKFLOW_ACTION_RETRIES, Integer.TYPE));
094        WF_ACTION.put("getStartTime", new Property(JsonTags.WORKFLOW_ACTION_START_TIME, Date.class));
095        WF_ACTION.put("getEndTime", new Property(JsonTags.WORKFLOW_ACTION_END_TIME, Date.class));
096        WF_ACTION.put("getTransition", new Property(JsonTags.WORKFLOW_ACTION_TRANSITION, String.class));
097        WF_ACTION.put("getData", new Property(JsonTags.WORKFLOW_ACTION_DATA, String.class));
098        WF_ACTION.put("getStats", new Property(JsonTags.WORKFLOW_ACTION_STATS, String.class));
099        WF_ACTION.put("getExternalChildIDs", new Property(JsonTags.WORKFLOW_ACTION_EXTERNAL_CHILD_IDS, String.class));
100        WF_ACTION.put("getExternalId", new Property(JsonTags.WORKFLOW_ACTION_EXTERNAL_ID, String.class));
101        WF_ACTION.put("getExternalStatus", new Property(JsonTags.WORKFLOW_ACTION_EXTERNAL_STATUS, String.class));
102        WF_ACTION.put("getTrackerUri", new Property(JsonTags.WORKFLOW_ACTION_TRACKER_URI, String.class));
103        WF_ACTION.put("getConsoleUrl", new Property(JsonTags.WORKFLOW_ACTION_CONSOLE_URL, String.class));
104        WF_ACTION.put("getErrorCode", new Property(JsonTags.WORKFLOW_ACTION_ERROR_CODE, String.class));
105        WF_ACTION.put("getErrorMessage", new Property(JsonTags.WORKFLOW_ACTION_ERROR_MESSAGE, String.class));
106        WF_ACTION.put("toString", new Property(JsonTags.TO_STRING, String.class));
107        WF_ACTION.put("getUserRetryInterval", new Property(JsonTags.WORKFLOW_ACTION_USER_RETRY_INTERVAL, Integer.TYPE));
108        WF_ACTION.put("getUserRetryCount", new Property(JsonTags.WORKFLOW_ACTION_USER_RETRY_COUNT, Integer.TYPE));
109        WF_ACTION.put("getUserRetryMax", new Property(JsonTags.WORKFLOW_ACTION_USER_RETRY_MAX, Integer.TYPE));
110        WF_ACTION.put("getCred", new Property(JsonTags.WORKFLOW_ACTION_CRED, String.class));
111
112        WF_JOB.put("getExternalId", new Property(JsonTags.WORKFLOW_EXTERNAL_ID, String.class));
113        WF_JOB.put("getAppPath", new Property(JsonTags.WORKFLOW_APP_PATH, String.class));
114        WF_JOB.put("getAppName", new Property(JsonTags.WORKFLOW_APP_NAME, String.class));
115        WF_JOB.put("getId", new Property(JsonTags.WORKFLOW_ID, String.class));
116        WF_JOB.put("getConf", new Property(JsonTags.WORKFLOW_CONF, String.class));
117        WF_JOB.put("getStatus", new Property(JsonTags.WORKFLOW_STATUS, WorkflowJob.Status.class));
118        WF_JOB.put("getLastModifiedTime", new Property(JsonTags.WORKFLOW_LAST_MOD_TIME, Date.class));
119        WF_JOB.put("getCreatedTime", new Property(JsonTags.WORKFLOW_CREATED_TIME, Date.class));
120        WF_JOB.put("getStartTime", new Property(JsonTags.WORKFLOW_START_TIME, Date.class));
121        WF_JOB.put("getEndTime", new Property(JsonTags.WORKFLOW_END_TIME, Date.class));
122        WF_JOB.put("getUser", new Property(JsonTags.WORKFLOW_USER, String.class));
123        WF_JOB.put("getGroup", new Property(JsonTags.WORKFLOW_GROUP, String.class));
124        WF_JOB.put("getAcl", new Property(JsonTags.WORKFLOW_ACL, String.class));
125        WF_JOB.put("getRun", new Property(JsonTags.WORKFLOW_RUN, Integer.TYPE));
126        WF_JOB.put("getConsoleUrl", new Property(JsonTags.WORKFLOW_CONSOLE_URL, String.class));
127        WF_JOB.put("getActions", new Property(JsonTags.WORKFLOW_ACTIONS, WorkflowAction.class, true));
128        WF_JOB.put("getParentId", new Property(JsonTags.WORKFLOW_PARENT_ID, String.class));
129        WF_JOB.put("toString", new Property(JsonTags.TO_STRING, String.class));
130
131        COORD_ACTION.put("getId", new Property(JsonTags.COORDINATOR_ACTION_ID, String.class));
132        COORD_ACTION.put("getJobId", new Property(JsonTags.COORDINATOR_JOB_ID, String.class));
133        COORD_ACTION.put("getActionNumber", new Property(JsonTags.COORDINATOR_ACTION_NUMBER, Integer.TYPE));
134        COORD_ACTION.put("getCreatedConf", new Property(JsonTags.COORDINATOR_ACTION_CREATED_CONF, String.class));
135        COORD_ACTION.put("getCreatedTime", new Property(JsonTags.COORDINATOR_ACTION_CREATED_TIME, Date.class));
136        COORD_ACTION.put("getNominalTime", new Property(JsonTags.COORDINATOR_ACTION_NOMINAL_TIME, Date.class));
137        COORD_ACTION.put("getExternalId", new Property(JsonTags.COORDINATOR_ACTION_EXTERNALID, String.class));
138        COORD_ACTION.put("getStatus", new Property(JsonTags.COORDINATOR_ACTION_STATUS, CoordinatorAction.Status.class));
139        COORD_ACTION.put("getRunConf", new Property(JsonTags.COORDINATOR_ACTION_RUNTIME_CONF, String.class));
140        COORD_ACTION
141                .put("getLastModifiedTime", new Property(JsonTags.COORDINATOR_ACTION_LAST_MODIFIED_TIME, Date.class));
142        COORD_ACTION
143                .put("getMissingDependencies", new Property(JsonTags.COORDINATOR_ACTION_MISSING_DEPS, String.class));
144        COORD_ACTION.put("getPushMissingDependencies", new Property(JsonTags.COORDINATOR_ACTION_PUSH_MISSING_DEPS,
145                String.class));
146        COORD_ACTION.put("getExternalStatus", new Property(JsonTags.COORDINATOR_ACTION_EXTERNAL_STATUS, String.class));
147        COORD_ACTION.put("getTrackerUri", new Property(JsonTags.COORDINATOR_ACTION_TRACKER_URI, String.class));
148        COORD_ACTION.put("getConsoleUrl", new Property(JsonTags.COORDINATOR_ACTION_CONSOLE_URL, String.class));
149        COORD_ACTION.put("getErrorCode", new Property(JsonTags.COORDINATOR_ACTION_ERROR_CODE, String.class));
150        COORD_ACTION.put("getErrorMessage", new Property(JsonTags.COORDINATOR_ACTION_ERROR_MESSAGE, String.class));
151        COORD_ACTION.put("toString", new Property(JsonTags.TO_STRING, String.class));
152
153        COORD_JOB.put("getAppPath", new Property(JsonTags.COORDINATOR_JOB_PATH, String.class));
154        COORD_JOB.put("getAppName", new Property(JsonTags.COORDINATOR_JOB_NAME, String.class));
155        COORD_JOB.put("getId", new Property(JsonTags.COORDINATOR_JOB_ID, String.class));
156        COORD_JOB.put("getConf", new Property(JsonTags.COORDINATOR_JOB_CONF, String.class));
157        COORD_JOB.put("getStatus", new Property(JsonTags.COORDINATOR_JOB_STATUS, CoordinatorJob.Status.class));
158        COORD_JOB.put("getExecutionOrder",
159                      new Property(JsonTags.COORDINATOR_JOB_EXECUTIONPOLICY, CoordinatorJob.Execution.class));
160        COORD_JOB.put("getFrequency", new Property(JsonTags.COORDINATOR_JOB_FREQUENCY, String.class));
161        COORD_JOB.put("getTimeUnit", new Property(JsonTags.COORDINATOR_JOB_TIMEUNIT, CoordinatorJob.Timeunit.class));
162        COORD_JOB.put("getTimeZone", new Property(JsonTags.COORDINATOR_JOB_TIMEZONE, String.class));
163        COORD_JOB.put("getConcurrency", new Property(JsonTags.COORDINATOR_JOB_CONCURRENCY, Integer.TYPE));
164        COORD_JOB.put("getTimeout", new Property(JsonTags.COORDINATOR_JOB_TIMEOUT, Integer.TYPE));
165        COORD_JOB.put("getLastActionTime", new Property(JsonTags.COORDINATOR_JOB_LAST_ACTION_TIME, Date.class));
166        COORD_JOB.put("getNextMaterializedTime",
167                      new Property(JsonTags.COORDINATOR_JOB_NEXT_MATERIALIZED_TIME, Date.class));
168        COORD_JOB.put("getCreatedTime", new Property(JsonTags.COORDINATOR_JOB_CREATED_TIME, Date.class));
169        COORD_JOB.put("getStartTime", new Property(JsonTags.COORDINATOR_JOB_START_TIME, Date.class));
170        COORD_JOB.put("getEndTime", new Property(JsonTags.COORDINATOR_JOB_END_TIME, Date.class));
171        COORD_JOB.put("getPauseTime", new Property(JsonTags.COORDINATOR_JOB_PAUSE_TIME, Date.class));
172        COORD_JOB.put("getUser", new Property(JsonTags.COORDINATOR_JOB_USER, String.class));
173        COORD_JOB.put("getGroup", new Property(JsonTags.COORDINATOR_JOB_GROUP, String.class));
174        COORD_JOB.put("getAcl", new Property(JsonTags.COORDINATOR_JOB_ACL, String.class));
175        COORD_JOB.put("getConsoleUrl", new Property(JsonTags.COORDINATOR_JOB_CONSOLE_URL, String.class));
176        COORD_JOB.put("getActions", new Property(JsonTags.COORDINATOR_ACTIONS, CoordinatorAction.class, true));
177        COORD_JOB.put("toString", new Property(JsonTags.TO_STRING, String.class));
178        COORD_JOB.put("getBundleId", new Property(JsonTags.COORDINATOR_JOB_BUNDLE_ID, String.class));
179        COORD_JOB.put("getExternalId", new Property(JsonTags.COORDINATOR_JOB_EXTERNAL_ID, String.class));
180
181        BUNDLE_JOB.put("getAppPath",new Property(JsonTags.BUNDLE_JOB_PATH, String.class));
182        BUNDLE_JOB.put("getAppName",new Property(JsonTags.BUNDLE_JOB_NAME, String.class));
183        BUNDLE_JOB.put("getId",new Property(JsonTags.BUNDLE_JOB_ID, String.class));
184        BUNDLE_JOB.put("getExternalId",new Property(JsonTags.BUNDLE_JOB_EXTERNAL_ID, String.class));
185        BUNDLE_JOB.put("getConf",new Property(JsonTags.BUNDLE_JOB_CONF, String.class));
186        BUNDLE_JOB.put("getStatus",new Property(JsonTags.BUNDLE_JOB_STATUS, BundleJob.Status.class));
187        BUNDLE_JOB.put("getTimeUnit",new Property(JsonTags.BUNDLE_JOB_TIMEUNIT, BundleJob.Timeunit.class));
188        BUNDLE_JOB.put("getTimeout",new Property(JsonTags.BUNDLE_JOB_TIMEOUT, Integer.TYPE));
189        BUNDLE_JOB.put("getKickoffTime",new Property(JsonTags.BUNDLE_JOB_KICKOFF_TIME, Date.class));
190        BUNDLE_JOB.put("getStartTime",new Property(JsonTags.BUNDLE_JOB_START_TIME, Date.class));
191        BUNDLE_JOB.put("getEndTime",new Property(JsonTags.BUNDLE_JOB_END_TIME, Date.class));
192        BUNDLE_JOB.put("getPauseTime",new Property(JsonTags.BUNDLE_JOB_PAUSE_TIME, Date.class));
193        BUNDLE_JOB.put("getCreatedTime",new Property(JsonTags.BUNDLE_JOB_CREATED_TIME, Date.class));
194        BUNDLE_JOB.put("getUser",new Property(JsonTags.BUNDLE_JOB_USER, String.class));
195        BUNDLE_JOB.put("getGroup",new Property(JsonTags.BUNDLE_JOB_GROUP, String.class));
196        BUNDLE_JOB.put("getConsoleUrl",new Property(JsonTags.BUNDLE_JOB_CONSOLE_URL, String.class));
197        BUNDLE_JOB.put("getCoordinators",new Property(JsonTags.BUNDLE_COORDINATOR_JOBS, CoordinatorJob.class, true));
198        BUNDLE_JOB.put("toString", new Property(JsonTags.TO_STRING, String.class));
199        BUNDLE_JOB.put("getAcl", new Property(JsonTags.BUNDLE_JOB_ACL, String.class));
200
201        BULK_RESPONSE.put("getBundle", new Property(JsonTags.BULK_RESPONSE_BUNDLE, BundleJob.class, false));
202        BULK_RESPONSE.put("getCoordinator", new Property(JsonTags.BULK_RESPONSE_COORDINATOR, CoordinatorJob.class, false));
203        BULK_RESPONSE.put("getAction", new Property(JsonTags.BULK_RESPONSE_ACTION, CoordinatorAction.class, false));
204
205        JMS_CONNECTION_INFO.put("getTopicPatternProperties", new Property(JsonTags.JMS_TOPIC_PATTERN, Properties.class));
206        JMS_CONNECTION_INFO.put("getJNDIProperties", new Property(JsonTags.JMS_JNDI_PROPERTIES, Properties.class));
207        JMS_CONNECTION_INFO.put("getTopicPrefix", new Property(JsonTags.JMS_TOPIC_PREFIX, String.class));
208    }
209
210    /**
211     * The dynamic proxy invocation handler used to convert JSON values to bean properties using a mapping.
212     */
213    private static class JsonInvocationHandler implements InvocationHandler {
214        private final Map<String, Property> mapping;
215        private final JSONObject json;
216
217        /**
218         * Invocation handler constructor.
219         *
220         * @param mapping property to JSON/type-info mapping.
221         * @param json the json object to back the property values.
222         */
223        public JsonInvocationHandler(Map<String, Property> mapping, JSONObject json) {
224            this.mapping = mapping;
225            this.json = json;
226        }
227
228        @Override
229        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
230            Property prop = mapping.get(method.getName());
231            if (prop == null) {
232                throw new RuntimeException("Undefined method mapping: " + method.getName());
233            }
234            if (prop.isList) {
235                if (prop.type == WorkflowAction.class) {
236                    return createWorkflowActionList((JSONArray) json.get(prop.label));
237                }
238                else if (prop.type == CoordinatorAction.class) {
239                    return createCoordinatorActionList((JSONArray) json.get(prop.label));
240                }
241                else if (prop.type == CoordinatorJob.class) {
242                    return createCoordinatorJobList((JSONArray) json.get(prop.label));
243                }
244                else {
245                    throw new RuntimeException("Unsupported list type : " + prop.type.getSimpleName());
246                }
247            }
248            else {
249                return parseType(prop.type, json.get(prop.label));
250            }
251        }
252
253        @SuppressWarnings("unchecked")
254        private Object parseType(Class type, Object obj) {
255            if (type == String.class) {
256                return obj == null ? obj : obj.toString();
257            }
258            else if (type == Integer.TYPE) {
259                return (obj != null) ? new Integer(((Long) obj).intValue()) : new Integer(0);
260            }
261            else if (type == Long.TYPE) {
262                return (obj != null) ? obj : new Long(0);
263            }
264            else if (type == Date.class) {
265                return JsonUtils.parseDateRfc822((String) obj);
266            }
267            else if (type.isEnum()) {
268                return Enum.valueOf(type, (String) obj);
269            }
270            else if (type == WorkflowAction.class) {
271                return createWorkflowAction((JSONObject) obj);
272            }
273            else if (type == Properties.class){
274                JSONObject jsonMap = (JSONObject)JSONValue.parse((String)obj);
275                Properties props = new Properties();
276                Set<Map.Entry> entrySet = jsonMap.entrySet();
277                for (Map.Entry jsonEntry: entrySet){
278                    props.put(jsonEntry.getKey(), jsonEntry.getValue());
279                }
280                return props;
281            }
282            else if (type == CoordinatorJob.class) {
283                return createCoordinatorJob((JSONObject) obj);
284            }
285            else if (type == CoordinatorAction.class) {
286                return createCoordinatorAction((JSONObject) obj);
287            }
288            else if (type == BundleJob.class) {
289                return createBundleJob((JSONObject) obj);
290            }
291            else {
292                throw new RuntimeException("Unsupported type : " + type.getSimpleName());
293            }
294        }
295    }
296
297    /**
298     * Creates a workflow action bean from a JSON object.
299     *
300     * @param json json object.
301     * @return a workflow action bean populated with the JSON object values.
302     */
303    public static WorkflowAction createWorkflowAction(JSONObject json) {
304        return (WorkflowAction) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
305                                                       new Class[]{WorkflowAction.class},
306                                                       new JsonInvocationHandler(WF_ACTION, json));
307    }
308
309    /**
310     * Creates a list of workflow action beans from a JSON array.
311     *
312     * @param json json array.
313     * @return a list of workflow action beans from a JSON array.
314     */
315    public static List<WorkflowAction> createWorkflowActionList(JSONArray json) {
316        List<WorkflowAction> list = new ArrayList<WorkflowAction>();
317        for (Object obj : json) {
318            list.add(createWorkflowAction((JSONObject) obj));
319        }
320        return list;
321    }
322
323    /**
324     * Creates a workflow job bean from a JSON object.
325     *
326     * @param json json object.
327     * @return a workflow job bean populated with the JSON object values.
328     */
329    public static WorkflowJob createWorkflowJob(JSONObject json) {
330        return (WorkflowJob) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
331                                                    new Class[]{WorkflowJob.class},
332                                                    new JsonInvocationHandler(WF_JOB, json));
333    }
334
335    /**
336     * Creates a list of workflow job beans from a JSON array.
337     *
338     * @param json json array.
339     * @return a list of workflow job beans from a JSON array.
340     */
341    public static List<WorkflowJob> createWorkflowJobList(JSONArray json) {
342        List<WorkflowJob> list = new ArrayList<WorkflowJob>();
343        for (Object obj : json) {
344            list.add(createWorkflowJob((JSONObject) obj));
345        }
346        return list;
347    }
348
349    /**
350     * Creates a coordinator action bean from a JSON object.
351     *
352     * @param json json object.
353     * @return a coordinator action bean populated with the JSON object values.
354     */
355    public static CoordinatorAction createCoordinatorAction(JSONObject json) {
356        return (CoordinatorAction) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
357                                                          new Class[]{CoordinatorAction.class},
358                                                          new JsonInvocationHandler(COORD_ACTION, json));
359    }
360
361    /**
362     * Creates a list of coordinator action beans from a JSON array.
363     *
364     * @param json json array.
365     * @return a list of coordinator action beans from a JSON array.
366     */
367    public static List<CoordinatorAction> createCoordinatorActionList(JSONArray json) {
368        List<CoordinatorAction> list = new ArrayList<CoordinatorAction>();
369        for (Object obj : json) {
370            list.add(createCoordinatorAction((JSONObject) obj));
371        }
372        return list;
373    }
374
375    /**
376     * Creates a coordinator job bean from a JSON object.
377     *
378     * @param json json object.
379     * @return a coordinator job bean populated with the JSON object values.
380     */
381    public static CoordinatorJob createCoordinatorJob(JSONObject json) {
382        return (CoordinatorJob) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
383                                                       new Class[]{CoordinatorJob.class},
384                                                       new JsonInvocationHandler(COORD_JOB, json));
385    }
386
387
388    /**
389     * Creates a JMSInfo bean from a JSON object.
390     *
391     * @param json json object.
392     * @return a coordinator job bean populated with the JSON object values.
393     */
394    public static JMSConnectionInfo createJMSConnectionInfo(JSONObject json) {
395        final JMSConnectionInfoWrapper jmsInfo = (JMSConnectionInfoWrapper) Proxy.newProxyInstance(
396                JsonToBean.class.getClassLoader(), new Class[] { JMSConnectionInfoWrapper.class },
397                new JsonInvocationHandler(JMS_CONNECTION_INFO, json));
398
399        return new JMSConnectionInfo() {
400            @Override
401            public String getTopicPrefix() {
402                return jmsInfo.getTopicPrefix();
403            }
404
405            @Override
406            public String getTopicPattern(AppType appType) {
407                return (String)jmsInfo.getTopicPatternProperties().get(appType.name());
408            }
409
410            @Override
411            public Properties getJNDIProperties() {
412                return jmsInfo.getJNDIProperties();
413            }
414        };
415    }
416
417    /**
418     * Creates a list of coordinator job beans from a JSON array.
419     *
420     * @param json json array.
421     * @return a list of coordinator job beans from a JSON array.
422     */
423    public static List<CoordinatorJob> createCoordinatorJobList(JSONArray json) {
424        List<CoordinatorJob> list = new ArrayList<CoordinatorJob>();
425        for (Object obj : json) {
426            list.add(createCoordinatorJob((JSONObject) obj));
427        }
428        return list;
429    }
430
431    /**
432     * Creates a bundle job bean from a JSON object.
433     *
434     * @param json json object.
435     * @return a bundle job bean populated with the JSON object values.
436     */
437    public static BundleJob createBundleJob(JSONObject json) {
438        return (BundleJob) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
439                                                       new Class[]{BundleJob.class},
440                                                       new JsonInvocationHandler(BUNDLE_JOB, json));
441    }
442
443    /**
444     * Creates a list of bundle job beans from a JSON array.
445     *
446     * @param json json array.
447     * @return a list of bundle job beans from a JSON array.
448     */
449    public static List<BundleJob> createBundleJobList(JSONArray json) {
450        List<BundleJob> list = new ArrayList<BundleJob>();
451        for (Object obj : json) {
452            list.add(createBundleJob((JSONObject) obj));
453        }
454        return list;
455    }
456
457    /**
458     * Creates a Bulk response object from a JSON object.
459     *
460     * @param json json object.
461     * @return a Bulk response object populated with the JSON object values.
462     */
463    public static BulkResponse createBulkResponse(JSONObject json) {
464        return (BulkResponse) Proxy.newProxyInstance(JsonToBean.class.getClassLoader(),
465                                                    new Class[]{BulkResponse.class},
466                                                    new JsonInvocationHandler(BULK_RESPONSE, json));
467    }
468
469    /**
470     * Creates a list of bulk response beans from a JSON array.
471     *
472     * @param json json array.
473     * @return a list of bulk response beans from a JSON array.
474     */
475    public static List<BulkResponse> createBulkResponseList(JSONArray json) {
476        List<BulkResponse> list = new ArrayList<BulkResponse>();
477        for (Object obj : json) {
478            list.add(createBulkResponse((JSONObject) obj));
479        }
480        return list;
481    }
482
483    /**
484     * Creates a list of bulk write job ids from a JSON array.
485     *
486     * @param json json array.
487     * @return a list of jobs ids from a JSON array.
488     */
489    public static List<String> createBulkWriteJobIdList(JSONArray json) {
490        List<String> list = new ArrayList<String>();
491        for (Object obj : json) {
492            list.add(obj.toString());
493        }
494        return list;
495    }
496
497}