001    /**
002      * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
003     * Licensed under the Apache License, Version 2.0 (the "License");
004     * you may not use this file except in compliance with the License.
005     * You may obtain a copy of the License at
006     *
007     *   http://www.apache.org/licenses/LICENSE-2.0
008     *
009     *  Unless required by applicable law or agreed to in writing, software
010     *  distributed under the License is distributed on an "AS IS" BASIS,
011     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012     *  See the License for the specific language governing permissions and
013     *  limitations under the License. See accompanying LICENSE file.
014     */
015    package org.apache.oozie.store;
016    
017    import java.sql.SQLException;
018    import java.sql.Timestamp;
019    import java.util.ArrayList;
020    import java.util.Date;
021    import java.util.List;
022    import java.util.Map;
023    import java.util.concurrent.Callable;
024    
025    import javax.persistence.EntityManager;
026    import javax.persistence.Query;
027    
028    import org.apache.oozie.CoordinatorActionBean;
029    import org.apache.oozie.CoordinatorJobBean;
030    import org.apache.oozie.CoordinatorJobInfo;
031    import org.apache.oozie.ErrorCode;
032    import org.apache.oozie.client.CoordinatorJob.Status;
033    import org.apache.oozie.client.CoordinatorJob.Timeunit;
034    import org.apache.oozie.service.InstrumentationService;
035    import org.apache.oozie.service.Services;
036    import org.apache.oozie.util.DateUtils;
037    import org.apache.oozie.util.Instrumentation;
038    import org.apache.oozie.util.ParamChecker;
039    import org.apache.oozie.util.XLog;
040    import org.apache.oozie.workflow.WorkflowException;
041    import org.apache.openjpa.persistence.OpenJPAPersistence;
042    import org.apache.openjpa.persistence.OpenJPAQuery;
043    import org.apache.openjpa.persistence.jdbc.FetchDirection;
044    import org.apache.openjpa.persistence.jdbc.JDBCFetchPlan;
045    import org.apache.openjpa.persistence.jdbc.LRSSizeAlgorithm;
046    import org.apache.openjpa.persistence.jdbc.ResultSetType;
047    
048    /**
049     * DB Implementation of Coord Store
050     */
051    public class CoordinatorStore extends Store {
052        private final XLog log = XLog.getLog(getClass());
053    
054        private EntityManager entityManager;
055        private static final String INSTR_GROUP = "db";
056        public static final int LOCK_TIMEOUT = 50000;
057        private static final long DAY_IN_MS = 24 * 60 * 60 * 1000;
058    
059        public CoordinatorStore(boolean selectForUpdate) throws StoreException {
060            super();
061            entityManager = getEntityManager();
062        }
063    
064        public CoordinatorStore(Store store, boolean selectForUpdate) throws StoreException {
065            super(store);
066            entityManager = getEntityManager();
067        }
068    
069        /**
070         * Create a CoordJobBean. It also creates the process instance for the job.
071         *
072         * @param workflow workflow bean
073         * @throws StoreException
074         */
075    
076        public void insertCoordinatorJob(final CoordinatorJobBean coordinatorJob) throws StoreException {
077            ParamChecker.notNull(coordinatorJob, "coordinatorJob");
078    
079            doOperation("insertCoordinatorJob", new Callable<Void>() {
080                public Void call() throws StoreException {
081                    entityManager.persist(coordinatorJob);
082                    return null;
083                }
084            });
085        }
086    
087        /**
088         * Load the CoordinatorJob into a Bean and return it. Also load the Workflow Instance into the bean. And lock the
089         * Workflow depending on the locking parameter.
090         *
091         * @param id Job ID
092         * @param locking Flag for Table Lock
093         * @return CoordinatorJobBean
094         * @throws StoreException
095         */
096        public CoordinatorJobBean getCoordinatorJob(final String id, final boolean locking) throws StoreException {
097            ParamChecker.notEmpty(id, "CoordJobId");
098            CoordinatorJobBean cjBean = doOperation("getCoordinatorJob", new Callable<CoordinatorJobBean>() {
099                @SuppressWarnings("unchecked")
100                public CoordinatorJobBean call() throws StoreException {
101                    Query q = entityManager.createNamedQuery("GET_COORD_JOB");
102                    q.setParameter("id", id);
103                    /*
104                     * if (locking) { OpenJPAQuery oq = OpenJPAPersistence.cast(q);
105                     * // q.setHint("openjpa.FetchPlan.ReadLockMode","WRITE");
106                     * FetchPlan fetch = oq.getFetchPlan();
107                     * fetch.setReadLockMode(LockModeType.WRITE);
108                     * fetch.setLockTimeout(-1); // 1 second }
109                     */
110                    List<CoordinatorJobBean> cjBeans = q.getResultList();
111    
112                    if (cjBeans.size() > 0) {
113                        return cjBeans.get(0);
114                    }
115                    else {
116                        throw new StoreException(ErrorCode.E0604, id);
117                    }
118                }
119            });
120    
121            cjBean.setStatus(cjBean.getStatus());
122            return cjBean;
123        }
124    
125        /**
126         * Get a list of Coordinator Jobs that should be materialized. Jobs with a 'last materialized time' older than the
127         * argument will be returned.
128         *
129         * @param d Date
130         * @return List of Coordinator Jobs that have a last materialized time older than input date
131         * @throws StoreException
132         */
133        public List<CoordinatorJobBean> getCoordinatorJobsToBeMaterialized(final Date d, final int limit)
134                throws StoreException {
135    
136            ParamChecker.notNull(d, "Coord Job Materialization Date");
137            List<CoordinatorJobBean> cjBeans = doOperation("getCoordinatorJobsToBeMaterialized",
138                                                                                      new Callable<List<CoordinatorJobBean>>() {
139                                                                                          public List<CoordinatorJobBean> call() throws StoreException {
140    
141                                                                                              List<CoordinatorJobBean> cjBeans;
142                                                                                              List<CoordinatorJobBean> jobList = new ArrayList<CoordinatorJobBean>();
143                                                                                              try {
144                                                                                                  Query q = entityManager.createNamedQuery("GET_COORD_JOBS_OLDER_THAN");
145                                                                                                  q.setParameter("matTime", new Timestamp(d.getTime()));
146                                                                                                  if (limit > 0) {
147                                                                                                      q.setMaxResults(limit);
148                                                                                                  }
149                                                                                                  /*
150                                                                                                  OpenJPAQuery oq = OpenJPAPersistence.cast(q);
151                                                                                                  FetchPlan fetch = oq.getFetchPlan();
152                                                                                                  fetch.setReadLockMode(LockModeType.WRITE);
153                                                                                                  fetch.setLockTimeout(-1); // no limit
154                                                                                                  */
155                                                                                                  cjBeans = q.getResultList();
156                                                                                                  // copy results to a new object
157                                                                                                  for (CoordinatorJobBean j : cjBeans) {
158                                                                                                      jobList.add(j);
159                                                                                                  }
160                                                                                              }
161                                                                                              catch (IllegalStateException e) {
162                                                                                                  throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
163                                                                                              }
164                                                                                              return jobList;
165    
166                                                                                          }
167                                                                                      });
168            return cjBeans;
169        }
170    
171        /**
172         * A list of Coordinator Jobs that are matched with the status and have last materialized time' older than
173         * checkAgeSecs will be returned.
174         *
175         * @param checkAgeSecs Job age in Seconds
176         * @param status Coordinator Job Status
177         * @param limit Number of results to return
178         * @param locking Flag for Table Lock
179         * @return List of Coordinator Jobs that are matched with the parameters.
180         * @throws StoreException
181         */
182        public List<CoordinatorJobBean> getCoordinatorJobsOlderThanStatus(final long checkAgeSecs, final String status,
183                                                                          final int limit, final boolean locking) throws StoreException {
184    
185            ParamChecker.notNull(status, "Coord Job Status");
186            List<CoordinatorJobBean> cjBeans = doOperation("getCoordinatorJobsOlderThanStatus",
187                                                                                      new Callable<List<CoordinatorJobBean>>() {
188                                                                                          public List<CoordinatorJobBean> call() throws StoreException {
189    
190                                                                                              List<CoordinatorJobBean> cjBeans;
191                                                                                              List<CoordinatorJobBean> jobList = new ArrayList<CoordinatorJobBean>();
192                                                                                              try {
193                                                                                                  Query q = entityManager.createNamedQuery("GET_COORD_JOBS_OLDER_THAN_STATUS");
194                                                                                                  Timestamp ts = new Timestamp(System.currentTimeMillis() - checkAgeSecs * 1000);
195                                                                                                  q.setParameter("lastModTime", ts);
196                                                                                                  q.setParameter("status", status);
197                                                                                                  if (limit > 0) {
198                                                                                                      q.setMaxResults(limit);
199                                                                                                  }
200                                                                                                  /*
201                                                                                                  * if (locking) { OpenJPAQuery oq =
202                                                                                                  * OpenJPAPersistence.cast(q); FetchPlan fetch =
203                                                                                                  * oq.getFetchPlan();
204                                                                                                  * fetch.setReadLockMode(LockModeType.WRITE);
205                                                                                                  * fetch.setLockTimeout(-1); // no limit }
206                                                                                                  */
207                                                                                                  cjBeans = q.getResultList();
208                                                                                                  for (CoordinatorJobBean j : cjBeans) {
209                                                                                                      jobList.add(j);
210                                                                                                  }
211                                                                                              }
212                                                                                              catch (Exception e) {
213                                                                                                  throw new StoreException(ErrorCode.E0603, e.getMessage(), e);
214                                                                                              }
215                                                                                              return jobList;
216    
217                                                                                          }
218                                                                                      });
219            return cjBeans;
220        }
221    
222        /**
223         * Load the CoordinatorAction into a Bean and return it.
224         *
225         * @param id action ID
226         * @return CoordinatorActionBean
227         * @throws StoreException
228         */
229        public CoordinatorActionBean getCoordinatorAction(final String id, final boolean locking) throws StoreException {
230            ParamChecker.notEmpty(id, "actionID");
231            CoordinatorActionBean caBean = doOperation("getCoordinatorAction", new Callable<CoordinatorActionBean>() {
232                public CoordinatorActionBean call() throws StoreException {
233                    Query q = entityManager.createNamedQuery("GET_COORD_ACTION");
234                    q.setParameter("id", id);
235                    OpenJPAQuery oq = OpenJPAPersistence.cast(q);
236                    /*
237                     * if (locking) { //q.setHint("openjpa.FetchPlan.ReadLockMode",
238                     * "WRITE"); FetchPlan fetch = oq.getFetchPlan();
239                     * fetch.setReadLockMode(LockModeType.WRITE);
240                     * fetch.setLockTimeout(-1); // no limit }
241                     */
242    
243                    CoordinatorActionBean action = null;
244                    List<CoordinatorActionBean> actions = q.getResultList();
245                    if (actions.size() > 0) {
246                        action = actions.get(0);
247                    }
248                    else {
249                        throw new StoreException(ErrorCode.E0605, id);
250                    }
251    
252                    /*
253                     * if (locking) return action; else
254                     */
255                    return getBeanForRunningCoordAction(action);
256                }
257            });
258            return caBean;
259        }
260    
261        /**
262         * Return CoordinatorActions for a jobID. Action should be in READY state. Number of returned actions should be <=
263         * concurrency number. Sort returned actions based on execution order (FIFO, LIFO, LAST_ONLY)
264         *
265         * @param id job ID
266         * @param numResults number of results to return
267         * @param executionOrder execution for this job - FIFO, LIFO, LAST_ONLY
268         * @return List of CoordinatorActionBean
269         * @throws StoreException
270         */
271        public List<CoordinatorActionBean> getCoordinatorActionsForJob(final String id, final int numResults,
272                                                                       final String executionOrder) throws StoreException {
273            ParamChecker.notEmpty(id, "jobID");
274            List<CoordinatorActionBean> caBeans = doOperation("getCoordinatorActionsForJob",
275                                                              new Callable<List<CoordinatorActionBean>>() {
276                                                                  public List<CoordinatorActionBean> call() throws StoreException {
277    
278                                                                      List<CoordinatorActionBean> caBeans;
279                                                                      Query q;
280                                                                      // check if executionOrder is FIFO, LIFO, or LAST_ONLY
281                                                                      if (executionOrder.equalsIgnoreCase("FIFO")) {
282                                                                          q = entityManager.createNamedQuery("GET_COORD_ACTIONS_FOR_JOB_FIFO");
283                                                                      }
284                                                                      else {
285                                                                          q = entityManager.createNamedQuery("GET_COORD_ACTIONS_FOR_JOB_LIFO");
286                                                                      }
287                                                                      q.setParameter("jobId", id);
288                                                                      // if executionOrder is LAST_ONLY, only retrieve first
289                                                                      // record in LIFO,
290                                                                      // otherwise, use numResults if it is positive.
291                                                                      if (executionOrder.equalsIgnoreCase("LAST_ONLY")) {
292                                                                          q.setMaxResults(1);
293                                                                      }
294                                                                      else {
295                                                                          if (numResults > 0) {
296                                                                              q.setMaxResults(numResults);
297                                                                          }
298                                                                      }
299                                                                      caBeans = q.getResultList();
300                                                                      return caBeans;
301                                                                  }
302                                                              });
303            return caBeans;
304        }
305    
306        /**
307         * Return CoordinatorActions for a jobID. Action should be in READY state. Number of returned actions should be <=
308         * concurrency number.
309         *
310         * @param id job ID
311         * @return Number of running actions
312         * @throws StoreException
313         */
314        public int getCoordinatorRunningActionsCount(final String id) throws StoreException {
315            ParamChecker.notEmpty(id, "jobID");
316            Integer cnt = doOperation("getCoordinatorRunningActionsCount", new Callable<Integer>() {
317                public Integer call() throws SQLException {
318    
319                    Query q = entityManager.createNamedQuery("GET_COORD_RUNNING_ACTIONS_COUNT");
320    
321                    q.setParameter("jobId", id);
322                    Long count = (Long) q.getSingleResult();
323                    return Integer.valueOf(count.intValue());
324                }
325            });
326            return cnt.intValue();
327        }
328    
329        /**
330         * Create a new Action record in the ACTIONS table with the given Bean.
331         *
332         * @param action WorkflowActionBean
333         * @throws StoreException If the action is already present
334         */
335        public void insertCoordinatorAction(final CoordinatorActionBean action) throws StoreException {
336            ParamChecker.notNull(action, "CoordinatorActionBean");
337            doOperation("insertCoordinatorAction", new Callable<Void>() {
338                public Void call() throws StoreException {
339                    entityManager.persist(action);
340                    return null;
341                }
342            });
343        }
344    
345        /**
346         * Update the given action bean to DB.
347         *
348         * @param action Action Bean
349         * @throws StoreException if action doesn't exist
350         */
351        public void updateCoordinatorAction(final CoordinatorActionBean action) throws StoreException {
352            ParamChecker.notNull(action, "CoordinatorActionBean");
353            doOperation("updateCoordinatorAction", new Callable<Void>() {
354                public Void call() throws StoreException {
355                    Query q = entityManager.createNamedQuery("UPDATE_COORD_ACTION");
356                    q.setParameter("id", action.getId());
357                    setActionQueryParameters(action, q);
358                    q.executeUpdate();
359                    return null;
360                }
361            });
362        }
363    
364        /**
365         * Update the given action bean to DB.
366         *
367         * @param action Action Bean
368         * @throws StoreException if action doesn't exist
369         */
370        public void updateCoordActionMin(final CoordinatorActionBean action) throws StoreException {
371            ParamChecker.notNull(action, "CoordinatorActionBean");
372            doOperation("updateCoordinatorAction", new Callable<Void>() {
373                public Void call() throws StoreException {
374                    Query q = entityManager.createNamedQuery("UPDATE_COORD_ACTION_MIN");
375                    q.setParameter("id", action.getId());
376                    q.setParameter("missingDependencies", action.getMissingDependencies());
377                    q.setParameter("lastModifiedTime", new Date());
378                    q.setParameter("status", action.getStatus().toString());
379                    q.setParameter("actionXml", action.getActionXml());
380                    q.executeUpdate();
381                    return null;
382                }
383            });
384        }
385    
386        /**
387         * Update the given coordinator job bean to DB.
388         *
389         * @param jobbean Coordinator Job Bean
390         * @throws StoreException if action doesn't exist
391         */
392        public void updateCoordinatorJob(final CoordinatorJobBean job) throws StoreException {
393            ParamChecker.notNull(job, "CoordinatorJobBean");
394            doOperation("updateJob", new Callable<Void>() {
395                public Void call() throws StoreException {
396                    Query q = entityManager.createNamedQuery("UPDATE_COORD_JOB");
397                    q.setParameter("id", job.getId());
398                    setJobQueryParameters(job, q);
399                    q.executeUpdate();
400                    return null;
401                }
402            });
403        }
404    
405        public void updateCoordinatorJobStatus(final CoordinatorJobBean job) throws StoreException {
406            ParamChecker.notNull(job, "CoordinatorJobBean");
407            doOperation("updateJobStatus", new Callable<Void>() {
408                public Void call() throws StoreException {
409                    Query q = entityManager.createNamedQuery("UPDATE_COORD_JOB_STATUS");
410                    q.setParameter("id", job.getId());
411                    q.setParameter("status", job.getStatus().toString());
412                    q.setParameter("lastModifiedTime", new Date());
413                    q.executeUpdate();
414                    return null;
415                }
416            });
417        }
418    
419        private <V> V doOperation(String name, Callable<V> command) throws StoreException {
420            try {
421                Instrumentation.Cron cron = new Instrumentation.Cron();
422                cron.start();
423                V retVal;
424                try {
425                    retVal = command.call();
426                }
427                finally {
428                    cron.stop();
429                }
430                Services.get().get(InstrumentationService.class).get().addCron(INSTR_GROUP, name, cron);
431                return retVal;
432            }
433            catch (StoreException ex) {
434                throw ex;
435            }
436            catch (SQLException ex) {
437                throw new StoreException(ErrorCode.E0603, name, ex.getMessage(), ex);
438            }
439            catch (Exception e) {
440                throw new StoreException(ErrorCode.E0607, name, e.getMessage(), e);
441            }
442        }
443    
444        private void setJobQueryParameters(CoordinatorJobBean jBean, Query q) {
445            q.setParameter("appName", jBean.getAppName());
446            q.setParameter("appPath", jBean.getAppPath());
447            q.setParameter("concurrency", jBean.getConcurrency());
448            q.setParameter("conf", jBean.getConf());
449            q.setParameter("externalId", jBean.getExternalId());
450            q.setParameter("frequency", jBean.getFrequency());
451            q.setParameter("lastActionNumber", jBean.getLastActionNumber());
452            q.setParameter("timeOut", jBean.getTimeout());
453            q.setParameter("timeZone", jBean.getTimeZone());
454            q.setParameter("authToken", jBean.getAuthToken());
455            q.setParameter("createdTime", jBean.getCreatedTimestamp());
456            q.setParameter("endTime", jBean.getEndTimestamp());
457            q.setParameter("execution", jBean.getExecution());
458            q.setParameter("jobXml", jBean.getJobXml());
459            q.setParameter("lastAction", jBean.getLastActionTimestamp());
460            q.setParameter("lastModifiedTime", new Date());
461            q.setParameter("nextMaterializedTime", jBean.getNextMaterializedTimestamp());
462            q.setParameter("origJobXml", jBean.getOrigJobXml());
463            q.setParameter("slaXml", jBean.getSlaXml());
464            q.setParameter("startTime", jBean.getStartTimestamp());
465            q.setParameter("status", jBean.getStatus().toString());
466            q.setParameter("timeUnit", jBean.getTimeUnitStr());
467        }
468    
469        private void setActionQueryParameters(CoordinatorActionBean aBean, Query q) {
470            q.setParameter("actionNumber", aBean.getActionNumber());
471            q.setParameter("actionXml", aBean.getActionXml());
472            q.setParameter("consoleUrl", aBean.getConsoleUrl());
473            q.setParameter("createdConf", aBean.getCreatedConf());
474            q.setParameter("errorCode", aBean.getErrorCode());
475            q.setParameter("errorMessage", aBean.getErrorMessage());
476            q.setParameter("externalStatus", aBean.getExternalStatus());
477            q.setParameter("missingDependencies", aBean.getMissingDependencies());
478            q.setParameter("runConf", aBean.getRunConf());
479            q.setParameter("timeOut", aBean.getTimeOut());
480            q.setParameter("trackerUri", aBean.getTrackerUri());
481            q.setParameter("type", aBean.getType());
482            q.setParameter("createdTime", aBean.getCreatedTimestamp());
483            q.setParameter("externalId", aBean.getExternalId());
484            q.setParameter("jobId", aBean.getJobId());
485            q.setParameter("lastModifiedTime", new Date());
486            q.setParameter("nominalTime", aBean.getNominalTimestamp());
487            q.setParameter("slaXml", aBean.getSlaXml());
488            q.setParameter("status", aBean.getStatus().toString());
489        }
490    
491        
492        /**
493         * Purge the coordinators completed older than given days.
494         *
495         * @param olderThanDays number of days for which to preserve the coordinators
496         * @param limit maximum number of coordinator jobs to be purged
497         * @throws StoreException
498         */
499        public void purge(final long olderThanDays, final int limit) throws StoreException {
500            doOperation("coord-purge", new Callable<Void>() {
501                public Void call() throws SQLException, StoreException, WorkflowException {
502                    Timestamp lastModTm = new Timestamp(System.currentTimeMillis() - (olderThanDays * DAY_IN_MS));
503                    Query jobQ = entityManager.createNamedQuery("GET_COMPLETED_COORD_JOBS_OLDER_THAN_STATUS");
504                    jobQ.setParameter("lastModTime", lastModTm);
505                    jobQ.setMaxResults(limit);
506                    List<CoordinatorJobBean> coordJobs = jobQ.getResultList();
507                    
508                    int actionDeleted = 0;
509                    if (coordJobs.size() != 0) {
510                        for (CoordinatorJobBean coord : coordJobs) {
511                            String jobId = coord.getId();
512                            entityManager.remove(coord);
513                            Query g = entityManager.createNamedQuery("DELETE_COMPLETED_ACTIONS_FOR_COORDINATOR");
514                            g.setParameter("jobId", jobId);
515                            actionDeleted += g.executeUpdate();
516                        }
517                    }
518                    
519                    XLog.getLog(getClass()).debug("ENDED Coord Purge deleted jobs :" + coordJobs.size() + " and actions " + actionDeleted);
520                    return null;
521                }
522            });
523        }
524    
525        public void commit() throws StoreException {
526        }
527    
528        public void close() throws StoreException {
529        }
530    
531        public CoordinatorJobBean getCoordinatorJobs(String id) {
532            // TODO Auto-generated method stub
533            return null;
534        }
535    
536        public CoordinatorJobInfo getCoordinatorInfo(final Map<String, List<String>> filter, final int start, final int len)
537                throws StoreException {
538    
539            CoordinatorJobInfo coordJobInfo = doOperation("getCoordinatorJobInfo", new Callable<CoordinatorJobInfo>() {
540                public CoordinatorJobInfo call() throws SQLException, StoreException {
541                    List<String> orArray = new ArrayList<String>();
542                    List<String> colArray = new ArrayList<String>();
543                    List<String> valArray = new ArrayList<String>();
544                    StringBuilder sb = new StringBuilder("");
545    
546                    StoreStatusFilter.filter(filter, orArray, colArray, valArray, sb, StoreStatusFilter.coordSeletStr,
547                                             StoreStatusFilter.coordCountStr);
548    
549                    int realLen = 0;
550    
551                    Query q = null;
552                    Query qTotal = null;
553                    if (orArray.size() == 0) {
554                        q = entityManager.createNamedQuery("GET_COORD_JOBS_COLUMNS");
555                        q.setFirstResult(start - 1);
556                        q.setMaxResults(len);
557                        qTotal = entityManager.createNamedQuery("GET_COORD_JOBS_COUNT");
558                    }
559                    else {
560                        StringBuilder sbTotal = new StringBuilder(sb);
561                        sb.append(" order by w.createdTimestamp desc ");
562                        XLog.getLog(getClass()).debug("Created String is **** " + sb.toString());
563                        q = entityManager.createQuery(sb.toString());
564                        q.setFirstResult(start - 1);
565                        q.setMaxResults(len);
566                        qTotal = entityManager.createQuery(sbTotal.toString().replace(StoreStatusFilter.coordSeletStr,
567                                                                                      StoreStatusFilter.coordCountStr));
568                    }
569    
570                    for (int i = 0; i < orArray.size(); i++) {
571                        q.setParameter(colArray.get(i), valArray.get(i));
572                        qTotal.setParameter(colArray.get(i), valArray.get(i));
573                    }
574    
575                    OpenJPAQuery kq = OpenJPAPersistence.cast(q);
576                    JDBCFetchPlan fetch = (JDBCFetchPlan) kq.getFetchPlan();
577                    fetch.setFetchBatchSize(20);
578                    fetch.setResultSetType(ResultSetType.SCROLL_INSENSITIVE);
579                    fetch.setFetchDirection(FetchDirection.FORWARD);
580                    fetch.setLRSSizeAlgorithm(LRSSizeAlgorithm.LAST);
581                    List<?> resultList = q.getResultList();
582                    List<Object[]> objectArrList = (List<Object[]>) resultList;
583                    List<CoordinatorJobBean> coordBeansList = new ArrayList<CoordinatorJobBean>();
584    
585                    for (Object[] arr : objectArrList) {
586                        CoordinatorJobBean ww = getBeanForCoordinatorJobFromArray(arr);
587                        coordBeansList.add(ww);
588                    }
589    
590                    realLen = ((Long) qTotal.getSingleResult()).intValue();
591    
592                    return new CoordinatorJobInfo(coordBeansList, start, len, realLen);
593                }
594            });
595            return coordJobInfo;
596        }
597    
598        private CoordinatorJobBean getBeanForCoordinatorJobFromArray(Object[] arr) {
599            CoordinatorJobBean bean = new CoordinatorJobBean();
600            bean.setId((String) arr[0]);
601            if (arr[1] != null) {
602                bean.setAppName((String) arr[1]);
603            }
604            if (arr[2] != null) {
605                bean.setStatus(Status.valueOf((String) arr[2]));
606            }
607            if (arr[3] != null) {
608                bean.setUser((String) arr[3]);
609            }
610            if (arr[4] != null) {
611                bean.setGroup((String) arr[4]);
612            }
613            if (arr[5] != null) {
614                bean.setStartTime((Timestamp) arr[5]);
615            }
616            if (arr[6] != null) {
617                bean.setEndTime((Timestamp) arr[6]);
618            }
619            if (arr[7] != null) {
620                bean.setAppPath((String) arr[7]);
621            }
622            if (arr[8] != null) {
623                bean.setConcurrency(((Integer) arr[8]).intValue());
624            }
625            if (arr[9] != null) {
626                bean.setFrequency(((Integer) arr[9]).intValue());
627            }
628            if (arr[10] != null) {
629                bean.setLastActionTime((Timestamp) arr[10]);
630            }
631            if (arr[11] != null) {
632                bean.setNextMaterializedTime((Timestamp) arr[11]);
633            }
634            if (arr[13] != null) {
635                bean.setTimeUnit(Timeunit.valueOf((String) arr[13]));
636            }
637            if (arr[14] != null) {
638                bean.setTimeZone((String) arr[14]);
639            }
640            if (arr[15] != null) {
641                bean.setTimeout((Integer) arr[15]);
642            }
643            return bean;
644        }
645    
646        /**
647         * Loads all actions for the given Coordinator job.
648         *
649         * @param jobId coordinator job id
650         * @param locking true if Actions are to be locked
651         * @return A List of CoordinatorActionBean
652         * @throws StoreException
653         */
654        public List<CoordinatorActionBean> getActionsForCoordinatorJob(final String jobId, final boolean locking)
655                throws StoreException {
656            ParamChecker.notEmpty(jobId, "CoordinatorJobID");
657            List<CoordinatorActionBean> actions = doOperation("getActionsForCoordinatorJob",
658                                                              new Callable<List<CoordinatorActionBean>>() {
659                                                                  @SuppressWarnings("unchecked")
660                                                                  public List<CoordinatorActionBean> call() throws StoreException {
661                                                                      List<CoordinatorActionBean> actions;
662                                                                      List<CoordinatorActionBean> actionList = new ArrayList<CoordinatorActionBean>();
663                                                                      try {
664                                                                          Query q = entityManager.createNamedQuery("GET_ACTIONS_FOR_COORD_JOB");
665                                                                          q.setParameter("jobId", jobId);
666                                                                          /*
667                                                                          * if (locking) { //
668                                                                          * q.setHint("openjpa.FetchPlan.ReadLockMode", //
669                                                                          * "READ"); OpenJPAQuery oq =
670                                                                          * OpenJPAPersistence.cast(q); JDBCFetchPlan fetch =
671                                                                          * (JDBCFetchPlan) oq.getFetchPlan();
672                                                                          * fetch.setReadLockMode(LockModeType.WRITE);
673                                                                          * fetch.setLockTimeout(-1); // 1 second }
674                                                                          */
675                                                                          actions = q.getResultList();
676                                                                          for (CoordinatorActionBean a : actions) {
677                                                                              CoordinatorActionBean aa = getBeanForRunningCoordAction(a);
678                                                                              actionList.add(aa);
679                                                                          }
680                                                                      }
681                                                                      catch (IllegalStateException e) {
682                                                                          throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
683                                                                      }
684                                                                      /*
685                                                                      * if (locking) { return actions; } else {
686                                                                      */
687                                                                      return actionList;
688                                                                      // }
689                                                                  }
690                                                              });
691            return actions;
692        }
693    
694        /**
695         * Loads given number of actions for the given Coordinator job.
696         *
697         * @param jobId coordinator job id
698         * @param start offset for select statement
699         * @param len number of Workflow Actions to be returned
700         * @return A List of CoordinatorActionBean
701         * @throws StoreException
702         */
703        public List<CoordinatorActionBean> getActionsSubsetForCoordinatorJob(final String jobId, final int start,
704                                                                             final int len) throws StoreException {
705            ParamChecker.notEmpty(jobId, "CoordinatorJobID");
706            List<CoordinatorActionBean> actions = doOperation("getActionsForCoordinatorJob",
707                                                              new Callable<List<CoordinatorActionBean>>() {
708                                                                  @SuppressWarnings("unchecked")
709                                                                  public List<CoordinatorActionBean> call() throws StoreException {
710                                                                      List<CoordinatorActionBean> actions;
711                                                                      List<CoordinatorActionBean> actionList = new ArrayList<CoordinatorActionBean>();
712                                                                      try {
713                                                                          Query q = entityManager.createNamedQuery("GET_ACTIONS_FOR_COORD_JOB");
714                                                                          q.setParameter("jobId", jobId);
715                                                                          q.setFirstResult(start - 1);
716                                                                          q.setMaxResults(len);
717                                                                          actions = q.getResultList();
718                                                                          for (CoordinatorActionBean a : actions) {
719                                                                              CoordinatorActionBean aa = getBeanForRunningCoordAction(a);
720                                                                              actionList.add(aa);
721                                                                          }
722                                                                      }
723                                                                      catch (IllegalStateException e) {
724                                                                          throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
725                                                                      }
726                                                                      return actionList;
727                                                                  }
728                                                              });
729            return actions;
730        }
731    
732        protected CoordinatorActionBean getBeanForRunningCoordAction(CoordinatorActionBean a) {
733            if (a != null) {
734                CoordinatorActionBean action = new CoordinatorActionBean();
735                action.setId(a.getId());
736                action.setActionNumber(a.getActionNumber());
737                action.setActionXml(a.getActionXml());
738                action.setConsoleUrl(a.getConsoleUrl());
739                action.setCreatedConf(a.getCreatedConf());
740                //action.setErrorCode(a.getErrorCode());
741                //action.setErrorMessage(a.getErrorMessage());
742                action.setExternalStatus(a.getExternalStatus());
743                action.setMissingDependencies(a.getMissingDependencies());
744                action.setRunConf(a.getRunConf());
745                action.setTimeOut(a.getTimeOut());
746                action.setTrackerUri(a.getTrackerUri());
747                action.setType(a.getType());
748                action.setCreatedTime(a.getCreatedTime());
749                action.setExternalId(a.getExternalId());
750                action.setJobId(a.getJobId());
751                action.setLastModifiedTime(a.getLastModifiedTime());
752                action.setNominalTime(a.getNominalTime());
753                action.setSlaXml(a.getSlaXml());
754                action.setStatus(a.getStatus());
755                return action;
756            }
757            return null;
758        }
759    
760        public CoordinatorActionBean getAction(String id, boolean b) {
761            return null;
762        }
763    
764        /*
765         * do not need this public void updateCoordinatorActionForExternalId(final
766         * CoordinatorActionBean action) throws StoreException { // TODO
767         * Auto-generated method stub ParamChecker.notNull(action,
768         * "updateCoordinatorActionForExternalId");
769         * doOperation("updateCoordinatorActionForExternalId", new Callable<Void>()
770         * { public Void call() throws SQLException, StoreException,
771         * WorkflowException { Query q =
772         * entityManager.createNamedQuery("UPDATE_COORD_ACTION_FOR_EXTERNALID");
773         * setActionQueryParameters(action,q); q.executeUpdate(); return null; } });
774         * }
775         */
776        public CoordinatorActionBean getCoordinatorActionForExternalId(final String externalId) throws StoreException {
777            // TODO Auto-generated method stub
778            ParamChecker.notEmpty(externalId, "coodinatorActionExternalId");
779            CoordinatorActionBean cBean = doOperation("getCoordinatorActionForExternalId",
780                                                      new Callable<CoordinatorActionBean>() {
781                                                          public CoordinatorActionBean call() throws StoreException {
782                                                              CoordinatorActionBean caBean = null;
783                                                              Query q = entityManager.createNamedQuery("GET_COORD_ACTION_FOR_EXTERNALID");
784                                                              q.setParameter("externalId", externalId);
785                                                              List<CoordinatorActionBean> actionList = q.getResultList();
786                                                              if (actionList.size() > 0) {
787                                                                  caBean = actionList.get(0);
788                                                              }
789                                                              return caBean;
790                                                          }
791                                                      });
792            return cBean;
793        }
794    
795        public List<CoordinatorActionBean> getRunningActionsForCoordinatorJob(final String jobId, final boolean locking)
796                throws StoreException {
797            ParamChecker.notEmpty(jobId, "CoordinatorJobID");
798            List<CoordinatorActionBean> actions = doOperation("getRunningActionsForCoordinatorJob",
799                                                              new Callable<List<CoordinatorActionBean>>() {
800                                                                  @SuppressWarnings("unchecked")
801                                                                  public List<CoordinatorActionBean> call() throws StoreException {
802                                                                      List<CoordinatorActionBean> actions;
803                                                                      try {
804                                                                          Query q = entityManager.createNamedQuery("GET_RUNNING_ACTIONS_FOR_COORD_JOB");
805                                                                          q.setParameter("jobId", jobId);
806                                                                          /*
807                                                                          * if (locking) {
808                                                                          * q.setHint("openjpa.FetchPlan.ReadLockMode",
809                                                                          * "READ"); OpenJPAQuery oq =
810                                                                          * OpenJPAPersistence.cast(q); FetchPlan fetch =
811                                                                          * oq.getFetchPlan();
812                                                                          * fetch.setReadLockMode(LockModeType.WRITE);
813                                                                          * fetch.setLockTimeout(-1); // no limit }
814                                                                          */
815                                                                          actions = q.getResultList();
816                                                                          return actions;
817                                                                      }
818                                                                      catch (IllegalStateException e) {
819                                                                          throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
820                                                                      }
821                                                                  }
822                                                              });
823            return actions;
824        }
825    
826        public List<CoordinatorActionBean> getRunningActionsOlderThan(final long checkAgeSecs, final boolean locking)
827                throws StoreException {
828            List<CoordinatorActionBean> actions = doOperation("getRunningActionsOlderThan",
829                                                              new Callable<List<CoordinatorActionBean>>() {
830                                                                  @SuppressWarnings("unchecked")
831                                                                  public List<CoordinatorActionBean> call() throws StoreException {
832                                                                      List<CoordinatorActionBean> actions;
833                                                                      Timestamp ts = new Timestamp(System.currentTimeMillis() - checkAgeSecs * 1000);
834                                                                      try {
835                                                                          Query q = entityManager.createNamedQuery("GET_RUNNING_ACTIONS_OLDER_THAN");
836                                                                          q.setParameter("lastModifiedTime", ts);
837                                                                          /*
838                                                                          * if (locking) { OpenJPAQuery oq =
839                                                                          * OpenJPAPersistence.cast(q); FetchPlan fetch =
840                                                                          * oq.getFetchPlan();
841                                                                          * fetch.setReadLockMode(LockModeType.WRITE);
842                                                                          * fetch.setLockTimeout(-1); // no limit }
843                                                                          */
844                                                                          actions = q.getResultList();
845                                                                          return actions;
846                                                                      }
847                                                                      catch (IllegalStateException e) {
848                                                                          throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
849                                                                      }
850                                                                  }
851                                                              });
852            return actions;
853        }
854    
855        public List<CoordinatorActionBean> getRecoveryActionsOlderThan(final long checkAgeSecs, final boolean locking)
856                throws StoreException {
857            List<CoordinatorActionBean> actions = doOperation("getRunningActionsOlderThan",
858                                                              new Callable<List<CoordinatorActionBean>>() {
859                                                                  @SuppressWarnings("unchecked")
860                                                                  public List<CoordinatorActionBean> call() throws StoreException {
861                                                                      List<CoordinatorActionBean> actions;
862                                                                      try {
863                                                                          Query q = entityManager.createNamedQuery("GET_WAITING_SUBMITTED_ACTIONS_OLDER_THAN");
864                                                                          Timestamp ts = new Timestamp(System.currentTimeMillis() - checkAgeSecs * 1000);
865                                                                          q.setParameter("lastModifiedTime", ts);
866                                                                          /*
867                                                                          * if (locking) { OpenJPAQuery oq =
868                                                                          * OpenJPAPersistence.cast(q); FetchPlan fetch =
869                                                                          * oq.getFetchPlan();
870                                                                          * fetch.setReadLockMode(LockModeType.WRITE);
871                                                                          * fetch.setLockTimeout(-1); // no limit }
872                                                                          */
873                                                                          actions = q.getResultList();
874                                                                          return actions;
875                                                                      }
876                                                                      catch (IllegalStateException e) {
877                                                                          throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
878                                                                      }
879                                                                  }
880                                                              });
881            return actions;
882        }
883    
884        /**
885         * Get coordinator action beans for given start date and end date
886         *
887         * @param startDate
888         * @param endDate
889         * @return list of coordinator action beans
890         * @throws StoreException
891         */
892        public List<CoordinatorActionBean> getCoordActionsForDates(final String jobId, final Date startDate,
893                final Date endDate)
894                throws StoreException {
895            List<CoordinatorActionBean> actions = doOperation("getCoordActionsForDates",
896                    new Callable<List<CoordinatorActionBean>>() {
897                        @SuppressWarnings("unchecked")
898                        public List<CoordinatorActionBean> call() throws StoreException {
899                            List<CoordinatorActionBean> actions;
900                            try {
901                                Query q = entityManager.createNamedQuery("GET_ACTIONS_FOR_DATES");
902                                q.setParameter("jobId", jobId);
903                                q.setParameter("startTime", new Timestamp(startDate.getTime()));
904                                q.setParameter("endTime", new Timestamp(endDate.getTime()));
905                                actions = q.getResultList();
906    
907                                List<CoordinatorActionBean> actionList = new ArrayList<CoordinatorActionBean>();
908                                for (CoordinatorActionBean a : actions) {
909                                    CoordinatorActionBean aa = getBeanForRunningCoordAction(a);
910                                    actionList.add(aa);
911                                }
912                                return actionList;
913                            }
914                            catch (IllegalStateException e) {
915                                throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
916                            }
917                        }
918                    });
919            return actions;
920        }
921    
922        /**
923         * Get coordinator action bean for given date
924         *
925         * @param nominalTime
926         * @return CoordinatorActionBean
927         * @throws StoreException
928         */
929        public CoordinatorActionBean getCoordActionForNominalTime(final String jobId, final Date nominalTime)
930                throws StoreException {
931            CoordinatorActionBean action = doOperation("getCoordActionForNominalTime",
932                    new Callable<CoordinatorActionBean>() {
933                @SuppressWarnings("unchecked")
934                public CoordinatorActionBean call() throws StoreException {
935                    List<CoordinatorActionBean> actions;
936                    Query q = entityManager.createNamedQuery("GET_ACTION_FOR_NOMINALTIME");
937                    q.setParameter("jobId", jobId);
938                    q.setParameter("nominalTime", new Timestamp(nominalTime.getTime()));
939                    actions = q.getResultList();
940    
941                    CoordinatorActionBean action = null;
942                    if (actions.size() > 0) {
943                        action = actions.get(0);
944                    }
945                    else {
946                        throw new StoreException(ErrorCode.E0605, DateUtils.convertDateToString(nominalTime));
947                    }
948                    return getBeanForRunningCoordAction(action);
949                }
950            });
951            return action;
952        }
953    
954        public List<String> getRecoveryActionsGroupByJobId(final long checkAgeSecs) throws StoreException {
955            List<String> jobids = doOperation("getRecoveryActionsGroupByJobId", new Callable<List<String>>() {
956                @SuppressWarnings("unchecked")
957                public List<String> call() throws StoreException {
958                    List<String> jobids = new ArrayList<String>();
959                    try {
960                        Query q = entityManager.createNamedQuery("GET_READY_ACTIONS_GROUP_BY_JOBID");
961                        Timestamp ts = new Timestamp(System.currentTimeMillis() - checkAgeSecs * 1000);
962                        q.setParameter(1, ts);
963                        List<Object[]> list = q.getResultList();
964    
965                        for (Object[] arr : list) {
966                            if (arr != null && arr[0] != null) {
967                                jobids.add((String) arr[0]);
968                            }
969                        }
970    
971                        return jobids;
972                    }
973                    catch (IllegalStateException e) {
974                        throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
975                    }
976                }
977            });
978            return jobids;
979        }
980        
981        public List<CoordinatorActionBean> getActionsOlderThan(final String jobId, final Date olderThan, final boolean locking)
982                 throws StoreException {
983             List<CoordinatorActionBean> actions = doOperation("getActionsOlderThan",
984                                                               new Callable<List<CoordinatorActionBean>>() {
985                                                                   @SuppressWarnings("unchecked")
986                                                                   public List<CoordinatorActionBean> call() throws StoreException {
987                                                                       List<CoordinatorActionBean> actions;
988                                                                       Timestamp ts = new Timestamp(olderThan.getTime());
989                                                                       try {
990                                                                           Query q = entityManager.createNamedQuery("GET_COORD_ACTIONS_FOR_JOB_OLDER_THAN");
991                                                                           q.setParameter("jobId", jobId);
992                                                                           q.setParameter("lastModifiedTime", ts);
993                                                                           actions = q.getResultList();
994                                                                           return actions;
995                                                                       }
996                                                                       catch (IllegalStateException e) {
997                                                                           throw new StoreException(ErrorCode.E0601, e.getMessage(), e);
998                                                                       }
999                                                                   }
1000                                                               });
1001             return actions;
1002         }
1003    
1004        public void deleteAction(final CoordinatorActionBean action) throws StoreException {
1005            doOperation("deleteAction",
1006                new Callable<Void>() {
1007                    @SuppressWarnings("unchecked")
1008                    public Void call() throws StoreException {
1009                        entityManager.remove(action);
1010                        return null;
1011                    }
1012                });
1013        }
1014    
1015    }