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.bundle;
016    
017    import java.util.Date;
018    import java.util.List;
019    
020    import org.apache.oozie.BundleActionBean;
021    import org.apache.oozie.BundleJobBean;
022    import org.apache.oozie.ErrorCode;
023    import org.apache.oozie.XException;
024    import org.apache.oozie.client.Job;
025    import org.apache.oozie.command.CommandException;
026    import org.apache.oozie.command.PreconditionException;
027    import org.apache.oozie.command.SuspendTransitionXCommand;
028    import org.apache.oozie.command.coord.CoordSuspendXCommand;
029    import org.apache.oozie.executor.jpa.BundleActionUpdateJPAExecutor;
030    import org.apache.oozie.executor.jpa.BundleActionsGetJPAExecutor;
031    import org.apache.oozie.executor.jpa.BundleJobGetJPAExecutor;
032    import org.apache.oozie.executor.jpa.BundleJobUpdateJPAExecutor;
033    import org.apache.oozie.executor.jpa.JPAExecutorException;
034    import org.apache.oozie.service.JPAService;
035    import org.apache.oozie.service.Services;
036    import org.apache.oozie.util.InstrumentUtils;
037    import org.apache.oozie.util.ParamChecker;
038    import org.apache.oozie.util.LogUtils;
039    
040    public class BundleJobSuspendXCommand extends SuspendTransitionXCommand {
041        private final String jobId;
042        private JPAService jpaService;
043        private List<BundleActionBean> bundleActions;
044        private BundleJobBean bundleJob;
045    
046        public BundleJobSuspendXCommand(String id) {
047            super("bundle_suspend", "bundle_suspend", 1);
048            this.jobId = ParamChecker.notEmpty(id, "id");
049        }
050    
051        /* (non-Javadoc)
052         * @see org.apache.oozie.command.TransitionXCommand#getJob()
053         */
054        @Override
055        public Job getJob() {
056            return bundleJob;
057        }
058    
059        /* (non-Javadoc)
060         * @see org.apache.oozie.command.TransitionXCommand#notifyParent()
061         */
062        @Override
063        public void notifyParent() throws CommandException {
064        }
065    
066        /* (non-Javadoc)
067         * @see org.apache.oozie.command.TransitionXCommand#setJob(org.apache.oozie.client.Job)
068         */
069        @Override
070        public void setJob(Job job) {
071        }
072    
073        /* (non-Javadoc)
074         * @see org.apache.oozie.command.XCommand#getEntityKey()
075         */
076        @Override
077        protected String getEntityKey() {
078            return this.jobId;
079        }
080    
081        /* (non-Javadoc)
082         * @see org.apache.oozie.command.XCommand#isLockRequired()
083         */
084        @Override
085        protected boolean isLockRequired() {
086            return true;
087        }
088    
089        /* (non-Javadoc)
090         * @see org.apache.oozie.command.XCommand#loadState()
091         */
092        @Override
093        protected void loadState() throws CommandException {
094            jpaService = Services.get().get(JPAService.class);
095            if (jpaService == null) {
096                throw new CommandException(ErrorCode.E0610);
097            }
098    
099            try {
100                bundleJob = jpaService.execute(new BundleJobGetJPAExecutor(jobId));
101            }
102            catch (Exception Ex) {
103                throw new CommandException(ErrorCode.E0604, jobId);
104            }
105    
106            try {
107                bundleActions = jpaService.execute(new BundleActionsGetJPAExecutor(jobId));
108            }
109            catch (Exception Ex) {
110                throw new CommandException(ErrorCode.E1311, jobId);
111            }
112    
113            LogUtils.setLogInfo(bundleJob, logInfo);
114        }
115    
116        /* (non-Javadoc)
117         * @see org.apache.oozie.command.XCommand#verifyPrecondition()
118         */
119        @Override
120        protected void verifyPrecondition() throws CommandException, PreconditionException {
121            if (bundleJob.getStatus() == Job.Status.SUCCEEDED || bundleJob.getStatus() == Job.Status.FAILED
122                    || bundleJob.getStatus() == Job.Status.KILLED) {
123                LOG.info("BundleJobSuspendXCommand is not going to execute because job finished or failed or killed, id = "
124                                + jobId + ", status = " + bundleJob.getStatus());
125                throw new PreconditionException(ErrorCode.E1312, jobId, bundleJob.getStatus().toString());
126            }
127        }
128    
129        /* (non-Javadoc)
130         * @see org.apache.oozie.command.TransitionXCommand#updateJob()
131         */
132        @Override
133        public void updateJob() throws CommandException {
134            InstrumentUtils.incrJobCounter("bundle_suspend", 1, null);
135            bundleJob.setSuspendedTime(new Date());
136            bundleJob.setLastModifiedTime(new Date());
137    
138            LOG.debug("Suspend bundle job id = " + jobId + ", status = " + bundleJob.getStatus() + ", pending = " + bundleJob.isPending());
139            try {
140                jpaService.execute(new BundleJobUpdateJPAExecutor(bundleJob));
141            }
142            catch (JPAExecutorException e) {
143                throw new CommandException(e);
144            }
145        }
146    
147        @Override
148        public void suspendChildren() throws CommandException {
149            try {
150                for (BundleActionBean action : this.bundleActions) {
151                    if (action.getStatus() == Job.Status.RUNNING || action.getStatus() == Job.Status.PREP) {
152                        // queue a CoordSuspendXCommand
153                        if (action.getCoordId() != null) {
154                            queue(new CoordSuspendXCommand(action.getCoordId()));
155                            updateBundleAction(action);
156                            LOG.debug("Suspend bundle action = [{0}], new status = [{1}], pending = [{2}] and queue CoordSuspendXCommand for [{3}]",
157                                    action.getBundleActionId(), action.getStatus(), action.getPending(), action.getCoordId());
158                        } else {
159                            updateBundleAction(action);
160                            LOG.debug("Suspend bundle action = [{0}], new status = [{1}], pending = [{2}] and coord id is null",
161                                    action.getBundleActionId(), action.getStatus(), action.getPending());
162                        }
163    
164                    }
165                }
166                LOG.debug("Suspended bundle actions for the bundle=[{0}]", jobId);
167            }
168            catch (XException ex) {
169                throw new CommandException(ex);
170            }
171        }
172    
173        private void updateBundleAction(BundleActionBean action) throws CommandException {
174            if (action.getStatus() == Job.Status.PREP) {
175                action.setStatus(Job.Status.PREPSUSPENDED);
176            }
177            else if (action.getStatus() == Job.Status.RUNNING) {
178                action.setStatus(Job.Status.SUSPENDED);
179            }
180            action.incrementAndGetPending();
181            action.setLastModifiedTime(new Date());
182            try {
183                jpaService.execute(new BundleActionUpdateJPAExecutor(action));
184            }
185            catch (JPAExecutorException e) {
186                throw new CommandException(e);
187            }
188        }
189    }