com.jgoetsch.eventtrader.source.HttpPollingMsgSource.java Source code

Java tutorial

Introduction

Here is the source code for com.jgoetsch.eventtrader.source.HttpPollingMsgSource.java

Source

/*
 * Copyright (c) 2012 Jeremy Goetsch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jgoetsch.eventtrader.source;

import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jgoetsch.eventtrader.Msg;
import com.jgoetsch.eventtrader.source.parser.MsgParser;

public class HttpPollingMsgSource extends AbstractHttpMsgSource {

    private Logger log = LoggerFactory.getLogger(HttpPollingMsgSource.class);
    private long pollingInterval = 60000;
    private long freshnessThreshold = 30000;
    private MsgParser msgParser;
    private boolean useIfModifiedSince = false;
    private boolean alertInitial = false;

    private String lastModifiedDate;

    private class NewMsgHandler implements MsgHandler {
        private Set<Msg> lastMsgs;
        private Set<Msg> msgs = new HashSet<Msg>();
        private Date lastCheckAt;

        public boolean newMsg(Msg msg) {
            msgs.add(msg);
            if (lastCheckAt != null
                    && new Date().getTime() - lastCheckAt.getTime() > pollingInterval + freshnessThreshold) {
                if (lastMsgs != null)
                    lastMsgs.clear();
                lastMsgs = null;
            }
            if (lastMsgs == null) {
                log.debug("Previous message: {}", msg);
            }
            if ((lastMsgs != null && !lastMsgs.contains(msg)) || (lastMsgs == null && alertInitial)) {
                if (!HttpPollingMsgSource.this.newMsg(msg))
                    return false;
            }
            return true;
        }

        public void nextPass() {
            if (lastMsgs != null)
                lastMsgs.clear();
            lastMsgs = msgs;
            msgs = new HashSet<Msg>(lastMsgs.size() + 4);
            lastCheckAt = new Date();
        }
    };

    public void receiveMsgs(HttpClient client) {
        NewMsgHandler msgHandler = new NewMsgHandler();
        HttpUriRequest req = createRequest();
        for (;;) {
            HttpEntity entity = null;
            try {
                if (isUseIfModifiedSince() && lastModifiedDate != null)
                    req.setHeader("If-Modified-Since", lastModifiedDate);

                long startTime = System.currentTimeMillis();
                HttpResponse rsp = client.execute(req);
                if (rsp.containsHeader("Last-Modified")) {
                    lastModifiedDate = rsp.getFirstHeader("Last-Modified").getValue();
                    //log.debug("Resource last modified: " + lastModifiedDate);
                }
                entity = rsp.getEntity();
                if (rsp.getStatusLine().getStatusCode() >= 400) {
                    log.warn("HTTP request to " + req.getURI().getHost() + " failed ["
                            + rsp.getStatusLine().getStatusCode() + " " + rsp.getStatusLine().getReasonPhrase()
                            + ", " + (System.currentTimeMillis() - startTime) + " ms]");

                    // 400 level error should be unrecoverable so just quit out
                    if (rsp.getStatusLine().getStatusCode() < 500)
                        return;
                    else {
                        // give server some more time to recover before retrying if it returned 500 level error
                        // probably means site crashed and continuing to hit it will only make things worse
                        try {
                            Thread.sleep(pollingInterval * 6);
                        } catch (InterruptedException e) {
                        }
                    }
                } else {
                    boolean bContinue = true;
                    if (entity != null && rsp.getStatusLine().getStatusCode() != 304) { // 304 = not modified
                        bContinue = getMsgParser().parseContent(entity.getContent(), entity.getContentLength(),
                                entity.getContentType() == null ? null : entity.getContentType().getValue(),
                                msgHandler);
                        msgHandler.nextPass();
                    }
                    if (log.isDebugEnabled()) {
                        log.debug(
                                "Checked site at " + req.getURI().getHost() + " ["
                                        + rsp.getStatusLine().getStatusCode() + " "
                                        + rsp.getStatusLine().getReasonPhrase() + ", "
                                        + (entity != null ? (entity.getContentLength() != -1
                                                ? entity.getContentLength() + " bytes, "
                                                : "unknown length, ") : "")
                                        + (System.currentTimeMillis() - startTime) + " ms]");
                    }
                    if (!bContinue)
                        return;
                }
            } catch (IOException e) {
                log.warn(e.getClass() + ": " + e.getMessage());
            } catch (Exception e) {
                log.warn(e.getClass() + ": " + e.getMessage(), e);
            } finally {
                if (entity != null) {
                    // release connection gracefully
                    try {
                        entity.consumeContent();
                    } catch (IOException e) {
                    }
                }
            }

            delay();
        }
    }

    protected void delay() {
        try {
            Thread.sleep(pollingInterval);
        } catch (InterruptedException e) {
        }
    }

    protected void doLoginAction(HttpClient client) {
    }

    /*
    private LocalTime parseLocalTime(String time) {
       String tok[] = time.split("[\\:\\s]");
       if (tok.length < 3 || tok.length > 4)
     throw new IllegalArgumentException("Time must be in format \"HH:MM:SS [timezone]\"");
       return new LocalTime(Integer.parseInt(tok[0]), Integer.parseInt(tok[1]), Integer.parseInt(tok[2]));
    }
    */

    public void setPollingInterval(long milliseconds) {
        this.pollingInterval = milliseconds;
    }

    public long getPollingInterval() {
        return pollingInterval;
    }

    public void setPollingIntervalSeconds(long seconds) {
        this.pollingInterval = seconds * 1000;
    }

    public void setPollingIntervalMinutes(long minutes) {
        this.pollingInterval = minutes * 60000;
    }

    public void setMsgParser(MsgParser msgParser) {
        this.msgParser = msgParser;
    }

    public MsgParser getMsgParser() {
        return msgParser;
    }

    public void setUseIfModifiedSince(boolean useIfModifiedSince) {
        this.useIfModifiedSince = useIfModifiedSince;
    }

    public boolean isUseIfModifiedSince() {
        return useIfModifiedSince;
    }

    public void setAlertInitial(boolean alertInitial) {
        this.alertInitial = alertInitial;
    }

    public boolean isAlertInitial() {
        return alertInitial;
    }

    public long getFreshnessThreshold() {
        return freshnessThreshold;
    }

    public void setFreshnessThreshold(long freshnessThreshold) {
        this.freshnessThreshold = freshnessThreshold;
    }

}