org.mule.intents.AppBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.intents.AppBuilder.java

Source

/*
 * $Id$
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.intents;

import org.mule.intents.model.Action;
import org.mule.intents.model.ContentType;
import org.mule.intents.model.Module;
import org.mule.intents.model.Trigger;
import org.mule.intents.model.app.ActionConfig;
import org.mule.intents.model.app.AppDefinition;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import org.codehaus.jackson.map.ObjectMapper;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

/**
 * TODO
 */
public class AppBuilder {
    //public static final Namespace docNS = new Namespace("doc", "http://www.mulesoft.org/schema/mule/documentation");
    public static final Namespace muleNS = new Namespace("", "http://www.mulesoft.org/schema/mule/core");
    public static final Namespace xsiNS = new Namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");

    public static final QName xsiQN = new QName("schemaLocation", xsiNS);

    private Document config;
    private String rawConfig;
    private Registry registry;
    private AppDefinition app;
    private Element flow;
    private Map<String, String> schemaLocations = new HashMap<String, String>();
    private StringBuilder errors = new StringBuilder();
    private File appFile;

    public AppBuilder(File appDef, Registry registry) throws IOException, DocumentException {
        this.appFile = appDef;
        this.registry = registry;
        ObjectMapper mapper = new ObjectMapper();
        //This is a safe operation meaning that it is validated against the registry when it
        //is created, no need to perform any extra checks
        app = mapper.readValue(appDef, AppDefinition.class);
        //this could be better isolated, but its a spike
        app.validate(registry, errors);
        if (errors.length() > 0) {
            throw new IllegalArgumentException(
                    "Application is not configured properly: " + appFile + "\n" + errors);
        }
        List<Action> actions = new ArrayList<Action>();

        //Lookup Action elements for this app
        Action currentAction = null;

        for (ActionConfig actionConfig : app.getActions()) {
            Action action = registry.getAction(actionConfig.getName());
            if (currentAction != null) {
                if (!action.getTemplate().supportsInputTypes(currentAction.getTemplate().getOutputTypes())) {
                    throw new IllegalArgumentException("App is not valid, Template "
                            + currentAction.getTemplate().getName() + " ("
                            + currentAction.getTemplate().getOutputTypes() + ") not compatible with template: "
                            + action.getName() + " (" + action.getTemplate().getInputTypes() + ")");
                }
                currentAction = action;
            }

            actions.add(action);
        }

        //Create the Mule config with the mule root element and NS
        config = createMuleConfig();

        Trigger trigger = registry.getTrigger(app.getTrigger().getName());
        addModuleConfig(trigger.getTemplate().getModule());
        addTrigger(trigger);

        //Process any top-level module configs first
        //We do this loop first since these config elements should appear at the
        //top of the config
        for (Action action : actions) {
            addModuleConfig(action.getTemplate().getModule());
        }

        for (Action action : actions) {
            addAction(action);
        }

        rawConfig = convertConfigToString();
        System.out.println(rawConfig);
        System.out.println(getAllParams().toString());

        printDataTypes();
    }

    public Document getConfig() {
        return config;
    }

    public String getRawConfig() {
        return rawConfig;
    }

    public AppDefinition getApp() {
        return app;
    }

    public void addModuleConfig(Module module) throws IOException, DocumentException {
        //This top level module config is optional
        Document snippet = module.loadConfig();
        if (snippet == null)
            return;

        addNamespaces(snippet);
        addSchemaLocations(snippet);
        for (Object o : snippet.getRootElement().content()) {
            if (o instanceof Element) {
                Element e = (Element) ((Element) o).detach();
                config.getRootElement().add(e);
            }
        }

    }

    public void addTrigger(Trigger trigger) throws IOException, DocumentException {
        Document snippet = trigger.getTemplate().loadSnippet();
        addNamespaces(snippet);
        addSchemaLocations(snippet);

        for (Object o : snippet.getRootElement().content()) {
            if (o instanceof Element) {
                Element e = (Element) ((Element) o).detach();
                config.getRootElement().add(e);
                if (e.getName().equals("flow") && e.attribute("name").getValue().equals("main")) {
                    flow = e;
                }
            }
        }

        addInterceptor(trigger, flow);
    }

    public void addAction(Action action) throws IOException, DocumentException {
        Document snippet = action.getTemplate().loadSnippet();
        addNamespaces(snippet);
        addSchemaLocations(snippet);
        for (Object o : snippet.getRootElement().content()) {
            if (o instanceof Element) {
                Element e = (Element) ((Element) o).detach();
                config.getRootElement().add(e);
                if (e.getQName().getName().equals("sub-flow")) {
                    Element element = flow.addElement("flow-ref");
                    element.addAttribute("name", e.attribute("name").getValue());
                    addInterceptor(action, flow);
                }
            }
        }
    }

    protected void addInterceptor(Action action, Element e) {
        Element comp = e.addElement("component");
        Element obj = comp.addElement("singleton-object");
        obj.addAttribute("class", "org.mule.intents.TypeChecker");
        obj.addElement("property").addAttribute("key", "types").addAttribute("value",
                typesToString(action.getTemplate().getOutputTypes()));
        obj.addElement("property").addAttribute("key", "previousTemplate").addAttribute("value", action.getName());
    }

    private String typesToString(List<String> types) {
        StringBuilder buf = new StringBuilder();
        for (String type : types) {
            buf.append(type).append(",");
        }

        String t = buf.toString();
        return t.substring(0, t.length() - 1);
    }

    public Properties getAllParams() throws IOException {
        Properties params = new Properties();
        params.putAll(app.getTrigger().getParams());
        for (ActionConfig actionConfig : app.getActions()) {
            params.putAll(actionConfig.getParams());
        }

        return params;
    }

    protected void addNamespaces(Document snippet) {
        List<Namespace> ns = snippet.getRootElement().declaredNamespaces();
        for (Namespace n : ns) {
            config.getRootElement().add(n.detach());
        }
    }

    protected void addSchemaLocations(Document snippet) {
        Attribute att = snippet.getRootElement().attribute(xsiQN);
        if (att == null) {
            return;
        }

        Attribute existing = config.getRootElement().attribute(xsiQN);
        if (existing == null) {
            config.getRootElement().addAttribute(xsiQN, "");
            existing = config.getRootElement().attribute(xsiQN);
        }

        //save schemaLocations
        for (StringTokenizer tokenizer = new StringTokenizer(att.getValue(), " "); tokenizer.hasMoreTokens();) {
            String x = tokenizer.nextToken();
            String y = tokenizer.nextToken();
            schemaLocations.put(x, y);
        }

        StringBuilder buf = new StringBuilder();
        for (String s : schemaLocations.keySet()) {
            buf.append(s).append(" ").append(schemaLocations.get(s)).append("\n");
        }

        existing.setValue(buf.toString());

        System.out.println("xsi:schemaLocation = " + existing.getValue());
    }

    protected Document createMuleConfig() {
        DocumentFactory factory = DocumentFactory.getInstance();
        Element root = factory.createElement(new QName("mule", muleNS));
        root.addAttribute("version", app.getPlatformVersion());
        return DocumentFactory.getInstance().createDocument(root);
    }

    protected String convertConfigToString() throws IOException {
        OutputFormat format = OutputFormat.createPrettyPrint();
        StringWriter string = new StringWriter();
        XMLWriter writer = new XMLWriter(string, format);
        writer.write(getConfig());
        return string.toString();
    }

    protected void printDataTypes() {
        StringBuilder b = new StringBuilder();
        for (ContentType type : registry.getContentTypes().values()) {
            b.append("\n").append(type.toString());
        }
        System.out.println(b.toString());
    }
}