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.coord;
016    
017    import java.io.IOException;
018    import java.io.StringReader;
019    import java.net.HttpURLConnection;
020    import java.net.URL;
021    
022    import org.apache.hadoop.conf.Configuration;
023    import org.apache.oozie.CoordinatorActionBean;
024    import org.apache.oozie.ErrorCode;
025    import org.apache.oozie.client.OozieClient;
026    import org.apache.oozie.command.CommandException;
027    import org.apache.oozie.command.wf.NotificationCommand;
028    import org.apache.oozie.service.Services;
029    import org.apache.oozie.store.CoordinatorStore;
030    import org.apache.oozie.store.StoreException;
031    import org.apache.oozie.util.XConfiguration;
032    import org.apache.oozie.util.XLog;
033    
034    public class CoordActionNotification extends CoordinatorCommand<Void> {
035    
036        private CoordinatorActionBean actionBean;
037        private static final String STATUS_PATTERN = "\\$status";
038        private static final String ACTION_ID_PATTERN = "\\$actionId";
039    
040        //this variable is package private only for test purposes
041        int retries = 0;
042        private final XLog log = XLog.getLog(getClass());
043    
044            public CoordActionNotification(CoordinatorActionBean actionBean) {
045                    super("coord_action_notification", "coord_action_notification", 0,
046                                    XLog.STD);
047                    this.actionBean = actionBean;
048            }
049    
050        @Override
051        protected Void call(CoordinatorStore store) throws StoreException,
052                CommandException {
053            setLogInfo(actionBean);
054            log.info("STARTED Coordinator Notification actionId="
055                    + actionBean.getId() + " : " + actionBean.getStatus());
056            Configuration conf;
057            try {
058                conf = new XConfiguration(new StringReader(actionBean.getRunConf()));
059            }
060            catch (IOException e1) {
061                log.warn("Configuration parse error. read from DB :"
062                        + actionBean.getRunConf());
063                throw new CommandException(ErrorCode.E1005, e1.getMessage(), e1);
064            }
065            String url = conf.get(OozieClient.COORD_ACTION_NOTIFICATION_URL);
066            if (url != null) {
067                url = url.replaceAll(ACTION_ID_PATTERN, actionBean.getId());
068                url = url.replaceAll(STATUS_PATTERN, actionBean.getStatus()
069                        .toString());
070                log.debug("Notification URL :" + url);
071                try {
072                    int timeout = Services.get().getConf().getInt(
073                        NotificationCommand.NOTIFICATION_URL_CONNECTION_TIMEOUT_KEY,
074                        NotificationCommand.NOTIFICATION_URL_CONNECTION_TIMEOUT_DEFAULT);
075                    URL urlObj = new URL(url);
076                    HttpURLConnection urlConn = (HttpURLConnection) urlObj.openConnection();
077                    urlConn.setConnectTimeout(timeout);
078                    urlConn.setReadTimeout(timeout);
079                    if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK) {
080                        handleRetry(url);
081                    }
082                }
083                catch (IOException ex) {
084                    handleRetry(url);
085                }
086            }
087            else {
088                log
089                        .info("No Notification URL is defined. Therefore nothing to notify for job "
090                                + actionBean.getJobId()
091                                + " action ID "
092                                + actionBean.getId());
093                // System.out.println("No Notification URL is defined. Therefore nothing is notified");
094            }
095            log.info("ENDED Coordinator Notification actionId="
096                    + actionBean.getId());
097            return null;
098        }
099    
100        private void handleRetry(String url) {
101            if (retries < 3) {
102                retries++;
103                queueCallable(this, 60 * 1000);
104            }
105            else {
106                XLog.getLog(getClass()).warn(XLog.OPS,
107                                             "could not send notification [{0}]", url);
108            }
109        }
110    
111    }