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.wf;
016    
017    import java.util.List;
018    
019    import org.apache.oozie.WorkflowActionBean;
020    import org.apache.oozie.WorkflowJobBean;
021    import org.apache.oozie.client.WorkflowJob;
022    import org.apache.oozie.command.CommandException;
023    import org.apache.oozie.store.StoreException;
024    import org.apache.oozie.store.WorkflowStore;
025    import org.apache.oozie.util.ParamChecker;
026    import org.apache.oozie.util.XLog;
027    import org.apache.oozie.workflow.WorkflowException;
028    import org.apache.oozie.workflow.WorkflowInstance;
029    import org.apache.oozie.workflow.lite.LiteWorkflowInstance;
030    
031    public class SuspendCommand extends WorkflowCommand<Void> {
032    
033        private String id;
034    
035        public SuspendCommand(String id) {
036            super("suspend", "suspend", 1, XLog.STD);
037            this.id = ParamChecker.notEmpty(id, "id");
038        }
039    
040        @Override
041        protected Void call(WorkflowStore store) throws StoreException, CommandException {
042            try {
043                WorkflowJobBean workflow = store.getWorkflow(id, false);
044                setLogInfo(workflow);
045                if (workflow.getStatus() == WorkflowJob.Status.RUNNING) {
046                    incrJobCounter(1);
047                    suspendJob(store, workflow, id, null);
048                    store.updateWorkflow(workflow);
049                    queueCallable(new NotificationCommand(workflow));
050                }
051                return null;
052            }
053            catch (WorkflowException ex) {
054                throw new CommandException(ex);
055            }
056        }
057    
058        /**
059         * Suspend the workflow job and pending flag to false for the actions that
060         * are START_RETRY or START_MANUAL or END_RETRY or END_MANUAL
061         *
062         * @param store WorkflowStore
063         * @param workflow WorkflowJobBean
064         * @param id String
065         * @param actionId String
066         * @throws WorkflowException
067         * @throws StoreException
068         */
069        public static void suspendJob(WorkflowStore store, WorkflowJobBean workflow, String id, String actionId)
070                throws WorkflowException, StoreException {
071            if (workflow.getStatus() == WorkflowJob.Status.RUNNING) {
072                workflow.getWorkflowInstance().suspend();
073                WorkflowInstance wfInstance = workflow.getWorkflowInstance();
074                ((LiteWorkflowInstance) wfInstance).setStatus(WorkflowInstance.Status.SUSPENDED);
075                workflow.setStatus(WorkflowJob.Status.SUSPENDED);
076                workflow.setWorkflowInstance(wfInstance);
077    
078                setPendingFalseForActions(store, id, actionId);
079            }
080        }
081    
082        /**
083         * Set pending flag to false for the actions that are START_RETRY or
084         * START_MANUAL or END_RETRY or END_MANUAL
085         * <p/>
086         *
087         * @param store WorkflowStore
088         * @param id workflow id
089         * @param actionId workflow action id
090         * @throws StoreException
091         */
092        public static void setPendingFalseForActions(WorkflowStore store, String id, String actionId) throws StoreException {
093            List<WorkflowActionBean> actions = store.getRetryAndManualActions(id);
094            for (WorkflowActionBean action : actions) {
095                if (actionId != null && actionId.equals(action.getId())) {
096                    // this action has been changed in handleNonTransient()
097                    continue;
098                }
099                else {
100                    action.resetPendingOnly();
101                }
102                store.updateAction(action);
103            }
104        }
105    
106        @Override
107        protected Void execute(WorkflowStore store) throws CommandException, StoreException {
108            XLog.getLog(getClass()).debug("STARTED SuspendCommand for wf id=" + id);
109            try {
110                if (lock(id)) {
111                    call(store);
112                }
113                else {
114                    queueCallable(new SuspendCommand(id), LOCK_FAILURE_REQUEUE_INTERVAL);
115                    XLog.getLog(getClass()).warn("Suspend lock was not acquired - failed {0}", id);
116                }
117            }
118            catch (InterruptedException e) {
119                queueCallable(new SuspendCommand(id), LOCK_FAILURE_REQUEUE_INTERVAL);
120                XLog.getLog(getClass()).warn("SuspendCommand lock was not acquired - interrupted exception failed {0}", id);
121            }
122            finally {
123                XLog.getLog(getClass()).debug("ENDED SuspendCommand for wf id=" + id);
124            }
125            return null;
126        }
127    }