001    package org.apache.oozie.command.bundle;
002    
003    import java.util.Date;
004    import java.util.HashMap;
005    import java.util.List;
006    import java.util.Map;
007    
008    import org.apache.oozie.BundleActionBean;
009    import org.apache.oozie.BundleJobBean;
010    import org.apache.oozie.CoordinatorJobBean;
011    import org.apache.oozie.ErrorCode;
012    import org.apache.oozie.XException;
013    import org.apache.oozie.client.Job;
014    import org.apache.oozie.client.rest.RestConstants;
015    import org.apache.oozie.command.CommandException;
016    import org.apache.oozie.command.RerunTransitionXCommand;
017    import org.apache.oozie.command.coord.CoordRerunXCommand;
018    import org.apache.oozie.executor.jpa.BundleActionUpdateJPAExecutor;
019    import org.apache.oozie.executor.jpa.BundleActionsGetJPAExecutor;
020    import org.apache.oozie.executor.jpa.BundleJobGetJPAExecutor;
021    import org.apache.oozie.executor.jpa.BundleJobUpdateJPAExecutor;
022    import org.apache.oozie.executor.jpa.CoordJobGetJPAExecutor;
023    import org.apache.oozie.executor.jpa.JPAExecutorException;
024    import org.apache.oozie.service.JPAService;
025    import org.apache.oozie.service.Services;
026    import org.apache.oozie.util.DateUtils;
027    import org.apache.oozie.util.LogUtils;
028    import org.apache.oozie.util.ParamChecker;
029    import org.apache.oozie.util.XLog;
030    
031    /**
032     * Rerun bundle coordinator jobs by a list of coordinator names or dates. User can specify if refresh or noCleanup.
033     * <p/>
034     * The "refresh" is used to indicate if user wants to refresh an action's input/outpur dataset urls
035     * <p/>
036     * The "noCleanup" is used to indicate if user wants to cleanup output events for given rerun actions
037     */
038    public class BundleRerunXCommand extends RerunTransitionXCommand<Void> {
039    
040        private final String coordScope;
041        private final String dateScope;
042        private final boolean refresh;
043        private final boolean noCleanup;
044        private BundleJobBean bundleJob;
045        private List<BundleActionBean> bundleActions;
046        protected boolean prevPending;
047    
048        private JPAService jpaService = null;
049    
050        /**
051         * The constructor for class {@link BundleRerunXCommand}
052         *
053         * @param jobId the bundle job id
054         * @param coordScope the rerun scope for coordinator job names separated by ","
055         * @param dateScope the rerun scope for coordinator nominal times separated by ","
056         * @param refresh true if user wants to refresh input/outpur dataset urls
057         * @param noCleanup false if user wants to cleanup output events for given rerun actions
058         */
059        public BundleRerunXCommand(String jobId, String coordScope, String dateScope, boolean refresh, boolean noCleanup) {
060            super("bundle_rerun", "bundle_rerun", 1);
061            this.jobId = ParamChecker.notEmpty(jobId, "jobId");
062            this.coordScope = coordScope;
063            this.dateScope = dateScope;
064            this.refresh = refresh;
065            this.noCleanup = noCleanup;
066        }
067    
068        /* (non-Javadoc)
069         * @see org.apache.oozie.command.XCommand#loadState()
070         */
071        @Override
072        protected void loadState() throws CommandException {
073            try {
074                jpaService = Services.get().get(JPAService.class);
075    
076                if (jpaService != null) {
077                    this.bundleJob = jpaService.execute(new BundleJobGetJPAExecutor(jobId));
078                    this.bundleActions = jpaService.execute(new BundleActionsGetJPAExecutor(jobId));
079                    LogUtils.setLogInfo(bundleJob, logInfo);
080                    super.setJob(bundleJob);
081                    prevPending = bundleJob.isPending();
082                }
083                else {
084                    throw new CommandException(ErrorCode.E0610);
085                }
086            }
087            catch (XException ex) {
088                throw new CommandException(ex);
089            }
090    
091        }
092    
093        /* (non-Javadoc)
094         * @see org.apache.oozie.command.RerunTransitionXCommand#rerunChildren()
095         */
096        @Override
097        public void rerunChildren() throws CommandException {
098            boolean isUpdateActionDone = false;
099            Map<String, BundleActionBean> coordNameToBAMapping = new HashMap<String, BundleActionBean>();
100            if (bundleActions != null) {
101                for (BundleActionBean action : bundleActions) {
102                    if (action.getCoordName() != null) {
103                        coordNameToBAMapping.put(action.getCoordName(), action);
104                    }
105                }
106            }
107    
108            if (coordScope != null && !coordScope.isEmpty()) {
109                String[] list = coordScope.split(",");
110                for (String coordName : list) {
111                    coordName = coordName.trim();
112                    if (coordNameToBAMapping.keySet().contains(coordName)) {
113                        String coordId = coordNameToBAMapping.get(coordName).getCoordId();
114                        if (coordId == null) {
115                            LOG.info("No coord id found. Therefore, nothing to queue for coord rerun for coordname: " + coordName);
116                            continue;
117                        }
118                        CoordinatorJobBean coordJob = getCoordJob(coordId);
119    
120                        String rerunDateScope;
121                        if (dateScope != null && !dateScope.isEmpty()) {
122                            rerunDateScope = dateScope;
123                        }
124                        else {
125                            String coordStart = DateUtils.convertDateToString(coordJob.getStartTime());
126                            String coordEnd = DateUtils.convertDateToString(coordJob.getEndTime());
127                            rerunDateScope = coordStart + "::" + coordEnd;
128                        }
129                        LOG.debug("Queuing rerun range [" + rerunDateScope + "] for coord id " + coordId + " of bundle "
130                                + bundleJob.getId());
131                        queue(new CoordRerunXCommand(coordId, RestConstants.JOB_COORD_RERUN_DATE, rerunDateScope, refresh,
132                                noCleanup));
133                        updateBundleAction(coordNameToBAMapping.get(coordName));
134                        isUpdateActionDone = true;
135                    }
136                    else {
137                        LOG.info("Rerun for coord " + coordName + " NOT performed because it is not in bundle ", bundleJob.getId());
138                    }
139                }
140            }
141            else if (dateScope != null && !dateScope.isEmpty()) {
142                if (bundleActions != null) {
143                    for (BundleActionBean action : bundleActions) {
144                        if (action.getCoordId() == null) {
145                            LOG.info("No coord id found. Therefore nothing to queue for coord rerun with coord name "
146                                    + action.getCoordName());
147                            continue;
148                        }
149                        LOG.debug("Queuing rerun range [" + dateScope + "] for coord id " + action.getCoordId() + " of bundle "
150                                + bundleJob.getId());
151                        queue(new CoordRerunXCommand(action.getCoordId(), RestConstants.JOB_COORD_RERUN_DATE, dateScope,
152                                refresh, noCleanup));
153                        updateBundleAction(action);
154                        isUpdateActionDone = true;
155                    }
156                }
157            }
158            if (!isUpdateActionDone) {
159                transitToPrevious();
160            }
161            LOG.info("Rerun coord jobs for the bundle=[{0}]", jobId);
162        }
163    
164        private final void transitToPrevious() throws CommandException {
165            bundleJob.setStatus(getPrevStatus());
166            if (!prevPending) {
167                bundleJob.resetPending();
168            }
169            else {
170                bundleJob.setPending();
171            }
172            updateJob();
173        }
174    
175        /**
176         * Update bundle action
177         *
178         * @param action the bundle action
179         * @throws CommandException thrown if failed to update bundle action
180         */
181        private void updateBundleAction(BundleActionBean action) throws CommandException {
182            action.incrementAndGetPending();
183            action.setLastModifiedTime(new Date());
184            try {
185                jpaService.execute(new BundleActionUpdateJPAExecutor(action));
186            }
187            catch (JPAExecutorException je) {
188                throw new CommandException(je);
189            }
190        }
191    
192        /* (non-Javadoc)
193         * @see org.apache.oozie.command.TransitionXCommand#updateJob()
194         */
195        @Override
196        public void updateJob() throws CommandException {
197            try {
198                // rerun a paused bundle job will keep job status at paused and pending at previous pending
199                if (getPrevStatus()!= null && getPrevStatus().equals(Job.Status.PAUSED)) {
200                    bundleJob.setStatus(Job.Status.PAUSED);
201                    if (prevPending) {
202                        bundleJob.setPending();
203                    } else {
204                        bundleJob.resetPending();
205                    }
206                }
207                jpaService.execute(new BundleJobUpdateJPAExecutor(bundleJob));
208            }
209            catch (JPAExecutorException je) {
210                throw new CommandException(je);
211            }
212    
213        }
214    
215        /* (non-Javadoc)
216         * @see org.apache.oozie.command.XCommand#getEntityKey()
217         */
218        @Override
219        protected String getEntityKey() {
220            return jobId;
221        }
222    
223        /* (non-Javadoc)
224         * @see org.apache.oozie.command.XCommand#isLockRequired()
225         */
226        @Override
227        protected boolean isLockRequired() {
228            return true;
229        }
230    
231        /*
232         * (non-Javadoc)
233         * @see org.apache.oozie.command.TransitionXCommand#getJob()
234         */
235        @Override
236        public Job getJob() {
237            return bundleJob;
238        }
239    
240        /* (non-Javadoc)
241         * @see org.apache.oozie.command.TransitionXCommand#notifyParent()
242         */
243        @Override
244        public void notifyParent() throws CommandException {
245    
246        }
247    
248        /* (non-Javadoc)
249         * @see org.apache.oozie.command.RerunTransitionXCommand#getLog()
250         */
251        @Override
252        public XLog getLog() {
253            return LOG;
254        }
255    
256        private final CoordinatorJobBean getCoordJob(String coordId) throws CommandException {
257            try {
258                CoordinatorJobBean job = jpaService.execute(new CoordJobGetJPAExecutor(coordId));
259                return job;
260            }
261            catch (JPAExecutorException je) {
262                throw new CommandException(je);
263            }
264    
265        }
266    
267    }