it.txt.ens.client.subscriber.printer.osgi.Activator.java Source code

Java tutorial

Introduction

Here is the source code for it.txt.ens.client.subscriber.printer.osgi.Activator.java

Source

/***************************************************************************
 * Copyright 2012-2013 TXT e-solutions SpA
 * Licensed 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.
 * 
 * This work was performed within the IoT@Work Project
 * and partially funded by the contract ICT-257367.
 *
 * Authors:
 *      Salvatore Piccione (TXT e-solutions SpA)
 *
 * Contributors:
 *        Domenico Rotondi (TXT e-solutions SpA)
 **************************************************************************/
package it.txt.ens.client.subscriber.printer.osgi;

import it.txt.ens.client.subscriber.ENSSubscriber;
import it.txt.ens.client.subscriber.osgi.RegisteredServices;
import it.txt.ens.client.subscriber.printer.ENSEventPrinterImpl;
import it.txt.ens.core.ENSResource;
import it.txt.ens.core.factory.ENSResourceFactory;
import it.txt.ens.core.factory.URIParseException;
import it.txt.ens.core.util.converter.MapConverter;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ConfigurationException;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;

/**
 * @author Salvatore Piccione (TXT e-solutions SpA - salvatore.piccione AT txtgroup.com)
 * @author Domenico Rotondi (TXT e-solutions SpA - domenico.rotondi AT txtgroup.com)
 *
 */
public class Activator implements BundleActivator {

    private static final ResourceBundle LOGGING_MESSAGES = ResourceBundle
            .getBundle("logging-messages/" + Activator.class.getSimpleName(), Locale.ROOT);
    private static final Logger LOGGER = Logger.getLogger(Activator.class.getName());
    private static final String DEFAULT_CONFIG_DIR = "conf/";
    public static final String PROPERTY_NAME_FORMAT = "ENSSubscriber-PrinterApp-%1$s.properties";
    private static final String SUBSCRIBER_IMPLEMENTATION_ID = "default";
    private static final int CONFIGURATION_CAPACITY = 100;
    //    private static final String SUBSCRIBER_SEARCH_FILTER_FORMAT = 
    //            "(&(" + it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY
    //            + "=%1$s)(" + it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY + "=%2$d)(" +
    //            ENSResourceFactory.PATTERN + "=%3$s))";
    //    private final BlockingQueue<Filter> filters;
    private final BlockingQueue<SubscriberFilter> filters;
    private ConfiguredSubscriberTracker tracker;

    public Activator() {
        //        filters = new LinkedBlockingQueue<Filter>(CONFIGURATION_CAPACITY);
        filters = new LinkedBlockingQueue<SubscriberFilter>(CONFIGURATION_CAPACITY);
    }

    /* (non-Javadoc)
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */
    @Override
    public void start(final BundleContext context) throws Exception {
        if (LOGGER.isLoggable(Level.INFO)) {
            LOGGER.log(Level.INFO,
                    "[ENS Subscriber - Event printer example] Bundle ID: " + context.getBundle().getBundleId());
        }

        //retrieve the configuration admin service
        ServiceReference<ConfigurationAdmin> configAdminSR = context.getServiceReference(ConfigurationAdmin.class);
        if (configAdminSR == null)
            throw new Exception("No " + ConfigurationAdmin.class.getName() + " available");
        ConfigurationAdmin configAdmin = context.getService(configAdminSR);

        File currentPropertiesFile;

        Properties currentProperties;
        Configuration config;
        FileInputStream stream = null;
        Dictionary<String, Object> configuration;
        int i = 1;
        while ((currentPropertiesFile = new File(DEFAULT_CONFIG_DIR + String.format(PROPERTY_NAME_FORMAT, i++)))
                .exists()) {
            currentProperties = new Properties();
            try {
                stream = new FileInputStream(currentPropertiesFile);
                currentProperties.load(stream);

                config = configAdmin.createFactoryConfiguration(
                        RegisteredServices.SUBSCRIBER_MANAGED_SERVICE_FACTORY_PID, null);
            } catch (IOException e) {
                LOGGER.log(Level.WARNING,
                        MessageFormat.format(LOGGING_MESSAGES.getString("errorWhileReadingPropertiesFile"),
                                currentPropertiesFile.getAbsolutePath()),
                        e);
                continue;
            } finally {
                if (stream != null)
                    try {
                        stream.close();
                    } catch (Exception e) {
                    }
            }

            configuration = MapConverter.convert(currentProperties);
            configuration.put(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY,
                    (Long) context.getBundle().getBundleId());
            configuration.put(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY,
                    SUBSCRIBER_IMPLEMENTATION_ID);
            config.update(configuration);

            Object patternOBJ = configuration.get(ENSResourceFactory.PATTERN);
            String pattern;
            String namespace;
            if (patternOBJ == null) {
                Object resourceOBJ = configuration.get(ENSResourceFactory.URI);
                if (resourceOBJ == null)
                    throw new ConfigurationException(ENSResourceFactory.URI, "Missing property");
                else {
                    ServiceReference<ENSResourceFactory> resourceFactorySR = context
                            .getServiceReference(ENSResourceFactory.class);
                    ENSResourceFactory resourceFactory = context.getService(resourceFactorySR);
                    ENSResource resource;
                    try {
                        resource = resourceFactory.create(new URI(resourceOBJ.toString()));
                        pattern = resource.getPattern();
                        namespace = resource.getNamespace();
                    } catch (IllegalArgumentException e) {
                        throw new ConfigurationException(ENSResourceFactory.URI, e.getMessage(), e);
                    } catch (URIParseException e) {
                        throw new ConfigurationException(ENSResourceFactory.URI, e.getMessage(), e);
                    } catch (URISyntaxException e) {
                        throw new ConfigurationException(ENSResourceFactory.URI, e.getMessage(), e);
                    }
                    context.ungetService(resourceFactorySR);
                }
            } else {
                pattern = (String) patternOBJ;
                namespace = (String) configuration.get(ENSResourceFactory.NAMESPACE);
            }

            //this doesn't work because the escape doesn't work
            //            EqualsFilter implementationFilter = new EqualsFilter(
            //                    it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY, 
            //                    LdapEncoder.filterEncode(SUBSCRIBER_IMPLEMENTATION_ID));
            //            EqualsFilter ownershipFilter = new EqualsFilter(
            //                    it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY,
            //                    (int) context.getBundle().getBundleId());
            //            EqualsFilter patternFilter = new EqualsFilter(ENSResourceFactory.PATTERN,LdapEncoder.filterEncode(pattern));
            //            AndFilter filter = new AndFilter().and(implementationFilter).and(ownershipFilter).and(patternFilter);
            //            Filter osgiFilter = FrameworkUtil.createFilter(filter.toString());

            try {
                filters.put(new SubscriberFilter(SUBSCRIBER_IMPLEMENTATION_ID, context.getBundle().getBundleId(),
                        namespace, pattern));
                //            } catch (InvalidSyntaxException e) {
                //                throw new ConfigurationException(null, "An error occurred while tracking subscription services using filter " + 
                //                        osgiFilter.toString(), e);
            } catch (InterruptedException e) {
                continue;
            }
        }
        tracker = new ConfiguredSubscriberTracker(context);
        tracker.start();
    }

    /* (non-Javadoc)
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    @Override
    public void stop(BundleContext context) throws Exception {
        tracker.shutdown(context);
        tracker.join();
        tracker = null;
    }

    private class ConfiguredSubscriberTracker extends Thread {
        private final Logger TRACKER_LOGGER = Logger.getLogger(ConfiguredSubscriberTracker.class.getName());
        private static final long SUBSCRIBER_LOOKUP_TIMEOUT = 10000;
        private static final int TIMEOUT = 100;
        //        private ServiceTracker<ENSSubscriber,ENSSubscriber> subscriberTracker;
        private boolean run;
        private volatile BundleContext context;
        private final HashMap<String, ENSEventPrinterImpl> serviceMap;
        private List<ServiceReference<ENSSubscriber>> subscriberReferences;

        public ConfiguredSubscriberTracker(BundleContext context) throws ConfigurationException {
            run = true;
            this.context = context;
            serviceMap = new HashMap<String, ENSEventPrinterImpl>();
            subscriberReferences = Collections.synchronizedList(new LinkedList<ServiceReference<ENSSubscriber>>());
        }

        public void run() {
            //            Filter filter = null;
            SubscriberFilter filter = null;
            String id;
            while (run) {
                try {
                    filter = filters.poll(TIMEOUT, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    continue;
                }
                if (filter != null) {
                    //cannot use the service tracker because the special characters escape doesn't work!
                    //                    subscriberTracker = new ServiceTracker<ENSSubscriber, ENSSubscriber>(context, filter, null);
                    //                    subscriberTracker.open();
                    ENSSubscriber subscriber = null;
                    Collection<ServiceReference<ENSSubscriber>> subscriberReferences;
                    long startTime = System.currentTimeMillis();
                    try {
                        do {
                            subscriberReferences = context.getServiceReferences(ENSSubscriber.class,
                                    filter.toString());
                            if (!subscriberReferences.isEmpty())
                                subscriber = selectSubscriber(subscriberReferences, filter);
                        } while (subscriber == null
                                && (System.currentTimeMillis() - startTime) <= SUBSCRIBER_LOOKUP_TIMEOUT);
                        //                        subscriber = subscriberTracker.waitForService(SUBSCRIBER_LOOKUP_TIMEOUT);

                        //                    } catch (InterruptedException e) {
                        //                        TRACKER_LOGGER.log(Level.SEVERE, "The service tracker has been unexpectly stopped.", e);
                    } catch (InvalidSyntaxException e) {
                        TRACKER_LOGGER.log(Level.SEVERE, "The service tracker has been unexpectly stopped.", e);
                        continue;
                    }
                    //                    subscriberTracker.close();
                    if (subscriber == null) {
                        TRACKER_LOGGER.log(Level.SEVERE,
                                "No subscriber found with selection criteria " + filter.toString());
                        return;
                    }
                    subscriber = context.getService(subscriberReferences.iterator().next());
                    id = subscriber.getTargetResource().getNamespace() + "@"
                            + subscriber.getTargetResource().getPattern();
                    ENSEventPrinterImpl eventPrinter = new ENSEventPrinterImpl(id, subscriber);
                    //TODO register printers in the OSGi service registry
                    serviceMap.put(id, eventPrinter);
                    try {
                        eventPrinter.init();
                        if (eventPrinter.isInitialised()) {
                            eventPrinter.start();
                            if (LOGGER.isLoggable(Level.FINE))
                                LOGGER.log(Level.FINE, MessageFormat
                                        .format(LOGGING_MESSAGES.getString("eventPrinterStarted"), id));
                        }
                    } catch (Exception e) {
                        LOGGER.log(Level.SEVERE, MessageFormat
                                .format(LOGGING_MESSAGES.getString("errorWhileStartingEventPrinter"), id), e);
                        continue;
                    }
                    //
                    //                if (properties != null) {
                    //                    StringBuilder builder = new StringBuilder();
                    //                    boolean isFirst = true;
                    //                    java.util.Enumeration<String> keys = properties.keys();
                    //                    String key;
                    //                    while (keys.hasMoreElements()) {
                    //                        key = keys.nextElement();
                    //                        if (isFirst)
                    //                            isFirst = false;
                    //                        else
                    //                            builder.append("\n");
                    //                        builder.append(key);
                    //                        builder.append(": ");
                    //                        builder.append(properties.get(key));
                    //                    }
                    //                    LOGGER.log(Level.FINER, "Registering an instance of " + ENSEventPrinter.class.getName() + 
                    //                            " with pid " + pid + "and the following properties:\n" + builder.toString());
                    //                }

                }
            }

        }

        private ENSSubscriber selectSubscriber(Collection<ServiceReference<ENSSubscriber>> subscriberReferences,
                SubscriberFilter filter) {
            Iterator<ServiceReference<ENSSubscriber>> iterator = subscriberReferences.iterator();
            ENSSubscriber subscriber = null;
            ServiceReference<ENSSubscriber> subscriberSR;
            while (iterator.hasNext() && subscriber == null) {
                subscriberSR = iterator.next();
                if (filter.match(subscriberSR)) {
                    subscriber = context.getService(subscriberSR);
                    this.subscriberReferences.add(subscriberSR);
                    if (LOGGER.isLoggable(Level.FINER))
                        LOGGER.log(Level.FINER,
                                MessageFormat.format(LOGGING_MESSAGES.getString("addedSubscriberReference"),
                                        subscriberSR.getProperty(Constants.SERVICE_PID)));
                }
            }
            return subscriber;
        }

        public void shutdown(BundleContext context) {
            run = false;
            this.context = context;
            ENSEventPrinterImpl eventPrinter;
            for (Entry<String, ENSEventPrinterImpl> entry : serviceMap.entrySet()) {
                eventPrinter = entry.getValue();
                try {
                    if (eventPrinter.isWorking()) {
                        eventPrinter.stop();
                        eventPrinter.shutdown();
                    }
                } catch (Exception e) {
                    LOGGER.log(Level.WARNING, MessageFormat.format(
                            LOGGING_MESSAGES.getString("eventPrinterStoppingError"), eventPrinter.getID()), e);
                }
                LOGGER.log(Level.INFO,
                        MessageFormat.format(LOGGING_MESSAGES.getString("eventPrinterStopped"), entry.getKey()));
            }
            ServiceReference<ConfigurationAdmin> configAdminSR = context
                    .getServiceReference(ConfigurationAdmin.class);
            ConfigurationAdmin configAdmin = context.getService(configAdminSR);
            String pid;
            Configuration config;
            synchronized (subscriberReferences) {
                for (ServiceReference<ENSSubscriber> reference : subscriberReferences) {
                    pid = (String) reference.getProperty(Constants.SERVICE_PID);
                    if (LOGGER.isLoggable(Level.FINER))
                        LOGGER.log(Level.FINER, MessageFormat
                                .format(LOGGING_MESSAGES.getString("deletingSubscriberReference"), pid));
                    try {
                        if (pid != null) {
                            config = configAdmin.getConfiguration(pid);
                            if (config != null)
                                config.delete();
                        }
                    } catch (IOException e) {
                        if (LOGGER.isLoggable(Level.WARNING))
                            ;
                        LOGGER.log(Level.WARNING,
                                MessageFormat.format(LOGGING_MESSAGES.getString("configurationDeletionError"), pid),
                                e);
                    }
                    context.ungetService(reference);
                }
            }
            context.ungetService(configAdminSR);
        }
    }

    private static class SubscriberFilter implements Filter {

        private String unescapedImplementationID;
        private String unescapedPattern;
        private String unescapedNamespace;
        private long bundleOwnerID;
        private String encodedOsgiFilter;

        public SubscriberFilter(String unescapedImplementationID, long bundleOwnerID, String unescapedNamespace,
                String unescapedPattern) {
            if (unescapedImplementationID == null)
                throw new IllegalArgumentException("The implementation ID cannot be null");
            if (unescapedNamespace == null)
                throw new IllegalArgumentException("The namespace ID cannot be null");
            if (unescapedPattern == null)
                throw new IllegalArgumentException("The pattern cannot be null");
            this.unescapedImplementationID = unescapedImplementationID;
            this.unescapedPattern = unescapedPattern;
            this.unescapedNamespace = unescapedNamespace;
            this.bundleOwnerID = bundleOwnerID;

            EqualsFilter implementationFilter = new EqualsFilter(
                    it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY,
                    unescapedImplementationID);
            EqualsFilter ownershipFilter = new EqualsFilter(
                    it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY, bundleOwnerID + "");
            AndFilter filter = new AndFilter().and(implementationFilter).and(ownershipFilter);
            encodedOsgiFilter = filter.encode();
        }

        /* (non-Javadoc)
         * @see org.osgi.framework.Filter#match(org.osgi.framework.ServiceReference)
         */
        @Override
        public boolean match(ServiceReference<?> reference) {
            return matches(
                    reference.getProperty(
                            it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY),
                    reference.getProperty(ENSResourceFactory.NAMESPACE),
                    reference.getProperty(ENSResourceFactory.PATTERN), (Long) reference
                            .getProperty(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY));
        }

        /* (non-Javadoc)
         * @see org.osgi.framework.Filter#match(java.util.Dictionary)
         */
        @Override
        public boolean match(Dictionary<String, ?> dictionary) {
            return matches(
                    dictionary
                            .get(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY),
                    dictionary.get(ENSResourceFactory.NAMESPACE), dictionary.get(ENSResourceFactory.PATTERN),
                    (Long) dictionary.get(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY));
        }

        /* (non-Javadoc)
         * @see org.osgi.framework.Filter#matchCase(java.util.Dictionary)
         */
        @Override
        public boolean matchCase(Dictionary<String, ?> dictionary) {
            return matches(
                    dictionary
                            .get(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY),
                    dictionary.get(ENSResourceFactory.NAMESPACE), dictionary.get(ENSResourceFactory.PATTERN),
                    (Long) dictionary.get(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY));
        }

        /* (non-Javadoc)
         * @see org.osgi.framework.Filter#matches(java.util.Map)
         */
        @Override
        public boolean matches(Map<String, ?> map) {
            return matches(
                    map.get(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_IMPLEMENTATION_KEY),
                    map.get(ENSResourceFactory.NAMESPACE), map.get(ENSResourceFactory.PATTERN),
                    (Long) map.get(it.txt.ens.client.subscriber.osgi.FilterAttributes.SUBSCRIBER_OWNER_KEY));
        }

        private boolean matches(Object thatImplementationID, Object thatNamespace, Object thatPattern,
                long ownerID) {
            System.out.println(
                    thatImplementationID + "-----" + thatNamespace + "-----" + thatPattern + "-----" + ownerID);

            return unescapedImplementationID.equals(thatImplementationID)
                    && unescapedNamespace.equals(thatNamespace) && unescapedPattern.equals(thatPattern)
                    && bundleOwnerID == ownerID;
        }

        /* (non-Javadoc)
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (obj == null)
                return false;
            if (obj instanceof SubscriberFilter) {
                SubscriberFilter that = (SubscriberFilter) obj;
                return this.bundleOwnerID == that.bundleOwnerID
                        && this.unescapedImplementationID.equals(that.unescapedImplementationID)
                        && this.unescapedNamespace.equals(that.unescapedNamespace)
                        && this.unescapedPattern.equals(that.unescapedPattern);
            }
            return false;
        }

        /* (non-Javadoc)
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            return encodedOsgiFilter.hashCode();
        }

        /* (non-Javadoc)
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {
            System.out.println("Subscriuber filter = " + encodedOsgiFilter);

            return encodedOsgiFilter;
        }

        /**
         * @return the unescapedImplementationID
         */
        //        public String getUnescapedImplementationID() {
        //            return unescapedImplementationID;
        //        }

        /**
         * @param unescapedImplementationID the unescapedImplementationID to set
         */
        //        public void setUnescapedImplementationID(String unescapedImplementationID) {
        //            this.unescapedImplementationID = unescapedImplementationID;
        //        }

        /**
         * @return the unescapedPattern
         */
        //        public String getUnescapedPattern() {
        //            return unescapedPattern;
        //        }

        /**
         * @param unescapedPattern the unescapedPattern to set
         */
        //        public void setUnescapedPattern(String unescapedPattern) {
        //            this.unescapedPattern = unescapedPattern;
        //        }

        /**
         * @return the unescapedNamespace
         */
        //        public String getUnescapedNamespace() {
        //            return unescapedNamespace;
        //        }

        /**
         * @param unescapedNamespace the unescapedNamespace to set
         */
        //        public void setUnescapedNamespace(String unescapedNamespace) {
        //            this.unescapedNamespace = unescapedNamespace;
        //        }

        /**
         * @return the bundleOwnerID
         */
        //        public long getBundleOwnerID() {
        //            return bundleOwnerID;
        //        }

        /**
         * @param bundleOwnerID the bundleOwnerID to set
         */
        //        public void setBundleOwnerID(long bundleOwnerID) {
        //            this.bundleOwnerID = bundleOwnerID;
        //        }
    }
}