com.brewtab.irclog.SQLFromIrssiLog.java Source code

Java tutorial

Introduction

Here is the source code for com.brewtab.irclog.SQLFromIrssiLog.java

Source

/*
 * Copyright (c) 2013 Christopher Thunes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.brewtab.irclog;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sampullara.cli.Args;
import com.sampullara.cli.Argument;

public class SQLFromIrssiLog {
    private static final Logger log = LoggerFactory.getLogger(SQLFromIrssiLog.class);

    private static final Pattern metaPattern = Pattern.compile("^--- (.*)");
    private static final Pattern eventPattern = Pattern.compile("^(\\d\\d):(\\d\\d) (.*)");
    private static final Pattern messagePattern = Pattern.compile("<(.)(.*?)> (.*)");
    private static final Pattern actionPattern = Pattern.compile(" \\* (.*?) (.*)");

    @Argument(required = true)
    private String logFile;

    @Argument
    private String channel;

    private BufferedReader input;
    private DateTime currentDate;

    private static final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("EEE MMM dd yyyy");
    private static final DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss yyyy");

    private DateTime sessionStart = null;

    private void unexepectedLine(String line) {
        log.warn("Unexpected log line: {}", line);
    }

    private String timestampFormat(DateTime t) {
        return t.toString("yyyy-MM-dd HH:mm:ss");
    }

    private String prepare(String format, Object... args) {
        List<String> newArgs = new ArrayList<String>(args.length);

        for (Object arg : args) {
            if (arg instanceof DateTime) {
                newArgs.add("'" + timestampFormat((DateTime) arg) + "'");
            } else if (arg instanceof Integer || arg instanceof Long || arg instanceof Double
                    || arg instanceof Float) {
                newArgs.add(arg.toString());
            } else if (arg instanceof String) {
                newArgs.add("'" + ((String) arg).replace("'", "''") + "'");
            } else {
                throw new IllegalArgumentException("Can not convert type " + arg);
            }
        }

        return String.format(format.replace("?", "%s"), newArgs.toArray());
    }

    private void startSession(DateTime startTime) {
        if (sessionStart != null) {
            throw new IllegalStateException("Session already in progress");
        }

        this.sessionStart = startTime;
    }

    private void endSession(DateTime endTime) {
        if (sessionStart == null) {
            throw new IllegalStateException("Session ended without starting");
        }

        String sql = "INSERT INTO sessions (start_time, end_time, active) VALUES (?, ?, FALSE);";
        String prepared = prepare(sql, sessionStart, endTime);

        System.out.println(prepared);
        sessionStart = null;
    }

    private void event(DateTime time, String type, String nick) {
        String sql = "INSERT INTO events (event_time, type, nick) VALUES (?, ?, ?);";
        String prepared = prepare(sql, time, type, nick);

        System.out.println(prepared);
    }

    private void event(DateTime time, String type, String nick, String extra) {
        String sql = "INSERT INTO events (event_time, type, nick, extra) VALUES (?, ?, ?, ?);";
        String prepared = prepare(sql, time, type, nick, extra.substring(0, Math.min(extra.length(), 256)));

        System.out.println(prepared);
    }

    private void message(DateTime time, String channel, String nick, String msg) {
        String sql = "INSERT INTO messages (msg_time, channel, nick, message) VALUES (?, ?, ?, ?);";
        String prepared = prepare(sql, time, channel, nick, msg);

        System.out.println(prepared);
    }

    private void action(DateTime time, String channel, String nick, String act) {
        message(time, channel, nick, "\001ACTION " + act);
    }

    private void processLine(String line) throws Exception {
        Matcher lineMatcher = eventPattern.matcher(line);

        if (lineMatcher.matches()) {
            int hours = Integer.valueOf(lineMatcher.group(1));
            int minutes = Integer.valueOf(lineMatcher.group(2));
            currentDate = currentDate.withHourOfDay(hours).withMinuteOfHour(minutes);

            String rest = lineMatcher.group(3);

            if (rest.startsWith("<")) {
                Matcher messageMatcher = messagePattern.matcher(rest);

                if (!messageMatcher.matches()) {
                    unexepectedLine(line);
                    return;
                }

                String nick = messageMatcher.group(2);
                String msg = messageMatcher.group(3);

                message(currentDate, channel, nick, msg);
            } else if (rest.startsWith(" *")) {
                Matcher actionMatcher = actionPattern.matcher(rest);

                if (!actionMatcher.matches()) {
                    unexepectedLine(line);
                    return;
                }

                String nick = actionMatcher.group(1);
                String action = actionMatcher.group(2);

                action(currentDate, channel, nick, action);
            } else if (rest.startsWith("-!-")) {
                rest = rest.substring(4);

                if (rest.startsWith("Irssi: ")) {
                    // Ignore
                } else if (rest.startsWith("mode/")) {
                    // Ignore
                } else if (rest.matches(".*? \\[.*?\\] .*")) {
                    Matcher userEventMatcher = Pattern.compile("(.*?) \\[(.*?)\\] (.*)").matcher(rest);
                    userEventMatcher.matches();

                    String nick = userEventMatcher.group(1);
                    String user = userEventMatcher.group(2);
                    String event = userEventMatcher.group(3);

                    if (event.startsWith("has quit ")) {
                        Matcher quitMatcher = Pattern.compile("has quit \\[(.*)\\]$").matcher(event);

                        if (!quitMatcher.matches()) {
                            unexepectedLine(line);
                            return;
                        }

                        String reason = quitMatcher.group(1);

                        event(currentDate, "quit", nick, channel);
                    } else if (event.startsWith("has joined ")) {
                        Matcher joinedMatcher = Pattern.compile("has joined (.*)").matcher(event);

                        if (!joinedMatcher.matches()) {
                            unexepectedLine(line);
                            return;
                        }

                        String channel = joinedMatcher.group(1);

                        event(currentDate, "join", nick, channel);
                    } else if (event.startsWith("has left ")) {
                        Matcher leftMatcher = Pattern.compile("has left (.*?) \\[(.*)\\]$").matcher(event);

                        if (!leftMatcher.matches()) {
                            unexepectedLine(line);
                            return;
                        }

                        String channel = leftMatcher.group(1);
                        String reason = leftMatcher.group(2);

                        event(currentDate, "part", nick, channel);
                    } else {
                        unexepectedLine(line);
                        return;
                    }
                } else if (rest.startsWith("You're now known as ")) {
                    Matcher nickChangeMatcher = Pattern.compile("^You're now known as (.*?)$").matcher(rest);
                    nickChangeMatcher.matches();

                    String toNick = nickChangeMatcher.group(1);

                    // Not supported
                } else if (rest.matches("^[^ ]* is now known as [^ ]*$")) {
                    Matcher nickChangeMatcher = Pattern.compile("^([^ ]*) is now known as ([^ ]*)$").matcher(rest);
                    nickChangeMatcher.matches();

                    String fromNick = nickChangeMatcher.group(1);
                    String toNick = nickChangeMatcher.group(2);

                    // Not supported
                } else if (rest.matches("^.*? was kicked from .*? by .*? \\[.*?\\]$")) {
                    Matcher kickMatcher = Pattern.compile("^(.*?) was kicked from (.*?) by (.*?) \\[(.*?)\\]$")
                            .matcher(rest);
                    kickMatcher.matches();

                    String nick = kickMatcher.group(1);
                    String from = kickMatcher.group(2);
                    String byNick = kickMatcher.group(3);
                    String reason = kickMatcher.group(4);

                    // Not supported
                } else if (rest.matches("^.*? changed the topic of .*? to: .*")) {
                    Matcher topicMatcher = Pattern.compile("^(.*?) changed the topic of (.*?) to: (.*)")
                            .matcher(rest);
                    topicMatcher.matches();

                    String nick = topicMatcher.group(1);
                    String topic = topicMatcher.group(3);

                    // Not supported
                } else {
                    unexepectedLine(line);
                    return;
                }
            } else {
                unexepectedLine(line);
                return;
            }
        } else {
            lineMatcher = metaPattern.matcher(line);

            if (!lineMatcher.matches()) {
                unexepectedLine(line);
                return;
            }

            String rest = lineMatcher.group(1);

            if (rest.startsWith("Day changed")) {
                currentDate = dateFormat.parseDateTime(rest.replace("Day changed ", ""));
            } else if (rest.startsWith("Log opened")) {
                if (sessionStart != null) {
                    // Previous session was ended abruptly. Close it using the
                    // last known timestamp.
                    endSession(currentDate);
                }

                startSession(dateTimeFormat.parseDateTime(rest.replace("Log opened ", "")));
            } else if (rest.startsWith("Log closed")) {
                if (sessionStart != null) {
                    endSession(dateTimeFormat.parseDateTime(rest.replace("Log closed ", "")));
                }
            } else {
                unexepectedLine(line);
                return;
            }
        }
    }

    private void run() throws Exception {
        if (channel == null) {
            Matcher channelMatcher = Pattern.compile("^(?:.*/)?(.*)\\.log$").matcher(logFile);

            if (channelMatcher.matches()) {
                channel = channelMatcher.group(1);
            } else {
                throw new IllegalArgumentException("Could not determine channel from log file name");
            }
        }

        input = new BufferedReader(new FileReader(logFile));
        currentDate = DateTime.now();

        System.out.println("BEGIN;");

        while (true) {
            String line = input.readLine();

            if (line == null) {
                break;
            }

            try {
                processLine(line);
            } catch (Exception e) {
                log.error("Error on line: {}", line, e);
                break;
            }
        }

        System.out.println("COMMIT;");

        input.close();
    }

    public static void main(String[] args) throws Exception {
        SQLFromIrssiLog cmd = new SQLFromIrssiLog();

        try {
            Args.parse(cmd, args);
        } catch (IllegalArgumentException e) {
            Args.usage(cmd);
            System.exit(-1);
            return;
        }

        cmd.run();
    }
}