All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.coos.messaging.PluginFactory Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
/**
 * COOS - Connected Objects Operating System (www.connectedobjects.org).
 *
 * Copyright (C) 2009 Telenor ASA and Tellu AS. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 * You may also contact one of the following for additional information:
 * Telenor ASA, Snaroyveien 30, N-1331 Fornebu, Norway (www.telenor.no)
 * Tellu AS, Hagalokkveien 13, N-1383 Asker, Norway (www.tellu.no)
 */
package org.coos.messaging;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import org.coos.messaging.impl.DefaultChannel;
import org.coos.messaging.serializer.ObjectJavaSerializer;
import org.coos.messaging.util.URIHelper;
import org.coos.messaging.util.UuidHelper;

import org.coos.pluginXMLSchema.ChannelType;
import org.coos.pluginXMLSchema.FilterType;
import org.coos.pluginXMLSchema.InBoundType;
import org.coos.pluginXMLSchema.OutBoundType;
import org.coos.pluginXMLSchema.PluginType;
import org.coos.pluginXMLSchema.PluginsDocument;
import org.coos.pluginXMLSchema.PluginsType;
import org.coos.pluginXMLSchema.ProcessorType;
import org.coos.pluginXMLSchema.PropertyType;
import org.coos.pluginXMLSchema.TransportType;

import org.coos.util.macro.MacroSubstituteReader;


/**
 * Factory for Plugin instances
 *
 * @author Knut Eilif Husa, Tellu AS
 */
public class PluginFactory extends COFactory {

    public static final String JVM_TRANSPORT_CLASS = "org.coos.messaging.transport.JvmTransport";
    public static final String PLUGIN_CHANNEL_CLASS = "org.coos.messaging.plugin.PluginChannel";

    private static Map sharedProcessors = new HashMap();
    private static Map processorTypes = new HashMap();


    private PluginFactory() {
    	SerializerFactory.registerSerializer(Message.SERIALIZATION_METHOD_JAVA, new ObjectJavaSerializer()); 
    }

    // Used in tests only
    public static Plugin createPlugin(String name, String className, String segment, String coosInstanceName, String channelServerName)
        throws Exception {

        COContainer cl = new COContainer() {

                public Class loadClass(String className) throws ClassNotFoundException {
                    return Class.forName(className);
                }

                public InputStream getResource(String resourceName) throws IOException {
                    InputStream is = COContainer.class.getResourceAsStream(resourceName);

                    return substitute(is);
                }

                public Object getObject(String name) {
                    return null;
                }

                public void start() {
                }

                public void stop() {
                }
            };

        Plugin plugin = new Plugin();

        Class pluginClass = PluginFactory.tryClass(cl, className);
        Endpoint endpoint = (Endpoint) pluginClass.newInstance();
        endpoint.setCoContainer(cl);
        if(name.matches(".*\\.")){
    		throw new Exception("Name :"+ name + " not allowed. '.' is reserved for separating segments");
    	}
        endpoint.setEndpointUri("coos://" + name);
        endpoint.setProperties(new Hashtable());
        plugin.setEndpoint(endpoint);

        URIHelper helper = new URIHelper(endpoint.getEndpointUri());

        if (helper.isEndpointUuid()) {
            endpoint.setEndpointUuid(name);
        }

        endpoint.setName(name);

        if (segment == null) {
            segment = ".";
        }

        Class channelClass = PluginFactory.tryClass(cl, PLUGIN_CHANNEL_CLASS);
        DefaultChannel channel = (DefaultChannel) channelClass.newInstance();
        channel.addProtocol("coos");
        channel.setCoContainer(cl);
        channel.setSegment(segment);
        plugin.addChannel(channel);

        Hashtable properties = new Hashtable();

        if (coosInstanceName != null)
            properties.put("COOSInstanceName", coosInstanceName);

        properties.put("ChannelServerName", channelServerName);

        Class transportClass = PluginFactory.tryClass(cl, JVM_TRANSPORT_CLASS);
        Transport transport = (Transport) transportClass.newInstance();
        transport.setProperties(properties);
        channel.setTransport(transport);

        return plugin;
    }


    // Used in tests only
    public static Plugin[] createPlugins(InputStream config) throws Exception {


        PluginsDocument doc = PluginsDocument.Factory.parse(config);
        COContainer cl = new COContainer() {

                public Class loadClass(String className) throws ClassNotFoundException {
                    return Class.forName(className);
                }

                public InputStream getResource(String resourceName) throws IOException {
                    InputStream is = COContainer.class.getResourceAsStream(resourceName);

                    return substitute(is);
                }

                public Object getObject(String name) {
                    return null;
                }

                @Override public void start() {
                }

                @Override public void stop() {
                }
            };

        Plugin[] plugins = instantiate(doc.getPlugins(), cl);

        return plugins;
    }

    private static InputStream substitute(InputStream is) throws IOException {
        InputStreamReader isr = new InputStreamReader(is);
        MacroSubstituteReader msr = new MacroSubstituteReader(isr);
        String substituted = msr.substituteMacros();
        is = new ByteArrayInputStream(substituted.getBytes());

        return is;
    }

    public static Plugin[] createPlugins(InputStream config, COContainer cl) throws Exception {

        // XmlOptions options = new XmlOptions();
        PluginsDocument doc = PluginsDocument.Factory.parse(config);
        Plugin[] plugins = instantiate(doc.getPlugins(), cl);

        return plugins;
    }

    private static Plugin[] instantiate(PluginsType model, COContainer cl) throws Exception {
        Plugin[] res = new Plugin[model.getPluginArray().length];

        // processors
        for (int i = 0; i < model.getProcessorArray().length; i++) {
            ProcessorType processorType = model.getProcessorArray()[i];

            if ((processorType.getName() == null) || (processorType.getClass1() == null)) {
                throw new Exception("Plugin processors must have a name and a implementing class. Must be defined!");
            }

            String name = processorType.getName();
            processorTypes.put(name, processorType);

            Processor processor = instantiateProcessor(processorType, cl);

            if (processor.isShared()) {
                sharedProcessors.put(name, processor);
            }
        }

        HashMap transportMap = new HashMap();

        // transports
        for (int i = 0; i < model.getTransportArray().length; i++) {
            TransportType transportType = model.getTransportArray()[i];

            if ((transportType.getName() == null) || (transportType.getClass1() == null)) {
                throw new Exception("Plugin transports must have a name and an implementing class. Must be defined!");
            }

            String name = transportType.getName();
            String className = transportType.getClass1();
            Map props = new HashMap();

            for (int j = 0; j < transportType.getPropertyArray().length; j++) {
                PropertyType propertyType = transportType.getPropertyArray()[j];

                if ((propertyType.getName() == null) || (propertyType.getValue() == null)) {
                    throw new Exception("Plugin properties must have a name and a value. Must be defined!");
                }

                props.put(propertyType.getName(), propertyType.getValue());
            }

            Class transportClass = PluginFactory.tryClass(cl, className);
            Transport transport = (Transport) transportClass.newInstance();
            transport.setName(name);
            transport.setCoContainer(cl);
            transport.setProperties(new Hashtable(props));
            transportMap.put(name, transport);
        }

        // channels
        HashMap channelMap = new HashMap();

        for (int i = 0; i < model.getChannelArray().length; i++) {
            ChannelType channelType = model.getChannelArray()[i];

            if ((channelType.getName() == null) || (channelType.getClass1() == null)) {
                throw new Exception("Plugin channels must have a name and an implementing class. Must be defined!");
            }

            String name = channelType.getName();
            String className = channelType.getClass1();
            String protocol = channelType.getProtocol2();
            String segment = channelType.getSegment();
            Class channelClass = PluginFactory.tryClass(cl, className);
            Channel channel = (Channel) channelClass.newInstance();
            channel.setCoContainer(cl);

            if (protocol != null) {
                channel.addProtocol(protocol);
            } else {
                channel.addProtocol("coos"); //The default protocol
            }

            channel.setName(name);

            if (segment != null) {
                channel.setSegment(segment);
            }

            Map props = new HashMap();

            for (int j = 0; j < channelType.getPropertyArray().length; j++) {
                PropertyType propertyType = channelType.getPropertyArray()[j];

                if ((propertyType.getName() == null) || (propertyType.getValue() == null)) {
                    throw new Exception("Plugin properties must have a name and a value. Must be defined!");
                }

                props.put(propertyType.getName(), propertyType.getValue());
            }

            channel.setProperties(new Hashtable(props));

            for (int j = 0; j < channelType.getProtocolArray().length; j++) {
                String prot = channelType.getProtocolArray()[j];
                channel.addProtocol(prot);
            }

            String transportType = channelType.getTransport();

            if (transportType != null) {

                if (!transportMap.keySet().contains(transportType)) {
                    throw new Exception("Transport " + transportType + " is not declared.");
                }

                channel.setTransport((Transport) transportMap.get(transportType).copy());
            } else {
                Class transportClass = PluginFactory.tryClass(cl, JVM_TRANSPORT_CLASS);
                Transport transport = (Transport) transportClass.newInstance();
                transport.setCoContainer(cl);
                channel.setTransport(transport);
            }

            OutBoundType outBoundType = channelType.getOutBound();

            if (outBoundType != null) {

                for (int j = 0; j < outBoundType.getFilterArray().length; j++) {
                    FilterType filterType = outBoundType.getFilterArray()[j];
                    String processor = filterType.getProcessor();
                    ProcessorType procType = processorTypes.get(processor);

                    if (procType == null) {
                        throw new Exception("Processor " + processor + " is not declared.");
                    }

                    if (procType.getShared()) {
                        channel.getOutLink().addFilterProcessor(sharedProcessors.get(processor));
                    } else {
                        channel.getOutLink().addFilterProcessor(instantiateProcessor(procType, cl));
                    }
                }
            }

            InBoundType inBoundType = channelType.getInBound();

            if (inBoundType != null) {

                for (int j = 0; j < inBoundType.getFilterArray().length; j++) {
                    FilterType filterType = inBoundType.getFilterArray()[j];
                    String processor = filterType.getProcessor();
                    ProcessorType procType = processorTypes.get(processor);

                    if (procType == null) {
                        throw new Exception("Processor " + processor + " is not declared.");
                    }

                    if (procType.getShared()) {
                        channel.getInLink().addFilterProcessor(sharedProcessors.get(processor));
                    } else {
                        channel.getInLink().addFilterProcessor(instantiateProcessor(procType, cl));
                    }
                }
            }

            channelMap.put(name, channel);
        }

        // Plugins
        for (int i = 0; i < model.getPluginArray().length; i++) {

            Plugin plugin = new Plugin();

            PluginType pluginType = model.getPluginArray()[i];

            if (pluginType.getClass1() == null) {
                throw new Exception("Plugin properties must have a name and a value. Must be defined!");
            }

            String className = pluginType.getClass1();
            Class pluginClass = PluginFactory.tryClass(cl, className);
            Endpoint endpoint = (Endpoint) pluginClass.newInstance();

            endpoint.setCoContainer(cl);

            String name = pluginType.getName();
            String nameSegment = "";

            if (name != null && !name.equals("")) {
            	
            	if(name.matches(".*\\.")){
            		throw new Exception("Name :"+ name + " not allowed. '.' is reserved for separating segments");
            	}
            	
                if (UuidHelper.isUuid(name)) {
                    name = UuidHelper.getQualifiedUuid(name);
                    endpoint.setEndpointUuid(name);
                    endpoint.setEndpointUri("coos://" + name);
                    nameSegment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(name);
                } else {
                    endpoint.setEndpointUri("coos://" + name);

                    URIHelper uHelper = new URIHelper(endpoint.getEndpointUri());
                    nameSegment = uHelper.getSegment();
                }

                endpoint.setName(name); // the alias
            }

            String channelName = pluginType.getChannel2();
            String startLevelStr = pluginType.getStartLevel();

            if (startLevelStr != null) {
                plugin.setStartLevel(Integer.valueOf(startLevelStr));
            }

            String[] aliases = pluginType.getAliasArray();

            for (int j = 0; j < aliases.length; j++) {
                endpoint.addAlias(aliases[j]);
            }

            if ((channelName == null) && (pluginType.getChannelArray().length == 0)) {

                // Always add the PluginChannel
                Class channelClass1 = PluginFactory.tryClass(cl, PLUGIN_CHANNEL_CLASS);
                Channel channel1 = (Channel) channelClass1.newInstance();
                channel1.addProtocol("coos");
                channel1.setCoContainer(cl);
                channel1.setName("default");
                channelMap.put("default", channel1);

                String transportType = pluginType.getTransport();

                if (transportType != null) {

                    if (!transportMap.keySet().contains(transportType)) {
                        throw new Exception("Transport " + transportType + " is not declared.");
                    }

                    channel1.setTransport(transportMap.get(transportType));
                } else {
                    Class transportClass1 = PluginFactory.tryClass(cl, JVM_TRANSPORT_CLASS);
                    Transport transport1 = (Transport) transportClass1.newInstance();
                    transport1.setCoContainer(cl);
                    channel1.setTransport(transport1);
                }

                plugin.addChannel((Channel) channelMap.get("default").copy());
            }

            if (channelName != null) {
                addChannel(channelMap, plugin, name, nameSegment, channelName);
            }

            for (int j = 0; j < pluginType.getChannelArray().length; j++) {
                channelName = pluginType.getChannelArray(j);
                addChannel(channelMap, plugin, name, nameSegment, channelName);
            }

            Map props = new HashMap();

            for (int k = 0; k < pluginType.getPropertyArray().length; k++) {
                PropertyType propertyType = pluginType.getPropertyArray()[k];

                if ((propertyType.getName() == null) || (propertyType.getValue() == null)) {
                    throw new Exception("Plugin properties must have a name and a value. Must be defined!");
                }

                props.put(propertyType.getName(), propertyType.getValue());
            }

            endpoint.setProperties(new Hashtable(props));
            plugin.setEndpoint(endpoint);

            res[i] = plugin;
        }

        return res;
    }

    private static void addChannel(HashMap channelMap, Plugin plugin, String name, String nameSegment, String channelName)
        throws Exception {

        if (!channelMap.keySet().contains(channelName)) {
            throw new Exception("Channel " + channelName + " is not declared for plugin: " + name);
        }

        Channel channel = (Channel) channelMap.get(channelName).copy();

        if (!nameSegment.equals("")) {

            if (channel.getSegment().equals("")) {

                //use namesegment as channelsegment
                channel.setSegment(nameSegment);
            } else if (!channel.getSegment().equals(nameSegment)) {

                //if different they must match
                throw new Exception("Channel " + channelName + " with segment '" + channel.getSegment() +
                    "' does not match segment declared for plugin: " + name);
            }
        }

        plugin.addChannel(channel);
    }

    private static Processor instantiateProcessor(ProcessorType processorType, COContainer cl) throws Exception {
        String className = processorType.getClass1();
        boolean isShared = processorType.getShared();
        String name = processorType.getName();
        Map props = new HashMap();

        for (int j = 0; j < processorType.getPropertyArray().length; j++) {
            PropertyType propertyType = processorType.getPropertyArray()[j];

            if ((propertyType.getName() == null) || (propertyType.getValue() == null)) {
                throw new Exception("COOS properties must have a name and a value. Must be defined!");
            }

            props.put(propertyType.getName(), propertyType.getValue());
        }

        Class procClass = PluginFactory.tryClass(cl, className);
        Processor processor = (Processor) procClass.newInstance();
        processor.setCoContainer(cl);
        processor.setName(name);
        processor.setProperties(new Hashtable(props));
        processor.setShared(isShared);

        return processor;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy