Package org.apache.felix.fileinstall.internal

Source Code of org.apache.felix.fileinstall.internal.FileInstall$ConfigAdminSupport$Tracker

/*
* 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.fileinstall.internal;

import java.io.File;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.felix.fileinstall.ArtifactInstaller;
import org.apache.felix.fileinstall.ArtifactListener;
import org.apache.felix.fileinstall.ArtifactTransformer;
import org.apache.felix.fileinstall.ArtifactUrlTransformer;
import org.apache.felix.fileinstall.internal.Util.Logger;
import org.apache.felix.utils.properties.InterpolationHelper;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.wiring.FrameworkWiring;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

/**
* This clever little bundle watches a directory and will install any jar file
* if finds in that directory (as long as it is a valid bundle and not a
* fragment).
*
*/
public class FileInstall implements BundleActivator, ServiceTrackerCustomizer
{
    Runnable cmSupport;
    final Map<ServiceReference, ArtifactListener> listeners = new TreeMap<ServiceReference, ArtifactListener>();
    final BundleTransformer bundleTransformer = new BundleTransformer();
    BundleContext context;
    final Map<String, DirectoryWatcher> watchers = new HashMap<String, DirectoryWatcher>();
    ServiceTracker listenersTracker;
    final ReadWriteLock lock = new ReentrantReadWriteLock();
    ServiceRegistration urlHandlerRegistration;
    volatile boolean stopped;

    public void start(BundleContext context) throws Exception
    {
        this.context = context;
        lock.writeLock().lock();

        try
        {
            Hashtable<String, Object> props = new Hashtable<String, Object>();
            props.put("url.handler.protocol", JarDirUrlHandler.PROTOCOL);
            urlHandlerRegistration = context.registerService(org.osgi.service.url.URLStreamHandlerService.class.getName(), new JarDirUrlHandler(), props);

            String flt = "(|(" + Constants.OBJECTCLASS + "=" + ArtifactInstaller.class.getName() + ")"
                    + "(" + Constants.OBJECTCLASS + "=" + ArtifactTransformer.class.getName() + ")"
                    + "(" + Constants.OBJECTCLASS + "=" + ArtifactUrlTransformer.class.getName() + "))";
            listenersTracker = new ServiceTracker(context, FrameworkUtil.createFilter(flt), this);
            listenersTracker.open();

            try
            {
                cmSupport = new ConfigAdminSupport(context, this);
            }
            catch (NoClassDefFoundError e)
            {
                Util.log(context, Logger.LOG_DEBUG,
                        "ConfigAdmin is not available, some features will be disabled", e);
            }

            // Created the initial configuration
            Hashtable<String, String> ht = new Hashtable<String, String>();

            set(ht, DirectoryWatcher.POLL);
            set(ht, DirectoryWatcher.DIR);
            set(ht, DirectoryWatcher.LOG_LEVEL);
            set(ht, DirectoryWatcher.FILTER);
            set(ht, DirectoryWatcher.TMPDIR);
            set(ht, DirectoryWatcher.START_NEW_BUNDLES);
            set(ht, DirectoryWatcher.USE_START_TRANSIENT);
            set(ht, DirectoryWatcher.NO_INITIAL_DELAY);
            set(ht, DirectoryWatcher.START_LEVEL);

            // check if dir is an array of dirs
            String dirs = ht.get(DirectoryWatcher.DIR);
            if (dirs != null && dirs.indexOf(',') != -1)
            {
                StringTokenizer st = new StringTokenizer(dirs, ",");
                int index = 0;
                while (st.hasMoreTokens())
                {
                    final String dir = st.nextToken().trim();
                    ht.put(DirectoryWatcher.DIR, dir);

                    String name = "initial";
                    if (index > 0) name = name + index;
                    updated(name, new Hashtable<String, String>(ht));

                    index++;
                }
            }
            else
            {
                updated("initial", ht);
            }
        }
        finally
        {
            // now notify all the directory watchers to proceed
            // We need this to avoid race conditions observed in FELIX-2791
            lock.writeLock().unlock();
        }
    }

    public Object addingService(ServiceReference serviceReference)
    {
        ArtifactListener listener = (ArtifactListener) context.getService(serviceReference);
        addListener(serviceReference, listener);
        return listener;
    }
    public void modifiedService(ServiceReference reference, Object service)
    {
        removeListener(reference, (ArtifactListener) service);
        addListener(reference, (ArtifactListener) service);
    }
    public void removedService(ServiceReference serviceReference, Object service)
    {
        removeListener(serviceReference, (ArtifactListener) service);
    }

    // Adapted for FELIX-524
    private void set(Hashtable<String, String> ht, String key)
    {
        String o = context.getProperty(key);
        if (o == null)
        {
           o = System.getProperty(key.toUpperCase().replace('.', '_'));
            if (o == null)
            {
                return;
            }
        }
        ht.put(key, o);
    }

    public void stop(BundleContext context) throws Exception
    {
        lock.writeLock().lock();
        try
        {
            urlHandlerRegistration.unregister();
            List<DirectoryWatcher> toClose = new ArrayList<DirectoryWatcher>();
            synchronized (watchers)
            {
                toClose.addAll(watchers.values());
                watchers.clear();
            }
            for (DirectoryWatcher aToClose : toClose)
            {
                try
                {
                    aToClose.close();
                }
                catch (Exception e)
                {
                    // Ignore
                }
            }
            if (listenersTracker != null)
            {
                listenersTracker.close();
            }
            if (cmSupport != null)
            {
                cmSupport.run();
            }
        }
        finally
        {
            stopped = true;
            lock.writeLock().unlock();
        }
    }

    public void deleted(String pid)
    {
        DirectoryWatcher watcher;
        synchronized (watchers)
        {
            watcher = watchers.remove(pid);
        }
        if (watcher != null)
        {
            watcher.close();
        }
    }

    public void updated(String pid, Map<String, String> properties)
    {
        InterpolationHelper.performSubstitution(properties, context);
        DirectoryWatcher watcher;
        synchronized (watchers)
        {
            watcher = watchers.get(pid);
            if (watcher != null && watcher.getProperties().equals(properties))
            {
                return;
            }
        }
        if (watcher != null)
        {
            watcher.close();
        }
        watcher = new DirectoryWatcher(this, properties, context);
        watcher.setDaemon(true);
        synchronized (watchers)
        {
            watchers.put(pid, watcher);
        }
        watcher.start();
    }

    public void updateChecksum(File file)
    {
        List<DirectoryWatcher> toUpdate = new ArrayList<DirectoryWatcher>();
        synchronized (watchers)
        {
            toUpdate.addAll(watchers.values());
        }
        for (DirectoryWatcher watcher : toUpdate)
        {
            watcher.scanner.updateChecksum(file);
        }
    }

    private void addListener(ServiceReference reference, ArtifactListener listener)
    {
        synchronized (listeners)
        {
            listeners.put(reference, listener);
        }
       
        long currentStamp = reference.getBundle().getLastModified();

        List<DirectoryWatcher> toNotify = new ArrayList<DirectoryWatcher>();
        synchronized (watchers)
        {
            toNotify.addAll(watchers.values());
        }
        for (DirectoryWatcher dir : toNotify)
        {
            dir.addListener(listener, currentStamp);
        }
    }

    private void removeListener(ServiceReference reference, ArtifactListener listener)
    {
        synchronized (listeners)
        {
            listeners.remove(reference);
        }
        List<DirectoryWatcher> toNotify = new ArrayList<DirectoryWatcher>();
        synchronized (watchers)
        {
            toNotify.addAll(watchers.values());
        }
        for (DirectoryWatcher dir : toNotify)
        {
            dir.removeListener(listener);
        }
    }

    List<ArtifactListener> getListeners()
    {
        synchronized (listeners)
        {
            List<ArtifactListener> l = new ArrayList<ArtifactListener>(listeners.values());
            Collections.reverse(l);
            l.add(bundleTransformer);
            return l;
        }
    }

    /**
     * Convenience to refresh the packages
     */
    static void refresh(BundleContext context, Collection<Bundle> bundles) throws InterruptedException
    {
        final CountDownLatch latch = new CountDownLatch(1);
        FrameworkWiring wiring = context.getBundle(0).adapt(FrameworkWiring.class);
        wiring.refreshBundles(bundles, new FrameworkListener() {
            public void frameworkEvent(FrameworkEvent event) {
                latch.countDown();
            }
        });
        latch.await();
    }

    private class ConfigAdminSupport implements Runnable
    {
        private Tracker tracker;
        private ServiceRegistration registration;

        private ConfigAdminSupport(BundleContext context, FileInstall fileInstall)
        {
            tracker = new Tracker(context, fileInstall);
            Hashtable<String, Object> props = new Hashtable<String, Object>();
            props.put(Constants.SERVICE_PID, tracker.getName());
            registration = context.registerService(ManagedServiceFactory.class.getName(), tracker, props);
            tracker.open();
        }

        public void run()
        {
            tracker.close();
            registration.unregister();
        }

        private class Tracker extends ServiceTracker<ConfigurationAdmin, ConfigurationAdmin> implements ManagedServiceFactory {

            private final FileInstall fileInstall;
            private final Set<String> configs = Collections.synchronizedSet(new HashSet<String>());
            private final Map<Long, ConfigInstaller> configInstallers = new HashMap<Long, ConfigInstaller>();

            private Tracker(BundleContext bundleContext, FileInstall fileInstall)
            {
                super(bundleContext, ConfigurationAdmin.class.getName(), null);
                this.fileInstall = fileInstall;
            }

            public String getName()
            {
                return "org.apache.felix.fileinstall";
            }

            public void updated(String s, Dictionary<String, ?> dictionary) throws ConfigurationException
            {
                configs.add(s);
                Map<String, String> props = new HashMap<String, String>();
                for (Enumeration<String> e = dictionary.keys(); e.hasMoreElements();) {
                    String k = e.nextElement();
                    props.put(k, dictionary.get(k).toString());
                }
                fileInstall.updated(s, props);
            }

            public void deleted(String s)
            {
                configs.remove(s);
                fileInstall.deleted(s);
            }

            public ConfigurationAdmin addingService(ServiceReference<ConfigurationAdmin> serviceReference)
            {
                lock.writeLock().lock();
                try
                {
                    if (stopped) {
                        return null;
                    }
                    ConfigurationAdmin cm = super.addingService(serviceReference);
                    long id = (Long) serviceReference.getProperty(Constants.SERVICE_ID);
                    ConfigInstaller configInstaller = new ConfigInstaller(this.context, cm, fileInstall);
                    configInstaller.init();
                    configInstallers.put(id, configInstaller);
                    return cm;
                }
                finally
                {
                    lock.writeLock().unlock();
                }
            }

            public void removedService(ServiceReference<ConfigurationAdmin> serviceReference, ConfigurationAdmin o)
            {
                lock.writeLock().lock();
                try
                {
                    if (stopped) {
                        return;
                    }
                    Iterator iterator = configs.iterator();
                    while (iterator.hasNext())
                    {
                        String s = (String) iterator.next();
                        fileInstall.deleted(s);
                        iterator.remove();
                    }
                    long id = (Long) serviceReference.getProperty(Constants.SERVICE_ID);
                    ConfigInstaller configInstaller = configInstallers.remove(id);
                    if (configInstaller != null)
                    {
                        configInstaller.destroy();
                    }
                    super.removedService(serviceReference, o);
                }
                finally
                {
                    lock.writeLock().unlock();
                }
            }
        }
    }

}
TOP

Related Classes of org.apache.felix.fileinstall.internal.FileInstall$ConfigAdminSupport$Tracker

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.