org.wikimedia.analytics.kraken.funnel.FunnelNode.java Source code

Java tutorial

Introduction

Here is the source code for org.wikimedia.analytics.kraken.funnel.FunnelNode.java

Source

/**
 *Copyright (C) 2012-2013  Wikimedia Foundation
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program 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 General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; if not, write to the Free Software
 *Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    
 */
package org.wikimedia.analytics.kraken.funnel;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.wikimedia.analytics.kraken.exceptions.MalformedFunnelException;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/*
 * A FunnelNode is a building block for a Funnel. The simplest funnel is:
 * A -> B where both A and B are instances of the FunnelNode class. To construct
 * a FunnelNode supply it a list of semi-colon separated edges, the edges are 
 * separated by a comma.  
 */
public class FunnelNode extends Node {
    /** The nodeDefinition. */
    private final Map<ComponentType, Pattern> nodeDefinition = new HashMap<ComponentType, Pattern>();
    public int impression = 0;
    public int bounced = 0;

    /**
     * Instantiates a new node. 
     *
     * @param edge contains a step in a funnel.
     * @throws MalformedFunnelException
      * @throws PatternSyntaxException
     */
    public FunnelNode(String edge) throws MalformedFunnelException, PatternSyntaxException {
        String[] nodes = edge.split("=");
        ComponentType key;
        try {
            key = ComponentType.valueOf(nodes[0].toUpperCase());
        } catch (IllegalArgumentException e) {
            key = null;
        }
        Pattern value = Pattern.compile(nodes[1], Pattern.CASE_INSENSITIVE);
        if (key != null) {
            this.nodeDefinition.put(key, value);
        }
    }

    protected void incrementImpression() {
        this.impression++;
    }

    protected void incrementBounced() {
        this.bounced++;
    }

    public double completionRate() {
        return 1.0 - ((double) this.bounced / this.impression);
    }

    /**
     * Whether a UserActionNode matches this FunnelNode
     *
     * @param {@link UserActionNode} instance to determine whether that
     *         action was taken inside/outside of a funnel.
     * @return true if the regular expression of {@link FunnelNode} matches
     * the node definition of {@link UserActionNode} otherwise false.
     */
    public boolean matches(UserActionNode node) {
        boolean match = true;
        for (ComponentType key : this.nodeDefinition.keySet()) {
            match = match && node.componentValues.containsKey(key)
                    && this.nodeDefinition.get(key).matcher(node.componentValues.get(key)).matches();
            if (!match) {
                break;
            }
        }
        return match;
    }

    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (obj instanceof UserActionNode) {
            return this.matches((UserActionNode) obj);
        }
        if (!(obj instanceof FunnelNode)) {
            return false;
        }

        FunnelNode node = (FunnelNode) obj;
        return new EqualsBuilder().append(this.nodeDefinition.toString(), node.nodeDefinition.toString())
                .isEquals();
    }

    public int hashCode() {
        return new HashCodeBuilder().append(this.toString()).toHashCode();
    }

    public String toString() {
        StringBuilder sb = new StringBuilder(100);
        int e = 1;
        for (ComponentType key : ComponentType.values()) {
            Pattern value = this.nodeDefinition.get(key);
            if (value != null) {
                sb.append(value.toString());
            }
            if (nodeDefinition.size() > 1 && e < nodeDefinition.size()) {
                sb.append(":");
            }
            e++;
        }
        return sb.toString();
    }
}