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.command.coord;
016    
017    import java.util.Date;
018    import java.util.List;
019    
020    import org.apache.oozie.CoordinatorActionBean;
021    import org.apache.oozie.CoordinatorJobBean;
022    import org.apache.oozie.ErrorCode;
023    import org.apache.oozie.XException;
024    import org.apache.oozie.client.CoordinatorJob;
025    import org.apache.oozie.client.Job;
026    import org.apache.oozie.command.CommandException;
027    import org.apache.oozie.command.PreconditionException;
028    import org.apache.oozie.command.ResumeTransitionXCommand;
029    import org.apache.oozie.command.bundle.BundleStatusUpdateXCommand;
030    import org.apache.oozie.command.wf.ResumeXCommand;
031    import org.apache.oozie.executor.jpa.CoordActionUpdateJPAExecutor;
032    import org.apache.oozie.executor.jpa.CoordJobGetActionsJPAExecutor;
033    import org.apache.oozie.executor.jpa.CoordJobGetJPAExecutor;
034    import org.apache.oozie.executor.jpa.CoordJobUpdateJPAExecutor;
035    import org.apache.oozie.executor.jpa.JPAExecutorException;
036    import org.apache.oozie.service.JPAService;
037    import org.apache.oozie.service.Services;
038    import org.apache.oozie.util.InstrumentUtils;
039    import org.apache.oozie.util.LogUtils;
040    import org.apache.oozie.util.ParamChecker;
041    
042    /**
043     * Resume coordinator job and actions.
044     *
045     */
046    public class CoordResumeXCommand extends ResumeTransitionXCommand {
047        private final String jobId;
048        private CoordinatorJobBean coordJob = null;
049        private JPAService jpaService = null;
050        private boolean exceptionOccured = false;
051        CoordinatorJob.Status prevStatus;
052    
053        public CoordResumeXCommand(String id) {
054            super("coord_resume", "coord_resume", 1);
055            this.jobId = ParamChecker.notEmpty(id, "id");
056        }
057    
058        /* (non-Javadoc)
059         * @see org.apache.oozie.command.XCommand#getEntityKey()
060         */
061        @Override
062        protected String getEntityKey() {
063            return jobId;
064        }
065    
066        /* (non-Javadoc)
067         * @see org.apache.oozie.command.XCommand#isLockRequired()
068         */
069        @Override
070        protected boolean isLockRequired() {
071            return true;
072        }
073    
074        /* (non-Javadoc)
075         * @see org.apache.oozie.command.XCommand#loadState()
076         */
077        @Override
078        protected void loadState() throws CommandException {
079            jpaService = Services.get().get(JPAService.class);
080            if (jpaService == null) {
081                throw new CommandException(ErrorCode.E0610);
082            }
083            try {
084                coordJob = jpaService.execute(new CoordJobGetJPAExecutor(jobId));
085            }
086            catch (JPAExecutorException e) {
087                throw new CommandException(e);
088            }
089            setJob(coordJob);
090            prevStatus = coordJob.getStatus();
091            LogUtils.setLogInfo(coordJob, logInfo);
092        }
093    
094        /* (non-Javadoc)
095         * @see org.apache.oozie.command.XCommand#verifyPrecondition()
096         */
097        @Override
098        protected void verifyPrecondition() throws CommandException, PreconditionException {
099            if (coordJob.getStatus() != CoordinatorJob.Status.SUSPENDED && coordJob.getStatus() != Job.Status.PREPSUSPENDED) {
100                throw new PreconditionException(ErrorCode.E1100, "CoordResumeXCommand not Resumed - "
101                        + "job not in SUSPENDED/PREPSUSPENDED state, job = " + jobId);
102            }
103        }
104    
105        /* (non-Javadoc)
106         * @see org.apache.oozie.command.TransitionXCommand#updateJob()
107         */
108        @Override
109        public void updateJob() throws CommandException {
110            InstrumentUtils.incrJobCounter(getName(), 1, getInstrumentation());
111            coordJob.setSuspendedTime(null);
112            coordJob.setLastModifiedTime(new Date());
113            LOG.debug("Resume coordinator job id = " + jobId + ", status = " + coordJob.getStatus() + ", pending = " + coordJob.isPending());
114            try {
115                jpaService.execute(new CoordJobUpdateJPAExecutor(coordJob));
116            }
117            catch (JPAExecutorException e) {
118                throw new CommandException(e);
119            }
120        }
121    
122        /* (non-Javadoc)
123         * @see org.apache.oozie.command.ResumeTransitionXCommand#resumeChildren()
124         */
125        @Override
126        public void resumeChildren() throws CommandException {
127            try {
128                List<CoordinatorActionBean> actionList = jpaService.execute(new CoordJobGetActionsJPAExecutor(jobId));
129    
130                for (CoordinatorActionBean action : actionList) {
131                    if(action.getStatus() == CoordinatorActionBean.Status.SUSPENDED){
132                        // queue a ResumeXCommand
133                        if (action.getExternalId() != null) {
134                            queue(new ResumeXCommand(action.getExternalId()));
135                            updateCoordAction(action);
136                            LOG.debug("Resume coord action = [{0}], new status = [{1}], pending = [{2}] and queue ResumeXCommand for [{3}]",
137                                    action.getId(), action.getStatus(), action.getPending(), action.getExternalId());
138                        }else {
139                            updateCoordAction(action);
140                            LOG.debug("Resume coord action = [{0}], new status = [{1}], pending = [{2}] and external id is null",
141                                    action.getId(), action.getStatus(), action.getPending());
142                        }
143                    }
144                }
145            }
146            catch (XException ex) {
147                exceptionOccured = true;
148                throw new CommandException(ex);
149            }
150            finally {
151                if (exceptionOccured) {
152                    coordJob.setStatus(CoordinatorJob.Status.FAILED);
153                    coordJob.resetPending();
154                    LOG.warn("Resume children failed so fail coordinator, coordinator job id = " + jobId
155                            + ", status = " + coordJob.getStatus());
156                    try {
157                        jpaService.execute(new CoordJobUpdateJPAExecutor(coordJob));
158                    }
159                    catch (JPAExecutorException je) {
160                        LOG.error("Failed to update coordinator job : " + jobId, je);
161                    }
162                }
163            }
164        }
165    
166        /* (non-Javadoc)
167         * @see org.apache.oozie.command.TransitionXCommand#notifyParent()
168         */
169        @Override
170        public void notifyParent() throws CommandException {
171            // update bundle action
172            if (this.coordJob.getBundleId() != null) {
173                BundleStatusUpdateXCommand bundleStatusUpdate = new BundleStatusUpdateXCommand(coordJob, prevStatus);
174                bundleStatusUpdate.call();
175            }
176        }
177    
178        private void updateCoordAction(CoordinatorActionBean action) throws CommandException {
179            action.setStatus(CoordinatorActionBean.Status.RUNNING);
180            action.incrementAndGetPending();
181            action.setLastModifiedTime(new Date());
182            try {
183                jpaService.execute(new CoordActionUpdateJPAExecutor(action));
184            }
185            catch (JPAExecutorException e) {
186                throw new CommandException(e);
187            }
188        }
189    
190        /* (non-Javadoc)
191         * @see org.apache.oozie.command.TransitionXCommand#getJob()
192         */
193        @Override
194        public Job getJob() {
195            return coordJob;
196        }
197    }