Package org.eclipse.sapphire.modeling.internal

Source Code of org.eclipse.sapphire.modeling.internal.SapphireModelingExtensionSystem$ServiceExtension

/******************************************************************************
* Copyright (c) 2014 Oracle
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Konstantin Komissarchik - initial implementation and ongoing maintenance
******************************************************************************/

package org.eclipse.sapphire.modeling.internal;

import static org.eclipse.sapphire.Result.failure;
import static org.eclipse.sapphire.Result.success;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.eclipse.sapphire.Context;
import org.eclipse.sapphire.LoggingService;
import org.eclipse.sapphire.Result;
import org.eclipse.sapphire.Sapphire;
import org.eclipse.sapphire.modeling.ExtensionsLocator;
import org.eclipse.sapphire.modeling.el.Function;
import org.eclipse.sapphire.services.Service;
import org.eclipse.sapphire.services.ServiceCondition;
import org.eclipse.sapphire.util.ListFactory;
import org.eclipse.sapphire.util.SetFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;

/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/

public final class SapphireModelingExtensionSystem
{
    private static final String EL_CONDITION = "condition";
    private static final String EL_CONTEXT = "context";
    private static final String EL_FUNCTION = "function";
    private static final String EL_ID = "id";
    private static final String EL_IMPL = "impl";
    private static final String EL_IMPLEMENTATION = "implementation";
    private static final String EL_NAME = "name";
    private static final String EL_OVERRIDES = "overrides";
    private static final String EL_PARAMETER = "parameter";
    private static final String EL_SERVICE = "service";
    private static final String EL_SIGNATURE = "signature";
   
    private static boolean initialized = false;
    private static List<ServiceExtension> serviceExtensions;
    private static Map<String,List<FunctionFactory>> functionFactories;

    public static List<ServiceExtension> services()
    {
        initialize();
        return serviceExtensions;
    }
   
    public static List<Function> functions( final String name, final int arity )
    {
        initialize();

        final List<FunctionFactory> factories = functionFactories.get( name.toLowerCase() );
        final ListFactory<Function> functions = ListFactory.start();

        if( factories != null )
        {
            for( FunctionFactory factory : factories )
            {
                if( factory.signature() == null || factory.signature().size() == arity )
                {
                    functions.add( factory.create() );
                }
            }
        }
       
        return functions.result();
    }
   
    private static synchronized void initialize()
    {
        if( ! initialized )
        {
            initialized = true;
            functionFactories = new HashMap<String,List<FunctionFactory>>();
           
            final ListFactory<ServiceExtension> serviceExtensionsFactory = ListFactory.start();

            for( final ExtensionsLocator.Handle handle : ExtensionsLocator.instance().find() )
            {
                final Element root = parse( handle.extension() );

                if( root != null )
                {
                    final NodeList nodes = root.getChildNodes();
                    final Context context = handle.context();

                    for( int i = 0, n = nodes.getLength(); i < n; i++ )
                    {
                        final Node node = nodes.item( i );

                        if( node instanceof Element )
                        {
                            final Element el = (Element) node;
                            final String elname = el.getLocalName();

                            try
                            {
                                if( elname.equals( EL_SERVICE ) )
                                {
                                    final String id = value( el, EL_ID ).required();
                                    final Set<String> contexts = SetFactory.unmodifiable( values( el, EL_CONTEXT ) );
                                    final Set<String> overrides = SetFactory.unmodifiable( values( el, EL_OVERRIDES ) );
                                   
                                    final Class<? extends Service> implementation = context.findClass( value( el, EL_IMPLEMENTATION ).required() );
                                   
                                    final String conditionClassName = value( el, EL_CONDITION ).optional();
                                    Class<? extends ServiceCondition> condition = null;
                                   
                                    if( conditionClassName != null )
                                    {
                                        condition = context.findClass( conditionClassName );
                                    }
                                   
                                    if( implementation != null )
                                    {
                                        serviceExtensionsFactory.add( new ServiceExtension( id, implementation, condition, contexts, overrides ) );
                                    }
                                }
                                else if( elname.equals( EL_FUNCTION ) )
                                {
                                    final String name = value( el, EL_NAME ).required().toLowerCase();
                                    final Class<? extends Function> impl = context.findClass( value( el, EL_IMPL ).required() );
                                   
                                    final Element signatureElement = element( el, EL_SIGNATURE ).optional();
                                    final List<Class<?>> signature;
                                   
                                    if( signatureElement == null )
                                    {
                                        signature = null;
                                    }
                                    else
                                    {
                                        final ListFactory<Class<?>> parameters = ListFactory.start();
                                       
                                        for( String string : values( signatureElement, EL_PARAMETER ) )
                                        {
                                            final Class<?> parameter;
                                           
                                            try
                                            {
                                                parameter = context.findClass( string );
                                            }
                                            catch( IllegalArgumentException e )
                                            {
                                                throw new InvalidExtensionException();
                                            }
                                           
                                            if( parameter == null )
                                            {
                                                throw new InvalidExtensionException();
                                            }
                                           
                                            parameters.add( parameter );
                                        }
                                       
                                        signature = parameters.result();
                                    }
                                   
                                    final ListFactory<FunctionFactory> factories = ListFactory.start();
                                   
                                    factories.add( functionFactories.get( name ) );
                                    factories.add( new FunctionFactory( impl, signature ) );
                                   
                                    functionFactories.put( name, factories.result() );
                                }
                            }
                            catch( InvalidExtensionException e ) {}
                        }
                    }
                }
            }
           
            serviceExtensions = serviceExtensionsFactory.result();
        }
    }
   
    private static Element parse( final URL url )
    {
        try
        {
            final InputStream in = url.openStream();

            try
            {
                final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

                factory.setValidating( false );
                factory.setNamespaceAware( true );
                factory.setIgnoringComments( false );

                final DocumentBuilder docbuilder = factory.newDocumentBuilder();

                docbuilder.setEntityResolver
                (
                    new EntityResolver()
                    {
                        public InputSource resolveEntity( final String publicID,
                                                          final String systemID )
                        {
                            return new InputSource( new StringReader( "" ) );
                        }
                    }
                );

                final Document document = docbuilder.parse( in );

                return document.getDocumentElement();
            }
            finally
            {
                try
                {
                    in.close();
                }
                catch( IOException e ) {}
            }
        }
        catch( Exception e )
        {
            // TODO: Log the problem.
            return null;
        }
    }

    private static String value( final Element element )
    {
        final StringBuilder buf = new StringBuilder();
        final NodeList nodes = element.getChildNodes();
   
        for( int i = 0, n = nodes.getLength(); i < n; i++ )
        {
            final Node node = nodes.item( i );
   
            if( node instanceof org.w3c.dom.Text )
            {
                buf.append( ( (org.w3c.dom.Text) node ).getData() );
            }
        }
   
        return buf.toString().trim();
    }
   
    private static Result<String> value( final Element element, final String valueElementName )
    {
        final Element el = element( element, valueElementName ).optional();
       
        if( el != null )
        {
            return success( value( el ) );
        }
       
        return failure( new InvalidExtensionException() );
    }

    private static List<String> values( final Element root, final String entryElementName )
    {
        final ListFactory<String> factory = ListFactory.start();
        final NodeList nodes = root.getChildNodes();
   
        for( int i = 0, n = nodes.getLength(); i < n; i++ )
        {
            final Node node = nodes.item( i );
   
            if( node instanceof Element && node.getLocalName().equals( entryElementName ) )
            {
                final String text = value( (Element) node );
               
                if( text.length() > 0 )
                {
                    factory.add( text );
                }
            }
        }
       
        return factory.result();
    }
   
    private static Result<Element> element( final Element element, final String childElementName )
    {
        final NodeList nodes = element.getChildNodes();

        for( int i = 0, n = nodes.getLength(); i < n; i++ )
        {
            final Node node = nodes.item( i );

            if( node instanceof Element )
            {
                final Element el = (Element) node;

                if( childElementName.equals( el.getLocalName() ) )
                {
                    return success( el );
                }
            }
        }
       
        return failure( new InvalidExtensionException() );
    }

    public static final class InvalidExtensionException extends RuntimeException
    {
        private static final long serialVersionUID = 1L;
    }
   
    public static final class ServiceExtension
    {
        private final String id;
        private final Class<? extends Service> implementation;
        private final Class<? extends ServiceCondition> condition;
        private final Set<String> contexts;
        private final Set<String> overrides;
       
        public ServiceExtension( final String id,
                                 final Class<? extends Service> implementation,
                                 final Class<? extends ServiceCondition> condition,
                                 final Set<String> contexts,
                                 final Set<String> overrides )
        {
            this.id = id;
            this.implementation = implementation;
            this.condition = condition;
            this.contexts = contexts;
            this.overrides = overrides;
        }
       
        public String id()
        {
            return this.id;
        }
       
        public Class<? extends Service> implementation()
        {
            return this.implementation;
        }
       
        public Class<? extends ServiceCondition> condition()
        {
            return this.condition;
        }
       
        public Set<String> contexts()
        {
            return this.contexts;
        }
       
        public Set<String> overrides()
        {
            return this.overrides;
        }
    }

    private static final class FunctionFactory
    {
        private final Class<? extends Function> functionClass;
        private boolean functionInstantiationFailed;
        private final List<Class<?>> signature;

        public FunctionFactory( final Class<? extends Function> functionClass,
                                final List<Class<?>> signature )
        {
            this.functionClass = functionClass;
            this.signature = signature;
        }
       
        public List<Class<?>> signature()
        {
            return this.signature;
        }

        public Function create()
        {
            Function function = null;

            if( ! this.functionInstantiationFailed )
            {
                try
                {
                    function = this.functionClass.newInstance();
                    function.initSignature( this.signature );
                }
                catch( Exception e )
                {
                    Sapphire.service( LoggingService.class ).log( e );
                    function = null;
                    this.functionInstantiationFailed = true;
                }
            }

            return function;
        }
    }

}
TOP

Related Classes of org.eclipse.sapphire.modeling.internal.SapphireModelingExtensionSystem$ServiceExtension

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.