001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.command.bundle;
020
021import java.util.Date;
022import java.util.List;
023
024import org.apache.oozie.BundleActionBean;
025import org.apache.oozie.BundleJobBean;
026import org.apache.oozie.ErrorCode;
027import org.apache.oozie.client.Job;
028import org.apache.oozie.command.CommandException;
029import org.apache.oozie.command.PreconditionException;
030import org.apache.oozie.command.SuspendTransitionXCommand;
031import org.apache.oozie.command.coord.CoordSuspendXCommand;
032import org.apache.oozie.executor.jpa.BundleActionQueryExecutor.BundleActionQuery;
033import org.apache.oozie.executor.jpa.BatchQueryExecutor;
034import org.apache.oozie.executor.jpa.BundleActionQueryExecutor;
035import org.apache.oozie.executor.jpa.BundleJobQueryExecutor;
036import org.apache.oozie.executor.jpa.BundleJobQueryExecutor.BundleJobQuery;
037import org.apache.oozie.executor.jpa.JPAExecutorException;
038import org.apache.oozie.executor.jpa.BatchQueryExecutor.UpdateEntry;
039import org.apache.oozie.util.InstrumentUtils;
040import org.apache.oozie.util.ParamChecker;
041import org.apache.oozie.util.LogUtils;
042
043public class BundleJobSuspendXCommand extends SuspendTransitionXCommand {
044    private final String jobId;
045    private List<BundleActionBean> bundleActions;
046    private BundleJobBean bundleJob;
047
048    public BundleJobSuspendXCommand(String id) {
049        super("bundle_suspend", "bundle_suspend", 1);
050        this.jobId = ParamChecker.notEmpty(id, "id");
051    }
052
053    /* (non-Javadoc)
054     * @see org.apache.oozie.command.TransitionXCommand#getJob()
055     */
056    @Override
057    public Job getJob() {
058        return bundleJob;
059    }
060
061    /* (non-Javadoc)
062     * @see org.apache.oozie.command.TransitionXCommand#notifyParent()
063     */
064    @Override
065    public void notifyParent() throws CommandException {
066    }
067
068    /* (non-Javadoc)
069     * @see org.apache.oozie.command.TransitionXCommand#setJob(org.apache.oozie.client.Job)
070     */
071    @Override
072    public void setJob(Job job) {
073    }
074
075    /* (non-Javadoc)
076     * @see org.apache.oozie.command.SuspendTransitionXCommand#performWrites()
077     */
078    @Override
079    public void performWrites() throws CommandException {
080        try {
081            BatchQueryExecutor.getInstance().executeBatchInsertUpdateDelete(null, updateList, null);
082        }
083        catch (JPAExecutorException e) {
084            throw new CommandException(e);
085        }
086    }
087
088    /* (non-Javadoc)
089     * @see org.apache.oozie.command.XCommand#getEntityKey()
090     */
091    @Override
092    public String getEntityKey() {
093        return this.jobId;
094    }
095
096    /* (non-Javadoc)
097     * @see org.apache.oozie.command.XCommand#isLockRequired()
098     */
099    @Override
100    protected boolean isLockRequired() {
101        return true;
102    }
103
104    /* (non-Javadoc)
105     * @see org.apache.oozie.command.XCommand#loadState()
106     */
107    @Override
108    protected void loadState() throws CommandException {
109        try {
110            bundleJob = BundleJobQueryExecutor.getInstance().get(BundleJobQuery.GET_BUNDLE_JOB, jobId);
111        }
112        catch (Exception Ex) {
113            throw new CommandException(ErrorCode.E0604, jobId);
114        }
115
116        try {
117            bundleActions = BundleActionQueryExecutor.getInstance().getList(
118                    BundleActionQuery.GET_BUNDLE_ACTIONS_STATUS_UNIGNORED_FOR_BUNDLE, bundleJob.getId());
119        }
120        catch (Exception Ex) {
121            throw new CommandException(ErrorCode.E1311, jobId);
122        }
123
124        LogUtils.setLogInfo(bundleJob);
125    }
126
127    /* (non-Javadoc)
128     * @see org.apache.oozie.command.XCommand#verifyPrecondition()
129     */
130    @Override
131    protected void verifyPrecondition() throws CommandException, PreconditionException {
132        if (bundleJob.getStatus() == Job.Status.SUCCEEDED || bundleJob.getStatus() == Job.Status.FAILED
133                || bundleJob.getStatus() == Job.Status.KILLED || bundleJob.getStatus() == Job.Status.DONEWITHERROR) {
134            LOG.info("BundleJobSuspendXCommand is not going to execute because job either succeeded, failed, killed,"
135                    + " or donewitherror; id = "
136                            + jobId + ", status = " + bundleJob.getStatus());
137            throw new PreconditionException(ErrorCode.E1312, jobId, bundleJob.getStatus().toString());
138        }
139    }
140
141    /* (non-Javadoc)
142     * @see org.apache.oozie.command.TransitionXCommand#updateJob()
143     */
144    @Override
145    public void updateJob() {
146        InstrumentUtils.incrJobCounter("bundle_suspend", 1, null);
147        bundleJob.setSuspendedTime(new Date());
148        bundleJob.setLastModifiedTime(new Date());
149
150        LOG.debug("Suspend bundle job id = " + jobId + ", status = " + bundleJob.getStatus() + ", pending = "
151        + bundleJob.isPending());
152        updateList.add(new UpdateEntry<BundleJobQuery>(BundleJobQuery.UPDATE_BUNDLE_JOB_STATUS_PENDING_SUSP_MOD_TIME, bundleJob));
153    }
154
155    @Override
156    public void suspendChildren() throws CommandException {
157        for (BundleActionBean action : this.bundleActions) {
158            if (action.getStatus() == Job.Status.RUNNING || action.getStatus() == Job.Status.RUNNINGWITHERROR
159                    || action.getStatus() == Job.Status.PREP || action.getStatus() == Job.Status.PAUSED
160                    || action.getStatus() == Job.Status.PAUSEDWITHERROR) {
161                // queue a CoordSuspendXCommand
162                if (action.getCoordId() != null) {
163                    queue(new CoordSuspendXCommand(action.getCoordId()));
164                    updateBundleAction(action);
165                    LOG.debug("Suspend bundle action = [{0}], new status = [{1}], pending = [{2}] and queue CoordSuspendXCommand"
166                            + " for [{3}]",
167                            action.getBundleActionId(), action.getStatus(), action.getPending(), action.getCoordId());
168                } else {
169                    updateBundleAction(action);
170                    LOG.debug("Suspend bundle action = [{0}], new status = [{1}], pending = [{2}] and coord id is null",
171                            action.getBundleActionId(), action.getStatus(), action.getPending());
172                }
173
174            }
175        }
176        LOG.debug("Suspended bundle actions for the bundle=[{0}]", jobId);
177    }
178
179    private void updateBundleAction(BundleActionBean action) {
180        if (action.getStatus() == Job.Status.PREP) {
181            action.setStatus(Job.Status.PREPSUSPENDED);
182        }
183        else if (action.getStatus() == Job.Status.RUNNING) {
184            action.setStatus(Job.Status.SUSPENDED);
185        }
186        else if (action.getStatus() == Job.Status.RUNNINGWITHERROR) {
187            action.setStatus(Job.Status.SUSPENDEDWITHERROR);
188        }
189        else if (action.getStatus() == Job.Status.PAUSED) {
190            action.setStatus(Job.Status.SUSPENDED);
191        }
192        else if (action.getStatus() == Job.Status.PAUSEDWITHERROR) {
193            action.setStatus(Job.Status.SUSPENDEDWITHERROR);
194        }
195
196        action.incrementAndGetPending();
197        action.setLastModifiedTime(new Date());
198        updateList.add(new UpdateEntry<BundleActionQuery>(
199                BundleActionQuery.UPDATE_BUNDLE_ACTION_STATUS_PENDING_MODTIME, action));
200    }
201}