Appendix - Groovy Processors

A Groovy processor is a piece of Groovy code defined with a Closure named process, taking one constant string (and one only) as parameter.

This page discusses:

The string value has two possible interpretations:

  • If empty, it means that the processor is executed on all document types pushed to the Consolidation Server.

  • If non-empty, then the processor is executed by checking if the type provided belongs to the document type inheritance. See Processor Type Inheritance and Runtime Selection.

Recommendation: Read the Groovy documentation.

The similar behavior is achieved in Java with IJavaAggregationProcessor.getAggregationDocumentType() and IJavaTransformationProcessor.getTransformationDocumentType().

process("city") {
  log.info("Processing " + it.getUri());
}

The code above is equivalent to Java Example 1. You do not find for which source it is associated to, because it is defined in the Administration Console as shown below.



Although it is not explicitly visible in the method signature, the process method receives the current document being processed (transformation or aggregation) using the special it variable. You can see it in the above example with it.getUri(), which is the equivalent of IConsolidationDocument.getUri().

Groovy Transformation and Aggregation Operations

The Java interfaces defining the allowed operations for Transformation and Aggregation are shared with the Groovy language.

As a result, all the operations present in Java are also available in Groovy. Specific shortcuts are however available in Groovy only:

  • You can access all getters directly without specifying a method call and the get prefix. For example, you can rewrite it.getUri() as it.uri.

  • You can also access the following properties with similar shorthands:

    • it.metas: The document metadata. For example, it.metas.company_name returns a Groovy list of strings containing the meta values for the company_name meta. You can also specify the meta name between quotes. So you could write it.metas."company_name". It is even more interesting to make it dynamic by writing it.metas."$myVar", where the variable ''myVar'' would be defined with the assignment myVar = "company_name".

    • it.directives: The document directives. Usage is similar to it.metas.

    • it.parts: The document parts. Usage is similar to it.metas except that values are now instances of IDocumentPart as in Java.

Company's Hierarchy Example in Groovy

Let us see how you can implement the Connect Employees to Services and Services to Companies in Groovy.

process("employee") {
    def addService = { serviceName, companyName ->
        serviceDoc = createDocument("service=" + serviceName + "&", "service")
        serviceDoc.directives.datamodel_class = "service"
        serviceDoc.addArcTo("service", "company=" + companyName + "&")
        yield serviceDoc
        serviceDoc //return object
    }

    if (it.metas.company_name && it.metas.service_name) {
      serviceDoc = addService(it.metas.service_name[0], it.metas.company_name[0])
      it.addArcTo("employee", serviceDoc.getUri())
    }
}

For Count the Number of Employees and Push Updated Documents, a possible implementation could be:

process("company") {
    it.metas.nb_employees = match(it, "-service.-employee").size();
}

Discard Processor Code Samples

DiscardAggregationProcessor.java

package com.exalead.samples.consolidation;

import com.exalead.cloudview.consolidationapi.processors.IAggregationDocument;
import com.exalead.cloudview.consolidationapi.processors.java.IJavaAllUpdatesAggregationHandler;
import com.exalead.cloudview.consolidationapi.processors.java.IJavaAllUpdatesAggregationProcessor;
import com.exalead.mercury.component.config.CVComponentConfigClass;

@CVComponentConfigClass(configClass = DiscardAggregationProcessorConfig.class, configCheckClass = 
DiscardAggregationProcessorConfigCheck.class)
public class DiscardAggregationProcessor implements IJavaAllUpdatesAggregationProcessor {

    private final String[] discardedDocumentTypes;

    public DiscardAggregationProcessor(final DiscardAggregationProcessorConfig config) {
        final String[] configDocumentTypes = config.getDocumentTypes();
        if (configDocumentTypes != null) {
            this.discardedDocumentTypes = new String[configDocumentTypes.length];
            for (int i = 0; i < configDocumentTypes.length; i++) {
                this.discardedDocumentTypes[i] = configDocumentTypes[i].trim();
            }
        } else {
            this.discardedDocumentTypes = null;
        }
    }

    @Override
    public String getAggregationDocumentType() {
        return null;
    }

    @Override
    public void process(IJavaAllUpdatesAggregationHandler handler, IAggregationDocument document) throws 
Exception {
        if (this.discardedDocumentTypes != null) {
            for (int i = 0; i < this.discardedDocumentTypes.length; i++) {
                if (document.getTypeInheritance().contains(this.discardedDocumentTypes[i])) {
                    handler.discard();
                }
            }
        }
    }
}

DiscardAggregationProcessorConfig.java

package com.exalead.samples.consolidation;

import com.exalead.config.bean.IsMandatory;
import com.exalead.config.bean.PropertyDescription;
import com.exalead.config.bean.PropertyLabel;
import com.exalead.mercury.component.config.CVComponentConfig;

public class DiscardAggregationProcessorConfig implements CVComponentConfig {
        public final static String[] METHODS = {
            "DocumentTypes"
    };

    public static final String[] getMethods() {
        return METHODS;
    }

    private String[] documentTypes;
        public DiscardAggregationProcessorConfig() {
    }

    @IsMandatory(true)
    @PropertyLabel("Discard document types")
    @PropertyDescription("Specifies types of documents to be discarded")
    public void setDocumentTypes(String[] documentTypes) {
        this.documentTypes = documentTypes;
    }

    public String[] getDocumentTypes() {
        return this.documentTypes;
    }
}

DiscardAggregationProcessorConfigCheck.java

package com.exalead.samples.consolidation;

import com.exalead.config.bean.ConfigurationException;
import com.exalead.mercury.component.config.CVComponentConfigCheck;

public class DiscardAggregationProcessorConfigCheck implements
 CVComponentConfigCheck<DiscardAggregationProcessorConfig> {
    @Override
    public void check(final DiscardAggregationProcessorConfig config, final boolean useNow) throws 
ConfigurationException, Exception {
        if (config != null) {
            final String[] documentTypes = config.getDocumentTypes();
            if (documentTypes != null && documentTypes.length == 0) {
                final ConfigurationException error = new ConfigurationException
                  ("Discard aggregation processor: 'documentTypes' property can't be empty.");
                error.setConfigKey("documentTypes");
                throw error;
            }
            for (String documentType : documentTypes) {
                final String trimmedDocumentType = documentType.trim();
                if (trimmedDocumentType.isEmpty()) {
                    final ConfigurationException error = new ConfigurationException
                      ("Discard aggregation processor: empty 'documentTypes' entry");
                    error.setConfigKey("documentTypes");
                    throw error;
                }
            }
        }
    }
}