Package org.apache.felix.webconsole.plugins.scriptconsole.internal

Source Code of org.apache.felix.webconsole.plugins.scriptconsole.internal.ScriptEngineManager$ScriptEngineFactoryState

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.felix.webconsole.plugins.scriptconsole.internal;

import org.apache.commons.io.IOUtils;
import org.osgi.framework.*;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* It is based on org.apache.sling.scripting.core.impl.ScriptEngineManagerFactory
*/
class ScriptEngineManager implements BundleListener, ServiceTrackerCustomizer
{
    private static final String ENGINE_FACTORY_SERVICE = "META-INF/services/"
        + ScriptEngineFactory.class.getName();
    private final Set<Bundle> engineSpiBundles = new HashSet<Bundle>();
    private final Map<ServiceReference, ScriptEngineFactoryState> engineSpiServices
            = new ConcurrentHashMap<ServiceReference, ScriptEngineFactoryState>();

    private final Logger log;
    private EngineManagerState state = new EngineManagerState();

    /**
     * ServiceTracker for ScriptEngineFactory
     */
    private ServiceTracker scriptFactoryTracker;
    private final BundleContext context;

    public ScriptEngineManager(BundleContext context, Logger logger)
    {
        this.log = logger;
        this.context = context;

        this.context.addBundleListener(this);

        Bundle[] bundles = this.context.getBundles();
        synchronized (this.engineSpiBundles) {
            for (Bundle bundle : bundles) {
                if (bundle.getState() == Bundle.ACTIVE
                        && bundle.getEntry(ENGINE_FACTORY_SERVICE) != null) {
                    this.engineSpiBundles.add(bundle);
                }
            }
        }

        // create a script engine manager
        this.refreshScriptEngineManager();

        this.scriptFactoryTracker = new ServiceTracker(context,
            ScriptEngineFactory.class.getName(), this);
        this.scriptFactoryTracker.open();
    }

    public List<ScriptEngineFactory> getEngineFactories()
    {
        return state.factories;
    }

    public ScriptEngine getEngineByExtension(String extension) {
        ScriptEngineFactory factory = state.extensionAssociations.get(extension);
        if (factory == null) return null;

        ScriptEngine engine = factory.getScriptEngine();

        //We do not support global scope for now
        //engine.setBindings(globalScope, ScriptContext.GLOBAL_SCOPE);

        return engine;
    }

    // ---------- BundleListener interface -------------------------------------

    public void bundleChanged(BundleEvent event)
    {
        if (event.getType() == BundleEvent.STARTED
            && event.getBundle().getEntry(ENGINE_FACTORY_SERVICE) != null)
        {
            synchronized (this.engineSpiBundles)
            {
                this.engineSpiBundles.add(event.getBundle());
            }
            this.refreshScriptEngineManager();
        }
        else if (event.getType() == BundleEvent.STOPPED)
        {
            boolean refresh;
            synchronized (this.engineSpiBundles)
            {
                refresh = this.engineSpiBundles.remove(event.getBundle());
            }
            if (refresh)
            {
                this.refreshScriptEngineManager();
            }
        }
    }

    // ---------- ServiceTrackerCustomizer interface -------------------------------------

    public Object addingService(ServiceReference reference) {
        ScriptEngineFactory service = (ScriptEngineFactory) context.getService(reference);
        engineSpiServices.put(reference,new ScriptEngineFactoryState(service,getServiceProperties(reference)));
        refreshScriptEngineManager();
        return service;
    }

    public void modifiedService(ServiceReference reference, Object service)
    {
        ScriptEngineFactoryState state = engineSpiServices.get(reference);
        state.properties = getServiceProperties(reference);
        refreshScriptEngineManager();
    }

    public void removedService(ServiceReference reference, Object service)
    {
        context.ungetService(reference);
        engineSpiServices.remove(reference);
        refreshScriptEngineManager();

    }

    private void refreshScriptEngineManager()
    {
        EngineManagerState tmp = new EngineManagerState();
        // register script engines from bundles
        final SortedSet<Object> extensions = new TreeSet<Object>();
        synchronized (this.engineSpiBundles)
        {
            for (final Bundle bundle : this.engineSpiBundles)
            {
                extensions.addAll(registerFactories(tmp, bundle));
            }
        }

        // register script engines from registered services
        synchronized (this.engineSpiServices)
        {
            for (final ScriptEngineFactoryState state : this.engineSpiServices.values())
            {
                extensions.addAll(registerFactory(tmp, state.scriptEngineFactory,
                    state.properties));
            }
        }

        synchronized (this){
            this.state = tmp;
        }
    }

    @SuppressWarnings("unchecked")
    private Collection<?> registerFactories(final EngineManagerState mgr,
        final Bundle bundle)
    {
        URL url = bundle.getEntry(ENGINE_FACTORY_SERVICE);
        InputStream ins = null;
        final SortedSet<String> extensions = new TreeSet<String>();
        try
        {
            ins = url.openStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(ins));
            String line;
            while ((line = reader.readLine()) != null)
            {
                if (!line.startsWith("#") && line.trim().length() > 0)
                {
                    try
                    {
                        Class<ScriptEngineFactory> clazz = bundle.loadClass(line);
                        ScriptEngineFactory spi = clazz.newInstance();
                        registerFactory(mgr, spi, null);
                        extensions.addAll(spi.getExtensions());
                    }
                    catch (Throwable t)
                    {
                        log.log(LogService.LOG_ERROR,
                            "Cannot register ScriptEngineFactory " + line, t);
                    }
                }
            }
        }
        catch (IOException ioe)
        {
            // ignore
        }
        finally
        {
            IOUtils.closeQuietly(ins);
        }

        return extensions;
    }

    private Collection<?> registerFactory(final EngineManagerState mgr,
        final ScriptEngineFactory factory, final Map<Object, Object> props)
    {
        log.log(
            LogService.LOG_INFO,
            String.format("Adding ScriptEngine %s, %s for language %s, %s",
                factory.getEngineName(), factory.getEngineVersion(),
                factory.getLanguageName(), factory.getLanguageVersion()));

        mgr.factories.add(factory);
        mgr.factoryProperties.put(factory, props);
        for (Object ext : factory.getExtensions()) {
            mgr.extensionAssociations.put((String) ext, factory);
        }
        return factory.getExtensions();
    }

    public void dispose()
    {
        if (scriptFactoryTracker != null)
        {
            scriptFactoryTracker.close();
        }
    }

    private static Map<Object, Object> getServiceProperties(ServiceReference reference)
    {
        Map<Object, Object> props = new HashMap<Object, Object>();
        for (String key : reference.getPropertyKeys())
        {
            props.put(key, reference.getProperty(key));
        }
        return props;
    }

    private static class ScriptEngineFactoryState
    {
        final ScriptEngineFactory scriptEngineFactory;
        Map<Object, Object> properties;

        private ScriptEngineFactoryState(ScriptEngineFactory scriptEngineFactory, Map<Object, Object> properties)
        {
            this.scriptEngineFactory = scriptEngineFactory;
            this.properties = properties;
        }
    }

    private static class EngineManagerState
    {
        private final List<ScriptEngineFactory> factories = new ArrayList<ScriptEngineFactory>();
        private final Map<ScriptEngineFactory, Map<Object, Object>> factoryProperties
                            = new HashMap<ScriptEngineFactory, Map<Object, Object>>();
        private final Map<String, ScriptEngineFactory> extensionAssociations
                            = new HashMap<String, ScriptEngineFactory>();

    }
}
TOP

Related Classes of org.apache.felix.webconsole.plugins.scriptconsole.internal.ScriptEngineManager$ScriptEngineFactoryState

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.