org.iobserve.analysis.behavior.models.data.BehaviorModelTable.java Source code

Java tutorial

Introduction

Here is the source code for org.iobserve.analysis.behavior.models.data.BehaviorModelTable.java

Source

/***************************************************************************
 * Copyright (C) 2017 iObserve Project (https://www.iobserve-devops.net)
 *
 * 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 org.iobserve.analysis.behavior.models.data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.math3.util.Pair;
import org.iobserve.analysis.behavior.SingleOrNoneCollector;
import org.iobserve.analysis.behavior.models.extended.CallInformation;
import org.iobserve.stages.general.data.EntryCallEvent;
import org.iobserve.stages.general.data.PayloadAwareEntryCallEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;

/**
 * table representation of a behavior model.
 *
 * @author Christoph Dornieden
 *
 *         TODO rework filter, presently some values are handled as strings due to other behavior
 *         model.
 *
 */

public class BehaviorModelTable extends AbstractBehaviorModelTable {

    private static final Logger LOGGER = LoggerFactory.getLogger(BehaviorModelTable.class);

    private final Map<String, Pair<Integer, AggregatedCallInformation[]>> signatures;
    private final String[] inverseSignatures;
    private final Integer[][] transitions;

    /**
     * constructor.
     *
     * @param signatures
     *            signatures
     */
    public BehaviorModelTable(final String[] signatures) { // NOPMD

        final int size = signatures.length;
        this.inverseSignatures = signatures;

        this.signatures = new HashMap<>();
        for (int i = 0; i < signatures.length; i++) {
            this.signatures.put(signatures[i], new Pair<>(i, new AggregatedCallInformation[0]));
        }

        this.transitions = new Integer[size][size];
    }

    /**
     * constructor.
     *
     * @param signatures
     *            signatures of CallEvents
     * @param reverseSignatures
     *            reverse signature Map
     * @param transitions
     *            transition matrix with marked EMPTY_TRANSITION fields
     */

    public BehaviorModelTable(final Map<String, Pair<Integer, AggregatedCallInformation[]>> signatures,
            final String[] reverseSignatures, final Integer[][] transitions) {

        // verify input
        final int length = signatures.size();

        if ((length == reverseSignatures.length) && (length == transitions.length)) {

            for (final Integer[] transition : transitions) {
                if (length != transition.length) {
                    throw new IllegalArgumentException("input value size mismatch");
                }
            }
            for (int i = 0; i < length; i++) {
                if (signatures.get(reverseSignatures[i]).getFirst() != i) {
                    throw new IllegalArgumentException("signature mismatch");
                }
            }
        } else {
            throw new IllegalArgumentException("input value size mismatch");
        }

        // assign values
        this.signatures = signatures;
        this.inverseSignatures = reverseSignatures;
        this.transitions = transitions;
    }

    @Override
    public void addTransition(final EntryCallEvent from, final EntryCallEvent to) {
        final String fromSignature = this.getSignatureFromEvent(from);
        final String toSignature = this.getSignatureFromEvent(to);

        if (!(this.isAllowedSignature(fromSignature) && this.isAllowedSignature(toSignature))) {
            throw new IllegalArgumentException("event signature not allowed");
        }

        final Integer fromIndex = this.signatures.get(fromSignature).getFirst();
        final Integer toIndex = this.signatures.get(toSignature).getFirst();

        final int currentTransitionValue = this.transitions[fromIndex][toIndex];

        if (currentTransitionValue == AbstractBehaviorModelTable.EMPTY_TRANSITION) {
            throw new IllegalArgumentException("transition not intended");
        }

        this.transitions[fromIndex][toIndex] = currentTransitionValue + 1;
    }

    @Override
    public boolean isAllowedSignature(final String signature) {
        return this.signatures.containsKey(signature);
    }

    @Override
    public void addInformation(final PayloadAwareEntryCallEvent event) {
        final String eventSignature = this.getSignatureFromEvent(event);
        final List<CallInformation> newCallInformations = new ArrayList<>();

        try {
            for (int i = 0; i < event.getParameters().length; i++) {
                newCallInformations.add(new CallInformation(event.getParameters()[i], String.valueOf(
                        this.parameterValueDoubleMapper.mapValue(event.getParameters()[i], event.getValues()[i]))));
            }

            final List<AggregatedCallInformation> aggCallInformations = Arrays
                    .asList(this.signatures.get(eventSignature).getSecond());

            for (final CallInformation newCallInformation : newCallInformations) {

                // add new CallInfromation to the aggregation correctly
                final Optional<AggregatedCallInformation> match = aggCallInformations.stream()
                        .filter(aggCallInformation -> aggCallInformation.belongsTo(newCallInformation))
                        .collect(new SingleOrNoneCollector<>());

                match.ifPresent(aggCallInformation -> aggCallInformation.addCallInformation(newCallInformation));
            }

        } catch (final IllegalArgumentException e) {
            BehaviorModelTable.LOGGER.error("Illegal argument exception", e);
        }
    }

    /**
     * creates a cleared copy.
     *
     * @param keepEmptyTransitions
     *            defines whether or not the empty transitions should be kept
     * @return cleared copy of the table
     */
    public BehaviorModelTable getClearedCopy(final boolean keepEmptyTransitions) {
        final Map<String, Pair<Integer, AggregatedCallInformation[]>> clearedSignatures = new HashMap<>();

        for (final String signature : this.signatures.keySet()) {

            final Pair<Integer, AggregatedCallInformation[]> valuePair = this.signatures.get(signature);

            final AggregatedCallInformation[] aggregatedCallInformations = Arrays.stream(valuePair.getSecond())
                    .map(AggregatedCallInformation::getClearedCopy).toArray(AggregatedCallInformation[]::new);

            final Pair<Integer, AggregatedCallInformation[]> fixedPair = new Pair<>(valuePair.getFirst(),
                    aggregatedCallInformations);
            clearedSignatures.put(signature, fixedPair);
        }
        final Integer[][] clearedTransitions = new Integer[clearedSignatures.size()][clearedSignatures.size()];

        for (int i = 0; i < clearedTransitions.length; i++) {
            for (int j = 0; j < clearedTransitions.length; j++) {
                clearedTransitions[i][j] = (this.transitions[i][j] == AbstractBehaviorModelTable.EMPTY_TRANSITION)
                        && keepEmptyTransitions ? AbstractBehaviorModelTable.EMPTY_TRANSITION : 0;

            }
        }

        return new BehaviorModelTable(clearedSignatures, this.inverseSignatures, clearedTransitions);
    }

    /**
     * create an Instances object for clustering.
     *
     * @return instance
     */
    public Instances toInstances() {
        final FastVector fastVector = new FastVector();

        // add transitions
        for (int i = 0; i < this.signatures.size(); i++) {
            for (int j = 0; j < this.signatures.size(); j++) {
                if (this.transitions[i][j] > AbstractBehaviorModelTable.TRANSITION_THRESHOLD) {
                    final Attribute attribute = new Attribute(
                            AbstractBehaviorModelTable.EDGE_INDICATOR + this.inverseSignatures[i]
                                    + AbstractBehaviorModelTable.EDGE_DIVIDER + this.inverseSignatures[j]);

                    fastVector.addElement(attribute);

                } else {
                    continue;
                }
            }
        }

        // add informations
        this.signatures.values().stream().forEach(pair -> Arrays.stream(pair.getSecond())
                .forEach(callInformation -> fastVector.addElement(new Attribute(
                        AbstractBehaviorModelTable.INFORMATION_INDICATOR + this.inverseSignatures[pair.getFirst()]
                                + AbstractBehaviorModelTable.INFORMATION_DIVIDER
                                + callInformation.getSignature()))));
        // TODO name
        final Instances instances = new Instances("Test", fastVector, 0);
        final Instance instance = this.toInstance();
        instances.add(instance);

        return instances;
    }

    /**
     * returns an instance vector.
     *
     * @return instance
     */
    public Instance toInstance() {
        final List<Double> attValues = new ArrayList<>();

        // add transitions
        for (int i = 0; i < this.signatures.size(); i++) {
            for (int j = 0; j < this.signatures.size(); j++) {

                if (this.transitions[i][j] > AbstractBehaviorModelTable.TRANSITION_THRESHOLD) {
                    attValues.add(Double.valueOf(this.transitions[i][j]));
                } else {
                    continue;
                }
            }
        }

        final Collection<Pair<Integer, AggregatedCallInformation[]>> signatureCollection = this.signatures.values();
        for (final Pair<Integer, AggregatedCallInformation[]> pair : signatureCollection) {
            for (final AggregatedCallInformation callInformation : pair.getValue()) {
                if (callInformation.getRepresentativeValue() != null) { // Check for
                                                                        // representativeValues that
                                                                        // are null
                    attValues.add(Double.parseDouble(callInformation.getRepresentativeValue()));
                } else {
                    attValues.add(0.0);
                }

            }
        }

        // this.signatures.values().stream()
        // .forEach(pair ->
        // Arrays.stream(pair.getSecond())
        // .forEach(callInformation ->
        // attValues.add(Double.parseDouble(callInformation.getRepresentativeValue()))
        // ));

        final double[] attArray = new double[attValues.size()];

        for (int i = 0; i < attValues.size(); i++) {
            attArray[i] = attValues.get(i) == null ? 0.0 : attValues.get(i);
        }

        return new Instance(1.0, attArray);
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return this.signatures.keySet().stream().reduce("\n", (s1, s2) -> s1 + "\n" + s2) + "\n";
    }

    /**
     * @return the signatures
     */
    public Map<String, Pair<Integer, AggregatedCallInformation[]>> getSignatures() {
        return this.signatures;
    }

    /**
     * @return the inverseSignatures
     */
    public String[] getInverseSignatures() {
        return this.inverseSignatures; // NOPMD
    }

    /**
     * @return the transitions
     */
    public Integer[][] getTransitions() {
        return this.transitions; // NOPMD
    }
}