Java tutorial
/*************************************************************************** * 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; // } } }