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 org.apache.oozie.client.OozieClient;
018    import org.apache.oozie.WorkflowActionBean;
019    import org.apache.oozie.WorkflowJobBean;
020    import org.apache.oozie.command.Command;
021    import org.apache.oozie.service.Services;
022    import org.apache.oozie.store.WorkflowStore;
023    import org.apache.oozie.store.Store;
024    import org.apache.oozie.util.XLog;
025    
026    import java.io.IOException;
027    import java.net.HttpURLConnection;
028    import java.net.URL;
029    
030    public class NotificationCommand extends WorkflowCommand<Void> {
031    
032        public static final String NOTIFICATION_URL_CONNECTION_TIMEOUT_KEY = "oozie.notification.url.connection.timeout";
033        public static final int NOTIFICATION_URL_CONNECTION_TIMEOUT_DEFAULT = 10 * 1000; // 10 seconds
034    
035        private static final String STATUS_PATTERN = "\\$status";
036        private static final String JOB_ID_PATTERN = "\\$jobId";
037        private static final String NODE_NAME_PATTERN = "\\$nodeName";
038    
039        private String url;
040        //this variable is package private only for test purposes
041        int retries = 0;
042    
043        public NotificationCommand(WorkflowJobBean workflow) {
044            super("job.notification", "job.notification", 0, XLog.STD, false);
045            url = workflow.getWorkflowInstance().getConf().get(OozieClient.WORKFLOW_NOTIFICATION_URL);
046            if (url != null) {
047                url = url.replaceAll(JOB_ID_PATTERN, workflow.getId());
048                url = url.replaceAll(STATUS_PATTERN, workflow.getStatus().toString());
049            }
050        }
051    
052        public NotificationCommand(WorkflowJobBean workflow, WorkflowActionBean action) {
053            super("action.notification", "job.notification", 0, XLog.STD);
054            url = workflow.getWorkflowInstance().getConf().get(OozieClient.ACTION_NOTIFICATION_URL);
055            if (url != null) {
056                url = url.replaceAll(JOB_ID_PATTERN, workflow.getId());
057                url = url.replaceAll(NODE_NAME_PATTERN, action.getName());
058                if (action.isComplete()) {
059                    url = url.replaceAll(STATUS_PATTERN, "T:" + action.getTransition());
060                }
061                else {
062                    url = url.replaceAll(STATUS_PATTERN, "S:" + action.getStatus().toString());
063                }
064            }
065        }
066    
067        public Void call(WorkflowStore store) {
068            if (url != null) {
069                int timeout = Services.get().getConf().getInt(NOTIFICATION_URL_CONNECTION_TIMEOUT_KEY,
070                                                              NOTIFICATION_URL_CONNECTION_TIMEOUT_DEFAULT);
071                try {
072                    URL url = new URL(this.url);
073                    HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
074                    urlConn.setConnectTimeout(timeout);
075                    urlConn.setReadTimeout(timeout);
076                    if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK) {
077                        handleRetry();
078                    }
079                }
080                catch (IOException ex) {
081                    handleRetry();
082                }
083            }
084            return null;
085        }
086    
087        private void handleRetry() {
088            if (retries < 3) {
089                retries++;
090                queueCallable(this, 60 * 1000);
091            }
092            else {
093                XLog.getLog(getClass()).warn(XLog.OPS, "could not send notification [{0}]", url);
094            }
095        }
096    
097    }