Creating an Analyzer

Overall Structure

Creating an analyzer is done in a builder class with the factory design pattern. The XML tags specified in the analyzer sequence related to that particular analyzer should be converted into the configuration information to be stored in the config file. That config object is passed to the analyzer constructor at the build time of the analyzer by the builder. (i.e. factory)

At the runtime the analyzer accepts a "DataContext" object that has the input data either in format of an Array or a Map of records. According to the configuration information specified in the config object input data can be processed performing the analyzing activity. Finally processed data are stored back into the given "DataContext" object.

Output data should be compatible with the input data types of other analyzers as well which enables the user to apply analyzers in different orders in a analyzer sequence that improves the flexibility. In this document we use "AggregateAnalyzer" as the example.

Analyzer Factory

An analyzer builder class should be created to generate analyzers in run time. Generally a builder class should be given a name similar to "AggregateAnalyzerBuilder" and extend the "AnalyzerBuilder" class. All existing analyzers builders are located in org.wso2.carbon.bam.analyzer/src/main/java/org/wso2/carbon/bam/analyzer/analyzers/builders package.

Sample builder class



public class AggregateAnalyzerBuilder extends AnalyzerBuilder {
    @Override
    protected AnalyzerConfig buildConfig(OMElement analyzerXML) throws AnalyzerException {	// Accepts XML tags to input as OMElement
	........
	........
	........
        return aggregateConfig; // Returns the configuration object
    }

    @Override
    public Analyzer buildAnalyzer(OMElement analyzerXML) throws AnalyzerException { // This builds a new analyzer
        return new AggregateAnalyzer(buildConfig(analyzerXML)); // Add the configurations to the analyzer while creating
    }
}



There the XML tags specified in the analyzer sequence related to that particular analyzer should be converted into the configuration information. The configuration information is to be stored in the config file that can be created in org.wso2.carbon.bam.analyzer/src/main/java/org/wso2/carbon/bam/analyzer/analyzers/configs package.

Sample XML tags specific to a particular analyzer


		<aggregate>            
			<measure name="quantity" aggregationType="SUM"/>        
		</aggregate>


Sample config class of a particular analyzer


public class AggregateConfig implements AnalyzerConfig { // Should implement AnalyzerConfig interface 
    private List<AggregationMeasure> measures; // Keeps measures as configuration information

    public List<AggregationMeasure> getMeasures() { // get method of configuration information
        return measures;
    }

    public void setMeasures(List<AggregationMeasure> measures) { // set method of configuration information
        this.measures = measures;
    }

    @Override
    public String serialize(Analyzer analyzer) throws AnalyzerException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Analyzer deserialize(OMElement anaylzerOM) throws AnalyzerException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }
}

Analyzer Class

All the analyzers should be named similar to the name as "AggregateAnalyzer" and included into the org.wso2.carbon.bam.analyzer/src/main/java/org/wso2/carbon/bam/analyzer/analyzers package. All the analyzers should extent the class "AbstractAnalyzer". The constructor of analyzer should pass the configuration object to its parent as "AbstractAnalyzer" keeps all the configuration information. "analyze" is the public method of analyzer that does the analyzing. Data to be analyzed should be given as a reference as an object of "DataContext". Data inside that object can be retrieved as an object using the "getData" method. Retrieved object should either be an Array or a Map of "Record"s. This test should be done in the "analyze" function and appropriate operations should be done for each case. Other cases should raise an error. After all the operations, modified data should be applied to the "DataContext" object given as inputs such that the "DataContext" object is compatible with the input data format of another analyzer.

Sample analyzer class of a particular analyzer


public class AggregateAnalyzer extends AbstractAnalyzer { // Should extend from AbstractAnalyzer

    private static final Log log = LogFactory.getLog(AggregateAnalyzer.class);

    public AggregateAnalyzer(AnalyzerConfig analyzerConfig) { // Set configurations in the super class
        super(analyzerConfig);
    }

    public void analyze(DataContext dataContext) { // Receive input as a reference to a DataContext object

        Object result = getData(dataContext); // Get data from DataContext object

        List<Record> results = new ArrayList<Record>();
        if (result != null) { // Input should have a value
            if (result instanceof List) { // Test whether input data are in the format of a List
                ..........
		..........
		..........

            } else if (result instanceof Map) { // Test whether input data are in the format of a Map
                ..........
		..........
		..........
            } else {
                log.error("Unknown data format in received data for aggregate analyzer..");
            }
        } else {
            log.warn("Data flow empty at aggregate analyzer in sequence : " +
                     getAnalyzerSequenceName());
        }

        setData(dataContext, results); // Finally update the DataContext with new data