org.eclipse.linuxtools.tmf.totalads.algorithms.slidingwindow.SlidingWindow.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.linuxtools.tmf.totalads.algorithms.slidingwindow.SlidingWindow.java

Source

/*********************************************************************************************
 * Copyright (c) 2014  Software Behaviour Analysis Lab, Concordia University, Montreal, Canada
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of XYZ License which
 * accompanies this distribution, and is available at xyz.com/license
 *
 * Contributors:
 *    Syed Shariyar Murtaza
 **********************************************************************************************/
package org.eclipse.linuxtools.tmf.totalads.algorithms.slidingwindow;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import org.eclipse.linuxtools.tmf.totalads.algorithms.IDetectionAlgorithm;
import org.eclipse.linuxtools.tmf.totalads.algorithms.AlgorithmFactory;
import org.eclipse.linuxtools.tmf.totalads.algorithms.Results;
import org.eclipse.linuxtools.tmf.totalads.algorithms.AlgorithmTypes;
import org.eclipse.linuxtools.tmf.totalads.core.Configuration;
import org.eclipse.linuxtools.tmf.totalads.dbms.DBMS;
import org.eclipse.linuxtools.tmf.totalads.exceptions.TotalADSDBMSException;
import org.eclipse.linuxtools.tmf.totalads.exceptions.TotalADSReaderException;
import org.eclipse.linuxtools.tmf.totalads.exceptions.TotalADSUIException;
import org.eclipse.linuxtools.tmf.totalads.readers.ITraceIterator;
import org.eclipse.linuxtools.tmf.totalads.ui.modeling.ProgressConsole;
import org.swtchart.Chart;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;

/**
 * This class implements the Sliding Window algorithm
 * @author <p> Syed Shariyar Murtaza justsshary@hotmail.com </p> 
 * 
 */
public class SlidingWindow implements IDetectionAlgorithm {

    private String TRACE_COLLECTION = "trace_data";//Configuration.traceCollection;
    private String SETTINGS_COLLECTION = "settings";//Configuration.settingsCollection;
    private Integer maxWin = 5;
    private Integer maxHamDis = 0;
    private String warningMessage = "";
    private HashMap<String, Event[]> sysCallSequences;
    private String[] trainingOptions = { "Max Win", "5", "Max Hamming Distance", "0" };
    private String[] testingOptions = { "Max Hamming Distance", "0" };
    private Integer validationTraceCount = 0;
    private Integer validationAnomalies = 0;
    private Integer testTraceCount = 0;
    private Integer testAnomalies = 0;
    private Boolean intialize = false;
    private Boolean isTestStarted = false;
    private SlidingWindowTree treeTransformer;

    /**
     * Constructor
     **/
    public SlidingWindow() {
        sysCallSequences = new HashMap<String, Event[]>();
        treeTransformer = new SlidingWindowTree();
    }

    /**
     * Initializes the model if already exists in the database
     * @param connection DBMS object
     * @param database   Database name
     */
    private void initialize(DBMS connection, String database) {

        DBCursor cursor = connection.selectAll(database, this.TRACE_COLLECTION);
        if (cursor != null) {
            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                Gson gson = new Gson();
                String key = dbObject.get("_id").toString();

                Event[] event = gson.fromJson(dbObject.get("tree").toString(), Event[].class);
                sysCallSequences.put(key, event);
            }
            cursor.close();
        }
        // get the maxwin
        cursor = connection.selectAll(database, this.SETTINGS_COLLECTION);
        if (cursor != null) {
            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                maxWin = Integer.parseInt(dbObject.get(SettingsCollection.MAX_WIN.toString()).toString());
                maxHamDis = Integer.parseInt(dbObject.get(SettingsCollection.MAX_HAM_DIS.toString()).toString());
            }
            cursor.close();
        }

    }

    /**
      * Returns the settings of an algorithm as option name at index i and value at index i+1
      * @return String[] Array of String
      */
    @Override
    public String[] getTrainingOptions() {
        return trainingOptions;

    }

    /**
     * 
     * Set the settings of an algorithm as option name at index i and value ate index i+1
     * @return String[] Array of String
     *
     */
    @Override
    public String[] getTestingOptions(String database, DBMS connection) {
        DBCursor cursor = connection.selectAll(database, this.SETTINGS_COLLECTION);
        if (cursor != null) {
            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                //maxWin=Integer.parseInt(dbObject.get(SETTINGS_COLL_FIELDS.MAX_WIN).toString());
                maxHamDis = Integer.parseInt(dbObject.get(SettingsCollection.MAX_HAM_DIS.toString()).toString());
            }
            cursor.close();
        }
        testingOptions[1] = maxHamDis.toString();
        return testingOptions;

    }

    /**
     * Creates a database to store models
     */
    @Override
    public void createDatabase(String databaseName, DBMS connection) throws TotalADSDBMSException {
        String[] collectionNames = { TRACE_COLLECTION, SETTINGS_COLLECTION };
        connection.createDatabase(databaseName, collectionNames);
    }

    /**
     * 
     * Trains the model by overriding a method from the interface {@link IDetectionAlgorithm}
     * 
     */
    @Override
    public void train(ITraceIterator trace, Boolean isLastTrace, String database, DBMS connection,
            ProgressConsole console, String[] options, Boolean isNewDB)
            throws TotalADSUIException, TotalADSDBMSException, TotalADSReaderException {

        if (!intialize) {
            validationTraceCount = 0;
            validationAnomalies = 0;
            int maxWinLimit = 15;

            // If the option name is the same and database has no model then take the maxwin from user
            // else maxwin aleady exists in the database. We cannot change it
            if (options != null) {
                try {
                    if (sysCallSequences.size() != 0)
                        warningMessage = "Warning: window size was not changed because the model (database) already exists.";
                    else if (options[0].equals(this.trainingOptions[0]))
                        maxWin = Integer.parseInt(options[1]);// on error exception will be thrown automatically

                    //check for hamming distance
                    if (options[2].equals(this.trainingOptions[2]))
                        maxHamDis = Integer.parseInt(options[3]);// on error exception will be thrown automatically

                } catch (Exception ex) {// Capturing exception to send a UI error
                    throw new TotalADSUIException("Please, enter integer numbers only in options.");
                }

                if (maxWin > maxWinLimit)
                    throw new TotalADSUIException("Sequence size too large; select " + maxWinLimit + " or lesser.");
            }

            intialize = true;
            // Initializing 
            if (isNewDB)
                createDatabase(database, connection);
            initialize(connection, database);

        }

        int winWidth = 0;
        LinkedList<String> newSequence = new LinkedList<String>();

        while (trace.advance()) {

            newSequence.add(trace.getCurrentEvent());

            winWidth++;

            if (winWidth >= maxWin) {

                winWidth--;
                String[] seq = new String[maxWin];
                seq = newSequence.toArray(seq);
                // searching and adding to db
                // System.out.println(Arrays.toString(seq));
                treeTransformer.searchAndAddSequence(seq, sysCallSequences);

                newSequence.remove(0);
            }

        }
        if (isLastTrace) {
            // Saving events tree in database

            treeTransformer.saveinDatabase(console, database, connection, sysCallSequences, TRACE_COLLECTION);
            intialize = false;
        }

    }

    /**
     * 
     * Validates the model by overriding a method from the interface {@link IDetectionAlgorithm}
     *
     */
    @Override
    public void validate(ITraceIterator trace, String database, DBMS connection, Boolean isLastTrace,
            ProgressConsole console) throws TotalADSUIException, TotalADSDBMSException, TotalADSReaderException {

        validationTraceCount++;// count the number of traces

        //Integer []hammAnomalies=new Integer[maxWin];
        Results result = evaluateTrace(trace, database, connection);

        if (result.getAnomaly()) {
            String details = result.getDetails().toString();
            console.printTextLn(details);
            // Integer hamming=Integer.parseInt(details.split("::")[1]);
            //hammAnomalies[hamming]++;
            validationAnomalies++;

        }

        if (isLastTrace) {

            //for (int hamCount=1; hamCount < hammAnomalies.length; hamCount++){
            //       console.printTextLn("Anomalies at hamming "+ hamCount + ":" +hammAnomalies[hamCount]);
            //       totalAnomalies+=hammAnomalies[hamCount];
            // }
            console.printTextLn("Total traces in validation folder: " + validationTraceCount);
            Double anomalyPrcentage = (validationAnomalies.doubleValue() / validationTraceCount.doubleValue())
                    * 100;
            console.printTextLn(
                    "Total anomalies at max hamming distance " + maxHamDis + " are " + anomalyPrcentage);
            Double normalPercentage = (100 - anomalyPrcentage);
            console.printTextLn("Total normal at max hamming distance " + maxHamDis + " are " + normalPercentage);

            // Update the settings collection for maxwin and maxhamm
            saveSettings(database, connection);
            console.printTextLn("Database updated..");

            if (!warningMessage.isEmpty())
                console.printTextLn(warningMessage);
        }

    }

    /**
     * Tests the model by overriding a method from the interface {@link IDetectionAlgorithm}
     */
    @Override
    public Results test(ITraceIterator trace, String database, DBMS connection, String[] options)
            throws TotalADSUIException, TotalADSDBMSException, TotalADSReaderException {

        if (!isTestStarted) {
            testTraceCount = 0;
            testAnomalies = 0;
            initialize(connection, database); // get the trees from db
            if (options != null && options[0].equals(this.testingOptions[0])) {
                try {
                    maxHamDis = Integer.parseInt(options[1]);
                } catch (NumberFormatException ex) {
                    throw new TotalADSUIException("Please, enter an integer value.");
                }
                saveSettings(database, connection); // save maxHamm
            }
            isTestStarted = true;
        }

        return evaluateTrace(trace, database, connection);

    }

    /**
     * Evaluates a trace
     * @param trace
     * @param database
     * @param connection
     * @return
     * @throws TotalADSReaderException 
     */
    private Results evaluateTrace(ITraceIterator trace, String database, DBMS connection)
            throws TotalADSReaderException {
        int winWidth = 0, anomalousSequencesToReturn = 0, maxAnomalousSequencesToReturn = 10;
        int displaySeqCount = 0;
        Results results = new Results();
        results.setAnomalyType("");
        results.setAnomaly(false);
        testTraceCount++;

        LinkedList<String> newSequence = new LinkedList<String>();
        //System.out.println(maxWin);
        while (trace.advance()) {

            newSequence.add(trace.getCurrentEvent());

            winWidth++;

            if (winWidth >= maxWin) {

                winWidth--;

                String[] seq = new String[maxWin];
                seq = newSequence.toArray(seq);

                Event[] nodes = null;
                int counter = 0;

                do {// This loop searches for the tree that starts with the first event of a new sequences, 
                    // if not found it starts with a second event, then the third event and so on. Each time
                    //it keeps on increasing the hamming distnace
                    nodes = sysCallSequences.get(seq[counter]);
                    counter++;
                } while (nodes == null && counter < seq.length);

                //Boolean isNormal=false;
                Integer hammDis = counter - 1; // we assign hamming distance 

                if (nodes != null) { // if a tree has been found then we go inside this condition

                    String[] tmp;

                    if (hammDis >= 1) {// if we have found a tree that does not start with the 
                        // first event of a new sequence in the above loop then we pass the sequence 
                        // from where it matched with the root of the tree in the above loop
                        if (seq.length == counter) {
                            int a = 0;
                            a++;
                        }

                        tmp = new String[seq.length - (counter - 1)];
                        for (int i = counter - 1; i < tmp.length; i++)
                            tmp[i] = seq[i + 1];
                        hammDis = hammDis + treeTransformer.getHammingAndSearch(nodes, tmp) - 1;// calculate hamming distance and subtract 1
                        // because one extra distance is reported from the function
                        // getHammingAndSearch
                    } else
                        hammDis = treeTransformer.getHammingAndSearch(nodes, seq); // just get the hamming and search with a full sequence

                }
                //isNormal=searchMatchingSequenceInTree(nodes, seq);
                // System.out.println(hammDis+ " "+maxHamDis);
                if (hammDis > maxHamDis) {// It is not normal, it is actually an anomaly
                    results.setAnomaly(true);

                    if (anomalousSequencesToReturn % maxWin == 0) { // add a new sequence when the previous events are gone
                        results.setDetails(Arrays.toString(seq) + "::" + hammDis + "\n");
                        displaySeqCount++;
                    }

                    anomalousSequencesToReturn++;
                }
                if (displaySeqCount >= maxAnomalousSequencesToReturn) {
                    results.setDetails(".....\n....." + maxAnomalousSequencesToReturn + " or less"
                            + " randomly selected anomalies" + "\n");
                    break;// No need to extract all the anomalous sequences in a trace;
                          // just return and break
                }
                newSequence.remove(0);// remove the top event and slide a window
            }

        }
        if (results.getAnomaly())
            testAnomalies++;

        return results;

    }

    /**
     * Updates settings collection
     * @param datatbase
     * @param connection
     * @throws TotalADSDBMSException 
     */
    private void saveSettings(String database, DBMS connection) throws TotalADSDBMSException {

        String settingsKey = "SWN_SETTINGS";

        JsonObject jsonKey = new JsonObject();
        jsonKey.addProperty("_id", settingsKey);

        JsonObject jsonObjToUpdate = new JsonObject();
        jsonObjToUpdate.addProperty(SettingsCollection.KEY.toString(), settingsKey);
        jsonObjToUpdate.addProperty(SettingsCollection.MAX_WIN.toString(), maxWin);
        jsonObjToUpdate.addProperty(SettingsCollection.MAX_HAM_DIS.toString(), maxHamDis);

        connection.insertOrUpdateUsingJSON(database, jsonKey, jsonObjToUpdate, this.SETTINGS_COLLECTION);

    }

    /** 
     * Text Results, an overriden method
     */
    @Override
    public String getSummaryOfTestResults() {
        Double anomalousPercentage = (testAnomalies.doubleValue() / testTraceCount.doubleValue()) * 100;
        return anomalousPercentage.toString() + "%";
    }

    /* 
     * graphicalResults, an overriden method
     */
    @Override
    public Chart graphicalResults(ITraceIterator traceIterator) {

        return null;
    }

    /* 
     * Creates Instance, an overriden method
     */
    @Override
    public IDetectionAlgorithm createInstance() {

        return new SlidingWindow();
    }

    /** 
     * Returns the name
     */
    @Override
    public String getName() {

        return "Sliding Window (SWN)";
    }

    /**
     * Returns the acronym of the model
     */
    public String getAcronym() {

        return "SWN";
    }

    /**
     *  Self registration of the model with the modelFactory 
     */
    public static void registerModel() throws TotalADSUIException {
        AlgorithmFactory modelFactory = AlgorithmFactory.getInstance();
        SlidingWindow sldWin = new SlidingWindow();
        modelFactory.registerModelWithFactory(AlgorithmTypes.ANOMALY, sldWin);
    }

    /**
     * Performs cross validation
     */
    @Override
    public void crossValidate(Integer folds, String database, DBMS connection, ProgressConsole console,
            ITraceIterator trace, Boolean isLastTrace) throws TotalADSUIException, TotalADSDBMSException {

    }
}