ai.susi.server.AccessTracker.java Source code

Java tutorial

Introduction

Here is the source code for ai.susi.server.AccessTracker.java

Source

/**
 *  AccessTracker
 *  Copyright 11.10.2015 by Michael Peter Christen, @0rb1t3r
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program in the file lgpl21.txt
 *  If not, see <http://www.gnu.org/licenses/>.
 */

package ai.susi.server;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentSkipListMap;

import org.eclipse.jetty.util.log.Log;
import org.json.JSONObject;

import ai.susi.DAO;
import ai.susi.json.JsonRepository;
import ai.susi.tools.DateParser;

public class AccessTracker extends Thread {

    private final static String START_DATE_KEY = "start";
    private final static String FINISH_DATE_KEY = "finish";
    private final static String CLIENT_KEY = "host"; // host address of the client
    private final static String LOCALHOST_FLAG = "local"; // boolean from isLocalhost
    private final static String COMMENT_KEY = "comment"; // to write i.e. termination reason
    private final static String IDLE_TIME_KEY = "idle";
    private final static String DOS_BLACKOUT_KEY = "dosb";
    private final static String DOS_REDUCTION_KEY = "dosr";
    private final static String RUNTIME_KEY = "busy";
    private final static String QUERY_KEY = "query";

    public final static String EVENT_PREFIX = "event_";

    private final static String COMMENT_CLOSED = "closed";

    public final static int MAX_FINISHED = 1000;

    private JsonRepository history;
    private long track_timeout;
    private long schedule_period;
    private boolean terminate;
    private ConcurrentSkipListMap<Date, Track> pendingQueue, finishedQueue;

    public AccessTracker(File dump_dir, String dump_file_prefix, long track_timeout, long schedule_period)
            throws IOException {
        this.history = new JsonRepository(dump_dir, dump_file_prefix, null, JsonRepository.Mode.COMPRESSED, false,
                1);
        this.track_timeout = track_timeout;
        this.schedule_period = schedule_period;
        this.terminate = false;
        this.pendingQueue = new ConcurrentSkipListMap<>();
        this.finishedQueue = new ConcurrentSkipListMap<>();
    }

    public Collection<Track> getTracks() {
        List<Track> tracks = new ArrayList<>();
        for (Track track : this.pendingQueue.descendingMap().values())
            tracks.add(track);
        for (Track track : this.finishedQueue.descendingMap().values())
            tracks.add(track);
        return tracks;
    }

    public void run() {
        monitor: while (!terminate) {
            // identify oldest track and remove it from the pending tracks if it is over timeout time
            timeoutcheck: while (this.pendingQueue.size() > 0) {
                Map.Entry<Date, Track> t = this.pendingQueue.firstEntry();
                if (t == null)
                    break timeoutcheck;
                boolean timeout = t.getKey().getTime() + AccessTracker.this.track_timeout < System
                        .currentTimeMillis();
                if (timeout || t.getValue().has(FINISH_DATE_KEY)) {
                    try {
                        writeToHistory(t.getValue(), null);
                        this.pendingQueue.remove(t.getKey());
                        this.finishedQueue.put(t.getKey(), t.getValue());
                        while (this.finishedQueue.size() > MAX_FINISHED)
                            this.finishedQueue.remove(this.finishedQueue.firstKey());
                        continue timeoutcheck;
                    } catch (IOException e) {
                        Log.getLog().warn(e);
                        break monitor;
                    }
                }
                break timeoutcheck;
            }

            try {
                Thread.sleep(this.schedule_period);
            } catch (InterruptedException e) {
                if (this.terminate)
                    break monitor;
            }
        }
        try {
            for (Track track : this.pendingQueue.values())
                writeToHistory(track, COMMENT_CLOSED);
        } catch (IOException e) {
            Log.getLog().warn(e);
        }
    }

    private void writeToHistory(Track track, String comment) throws IOException {
        if (comment != null)
            track.put(COMMENT_KEY, comment);
        this.history.write(track);
    }

    public void close() {
        // if the daemon is running, terminate first
        this.terminate = true;
        if (this.isAlive())
            try {
                this.interrupt();
                this.join(10000);
            } catch (InterruptedException e) {
            }

        // write remaining tracks from pending queue
        try {
            for (Track track : this.pendingQueue.values())
                writeToHistory(track, COMMENT_CLOSED);
        } catch (IOException e) {
            Log.getLog().warn(e);
        }
    }

    public class Track extends JSONObject {

        public String getClientHost() {
            return clientHost;
        }

        private Date accessTime;
        private String clientHost;
        private long time_since_last_access;
        private boolean isLocalhost;
        private boolean DoS_blackout, DoS_servicereduction;

        public Track(String servlet, String clientHost) {
            this.clientHost = clientHost;
            long time = System.currentTimeMillis();
            Date lastDate = null;
            try {
                lastDate = AccessTracker.this.pendingQueue.lastKey();
            } catch (NoSuchElementException e) {
            }
            long last = lastDate == null ? time - 1 : lastDate.getTime();
            if (time <= last)
                time = last + 1;
            this.accessTime = new Date(time);
            this.put(START_DATE_KEY, DateParser.iso8601MillisFormat.format(accessTime));
            this.put(CLIENT_KEY, clientHost);
            this.isLocalhost = RemoteAccess.isLocalhost(clientHost);
            this.put(LOCALHOST_FLAG, this.isLocalhost);
            AccessTracker.this.pendingQueue.put(accessTime, this);
        }

        public Track(String serialized) {
            try {
                JSONObject json = new JSONObject(serialized);
                this.putAll(json);
            } catch (Throwable e) {
                DAO.log("cannot parse \"" + serialized + "\"");
            }
        }

        public Date getDate() {
            return this.accessTime;
        }

        public long getTimeSinceLastAccess() {
            return time_since_last_access;
        }

        public void setTimeSinceLastAccess(long time_since_last_access) {
            this.time_since_last_access = time_since_last_access;
            this.put(IDLE_TIME_KEY, time_since_last_access);
        }

        public boolean isDoSBlackout() {
            return DoS_blackout;
        }

        public void setDoSBlackout(boolean doS_blackout) {
            DoS_blackout = doS_blackout;
            this.put(DOS_BLACKOUT_KEY, doS_blackout);
        }

        public boolean isDoSServicereduction() {
            return DoS_servicereduction;
        }

        public void setDoSServicereduction(boolean doS_servicereduction) {
            DoS_servicereduction = doS_servicereduction;
            this.put(DOS_REDUCTION_KEY, doS_servicereduction);
        }

        public boolean isLocalhostAccess() {
            return this.isLocalhost;
        }

        public void setQuery(final Map<String, String> qm) {
            if (qm == null)
                return;
            Map<String, Object> m = new LinkedHashMap<>();
            m.putAll(qm);
            this.put(QUERY_KEY, m);
        }

        public String toString() {
            return new JSONObject(this).toString();
        }

        public void finalize() {
            Date finishTime = new Date();
            long runtime = finishTime.getTime() - this.accessTime.getTime();
            this.put(RUNTIME_KEY, runtime);
            this.put(FINISH_DATE_KEY, DateParser.iso8601MillisFormat.format(finishTime));
        }
    }

    public Track startTracking(String servlet, String clientHost) {
        return new Track(servlet, clientHost);
    }

}