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.ErrorCode;
020    import org.apache.oozie.WorkflowActionBean;
021    import org.apache.oozie.WorkflowJobBean;
022    import org.apache.oozie.client.WorkflowJob;
023    import org.apache.oozie.command.CommandException;
024    import org.apache.oozie.command.PreconditionException;
025    import org.apache.oozie.command.coord.CoordActionUpdateXCommand;
026    import org.apache.oozie.executor.jpa.JPAExecutorException;
027    import org.apache.oozie.executor.jpa.WorkflowActionRetryManualGetJPAExecutor;
028    import org.apache.oozie.executor.jpa.WorkflowActionUpdateJPAExecutor;
029    import org.apache.oozie.executor.jpa.WorkflowJobGetJPAExecutor;
030    import org.apache.oozie.executor.jpa.WorkflowJobUpdateJPAExecutor;
031    import org.apache.oozie.service.JPAService;
032    import org.apache.oozie.service.Services;
033    import org.apache.oozie.util.InstrumentUtils;
034    import org.apache.oozie.util.LogUtils;
035    import org.apache.oozie.util.ParamChecker;
036    import org.apache.oozie.workflow.WorkflowException;
037    import org.apache.oozie.workflow.WorkflowInstance;
038    import org.apache.oozie.workflow.lite.LiteWorkflowInstance;
039    
040    public class SuspendXCommand extends WorkflowXCommand<Void> {
041        private final String wfid;
042        private WorkflowJobBean wfJobBean;
043        private JPAService jpaService;
044    
045        public SuspendXCommand(String id) {
046            super("suspend", "suspend", 1);
047            this.wfid = ParamChecker.notEmpty(id, "wfid");
048        }
049    
050        /* (non-Javadoc)
051         * @see org.apache.oozie.command.XCommand#execute()
052         */
053        @Override
054        protected Void execute() throws CommandException {
055            InstrumentUtils.incrJobCounter(getName(), 1, getInstrumentation());
056            try {
057                suspendJob(this.jpaService, this.wfJobBean, this.wfid, null);
058                jpaService.execute(new WorkflowJobUpdateJPAExecutor(this.wfJobBean));
059                queue(new NotificationXCommand(this.wfJobBean));
060            }
061            catch (WorkflowException e) {
062                throw new CommandException(e);
063            }
064            catch (JPAExecutorException je) {
065                throw new CommandException(je);
066            }
067            finally {
068                // update coordinator action
069                new CoordActionUpdateXCommand(wfJobBean).call();
070            }
071            return null;
072        }
073    
074        /**
075         * Suspend the workflow job and pending flag to false for the actions that are START_RETRY or START_MANUAL or
076         * END_RETRY or END_MANUAL
077         *
078         * @param jpaService jpa service
079         * @param workflow workflow job
080         * @param id workflow job id
081         * @param actionId workflow action id
082         * @throws WorkflowException thrown if failed to suspend workflow instance
083         * @throws CommandException thrown if unable set pending false for actions
084         */
085        public static void suspendJob(JPAService jpaService, WorkflowJobBean workflow, String id, String actionId)
086                throws WorkflowException, CommandException {
087            if (workflow.getStatus() == WorkflowJob.Status.RUNNING) {
088                workflow.getWorkflowInstance().suspend();
089                WorkflowInstance wfInstance = workflow.getWorkflowInstance();
090                ((LiteWorkflowInstance) wfInstance).setStatus(WorkflowInstance.Status.SUSPENDED);
091                workflow.setStatus(WorkflowJob.Status.SUSPENDED);
092                workflow.setWorkflowInstance(wfInstance);
093    
094                setPendingFalseForActions(jpaService, id, actionId);
095            }
096        }
097    
098        /**
099         * Set pending flag to false for the actions that are START_RETRY or START_MANUAL or END_RETRY or END_MANUAL
100         * <p/>
101         *
102         * @param jpaService jpa service
103         * @param id workflow job id
104         * @param actionId workflow action id
105         * @throws CommandException thrown if failed to update workflow action
106         */
107        private static void setPendingFalseForActions(JPAService jpaService, String id, String actionId)
108                throws CommandException {
109            List<WorkflowActionBean> actions;
110            try {
111                actions = jpaService.execute(new WorkflowActionRetryManualGetJPAExecutor(id));
112    
113                for (WorkflowActionBean action : actions) {
114                    if (actionId != null && actionId.equals(action.getId())) {
115                        // this action has been changed in handleNonTransient()
116                        continue;
117                    }
118                    else {
119                        action.resetPendingOnly();
120                    }
121                    jpaService.execute(new WorkflowActionUpdateJPAExecutor(action));
122    
123                }
124            }
125            catch (JPAExecutorException je) {
126                throw new CommandException(je);
127            }
128        }
129    
130        /* (non-Javadoc)
131         * @see org.apache.oozie.command.XCommand#eagerLoadState()
132         */
133        @Override
134        protected void eagerLoadState() throws CommandException {
135            super.eagerLoadState();
136            try {
137                jpaService = Services.get().get(JPAService.class);
138                if (jpaService != null) {
139                    this.wfJobBean = jpaService.execute(new WorkflowJobGetJPAExecutor(this.wfid));
140                }
141                else {
142                    throw new CommandException(ErrorCode.E0610);
143                }
144            }
145            catch (Exception ex) {
146                throw new CommandException(ErrorCode.E0603, ex);
147            }
148            LogUtils.setLogInfo(this.wfJobBean, logInfo);
149        }
150    
151        /* (non-Javadoc)
152         * @see org.apache.oozie.command.XCommand#eagerVerifyPrecondition()
153         */
154        @Override
155        protected void eagerVerifyPrecondition() throws CommandException, PreconditionException {
156            super.eagerVerifyPrecondition();
157            if (this.wfJobBean.getStatus() != WorkflowJob.Status.RUNNING) {
158                throw new PreconditionException(ErrorCode.E0727, this.wfJobBean.getStatus());
159            }
160        }
161    
162        /* (non-Javadoc)
163         * @see org.apache.oozie.command.XCommand#getEntityKey()
164         */
165        @Override
166        protected String getEntityKey() {
167            return this.wfid;
168        }
169    
170        /* (non-Javadoc)
171         * @see org.apache.oozie.command.XCommand#isLockRequired()
172         */
173        @Override
174        protected boolean isLockRequired() {
175            return true;
176        }
177    
178        /* (non-Javadoc)
179         * @see org.apache.oozie.command.XCommand#loadState()
180         */
181        @Override
182        protected void loadState() throws CommandException {
183    
184        }
185    
186        /* (non-Javadoc)
187         * @see org.apache.oozie.command.XCommand#verifyPrecondition()
188         */
189        @Override
190        protected void verifyPrecondition() throws CommandException, PreconditionException {
191        }
192    }