You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by gn...@apache.org on 2014/03/31 18:18:18 UTC

svn commit: r1583367 [2/4] - in /felix/trunk/pojosr: ./ src/ src/main/ src/main/java/ src/main/java/de/ src/main/java/de/kalpatec/ src/main/java/de/kalpatec/pojosr/ src/main/java/de/kalpatec/pojosr/framework/ src/main/java/de/kalpatec/pojosr/framework/...

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoSRBundleContext.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoSRBundleContext.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoSRBundleContext.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoSRBundleContext.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,297 @@
+/*
+ * 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 de.kalpatec.pojosr.framework;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.AllServiceListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+import de.kalpatec.pojosr.framework.felix.framework.ServiceRegistry;
+import de.kalpatec.pojosr.framework.felix.framework.capabilityset.SimpleFilter;
+import de.kalpatec.pojosr.framework.felix.framework.util.EventDispatcher;
+
+class PojoSRBundleContext implements BundleContext
+{
+    private final Bundle m_bundle;
+    private final ServiceRegistry m_reg;
+    private final EventDispatcher m_dispatcher;
+    private final Map<Long, Bundle> m_bundles;
+    private final Map m_config;
+
+    public PojoSRBundleContext(Bundle bundle, ServiceRegistry reg,
+            EventDispatcher dispatcher, Map<Long, Bundle> bundles, Map config)
+    {
+        m_bundle = bundle;
+        m_reg = reg;
+        m_dispatcher = dispatcher;
+        m_bundles = bundles;
+        m_config = config;
+    }
+
+    public boolean ungetService(ServiceReference reference)
+    {
+        return m_reg.ungetService(m_bundle, reference);
+    }
+
+    public void removeServiceListener(ServiceListener listener)
+    {
+        m_dispatcher.removeListener(this, ServiceListener.class,
+                    listener);
+    }
+
+    public void removeFrameworkListener(FrameworkListener listener)
+    {
+        m_dispatcher
+                .removeListener(this, FrameworkListener.class, listener);
+    }
+
+    public void removeBundleListener(BundleListener listener)
+    {
+        m_dispatcher.removeListener(this, BundleListener.class, listener);
+    }
+
+    public ServiceRegistration registerService(String clazz, Object service,
+            Dictionary properties)
+    {
+        return m_reg.registerService(m_bundle, new String[] { clazz }, service,
+                properties);
+    }
+
+    public ServiceRegistration registerService(String[] clazzes,
+            Object service, Dictionary properties)
+    {
+        return m_reg.registerService(m_bundle, clazzes, service, properties);
+    }
+
+    public Bundle installBundle(String location) throws BundleException
+    {
+        throw new BundleException("pojosr can't do that");
+    }
+
+    public Bundle installBundle(String location, InputStream input)
+            throws BundleException
+    {
+
+        throw new BundleException("pojosr can't do that");
+    }
+
+    public ServiceReference[] getServiceReferences(String clazz, String filter)
+            throws InvalidSyntaxException
+    {
+        return getAllServiceReferences(clazz, filter);
+    }
+
+    public ServiceReference getServiceReference(String clazz)
+    {
+        try
+        {
+            return getBestServiceReference(getAllServiceReferences(clazz, null));
+        }
+        catch (InvalidSyntaxException e)
+        {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    private ServiceReference getBestServiceReference(ServiceReference[] refs)
+    {
+        if (refs == null)
+        {
+            return null;
+        }
+
+        if (refs.length == 1)
+        {
+            return refs[0];
+        }
+
+        // Loop through all service references and return
+        // the "best" one according to its rank and ID.
+        ServiceReference bestRef = refs[0];
+        for (int i = 1; i < refs.length; i++)
+        {
+            if (bestRef.compareTo(refs[i]) < 0)
+            {
+                bestRef = refs[i];
+            }
+        }
+
+        return bestRef;
+    }
+
+    public Object getService(ServiceReference reference)
+    {
+        return m_reg.getService(m_bundle, reference);
+    }
+
+    public String getProperty(String key)
+    {
+        Object result = m_config.get(key);
+
+        return result == null ? System.getProperty(key) : result.toString();
+    }
+
+    public File getDataFile(String filename)
+    {
+        File root = new File("bundle" + m_bundle.getBundleId());
+        if (System.getProperty("org.osgi.framework.storage") != null)
+        {
+            root = new File(new File(System.getProperty("org.osgi.framework.storage")), root.getName());
+        }
+        root.mkdirs();
+        return filename.trim().length() > 0 ? new File(root, filename) : root;
+    }
+
+    public Bundle[] getBundles()
+    {
+        Bundle[] result = m_bundles.values().toArray(
+                new Bundle[m_bundles.size()]);
+        Arrays.sort(result, new Comparator<Bundle>()
+        {
+
+            public int compare(Bundle o1, Bundle o2)
+            {
+                return (int) (o1.getBundleId() - o2.getBundleId());
+            }
+        });
+        return result;
+    }
+
+    public Bundle getBundle(long id)
+    {
+        return m_bundles.get(id);
+    }
+
+    public Bundle getBundle()
+    {
+        return m_bundle;
+    }
+
+    public ServiceReference[] getAllServiceReferences(String clazz,
+            String filter) throws InvalidSyntaxException
+    {
+        SimpleFilter simple = null;
+        if (filter != null)
+        {
+            try
+            {
+                simple = SimpleFilter.parse(filter);
+            }
+            catch (Exception ex)
+            {
+                throw new InvalidSyntaxException(ex.getMessage(), filter);
+            }
+        }
+        List<ServiceReference> result = m_reg.getServiceReferences(clazz,
+                simple);
+        return result.isEmpty() ? null : result
+                .toArray(new ServiceReference[result.size()]);
+    }
+
+    public Filter createFilter(String filter) throws InvalidSyntaxException
+    {
+        return FrameworkUtil.createFilter(filter);
+    }
+
+    public void addServiceListener(ServiceListener listener)
+    {
+        try
+        {
+            addServiceListener(listener, null);
+        }
+        catch (InvalidSyntaxException e)
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+     public void addServiceListener(final ServiceListener listener, String filter)
+            throws InvalidSyntaxException
+    {
+		 m_dispatcher.addListener(this, ServiceListener.class, listener,
+                filter == null ? null : FrameworkUtil.createFilter(filter));
+    }
+
+    public void addFrameworkListener(FrameworkListener listener)
+    {
+        m_dispatcher.addListener(this, FrameworkListener.class, listener,
+                null);
+    }
+
+    public void addBundleListener(BundleListener listener)
+    {
+        m_dispatcher
+                .addListener(this, BundleListener.class, listener, null);
+    }
+
+    public <S> ServiceRegistration<S> registerService(Class<S> clazz, S service, Dictionary<String, ?> properties)
+    {
+        return (ServiceRegistration<S>) registerService(clazz.getName(), service, properties);
+    }
+
+    public <S> ServiceReference<S> getServiceReference(Class<S> clazz)
+    {
+        return (ServiceReference<S>) getServiceReference(clazz.getName());
+    }
+
+    public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter)
+                    throws InvalidSyntaxException
+    {
+        ServiceReference<S>[] refs = (ServiceReference<S>[]) getServiceReferences(clazz.getName(), filter);
+        if (refs == null)
+        {
+            return Collections.emptyList();
+        }
+        return Arrays.asList(refs);
+    }
+
+    public Bundle getBundle(String location)
+    {
+        for (Bundle bundle : m_bundles.values())
+        {
+            if (location.equals(bundle.getLocation()))
+            {
+                return bundle;
+            }
+        }
+        return null;
+    }
+}

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoServiceRegistryFactoryImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoServiceRegistryFactoryImpl.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoServiceRegistryFactoryImpl.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/PojoServiceRegistryFactoryImpl.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,238 @@
+/*
+ * 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 de.kalpatec.pojosr.framework;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.framework.Version;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+
+import de.kalpatec.pojosr.framework.launch.ClasspathScanner;
+import de.kalpatec.pojosr.framework.launch.PojoServiceRegistry;
+import de.kalpatec.pojosr.framework.launch.PojoServiceRegistryFactory;
+
+public class PojoServiceRegistryFactoryImpl implements
+		PojoServiceRegistryFactory, FrameworkFactory {
+
+	public PojoServiceRegistry newPojoServiceRegistry(Map configuration)
+			throws Exception {
+		return new PojoSR(configuration);
+	}
+
+	public Framework newFramework(Map configuration) {
+		return new FrameworkImpl((String) configuration.get("pojosr.filter"));
+	}
+
+	private static final class FrameworkImpl implements Framework {
+		private final String m_filter;
+		private volatile Bundle m_bundle = null;
+		private volatile PojoServiceRegistry m_reg = null;
+
+		public FrameworkImpl(String filter) {
+			m_filter = filter;
+		}
+
+		public void init() throws BundleException {
+			try {
+				m_reg = new PojoServiceRegistryFactoryImpl()
+				.newPojoServiceRegistry(new HashMap());
+				m_bundle = m_reg.getBundleContext()
+						.getBundle();
+			} catch (Exception ex) {
+				throw new BundleException("Unable to scan classpath", ex);
+			}
+		}
+
+		public int getState() {
+			return (m_bundle == null) ? Bundle.INSTALLED : m_bundle.getState();
+		}
+
+		public void start(int options) throws BundleException {
+			start();
+		}
+
+		public void start() throws BundleException {
+			try {
+				m_reg.startBundles((m_filter != null) ? new ClasspathScanner()
+					.scanForBundles(m_filter)
+					: new ClasspathScanner().scanForBundles());
+			} catch (Exception e) {
+				throw new BundleException("Error starting framework", e);
+			}
+		}
+
+		public void stop(int options) throws BundleException {
+			m_bundle.stop(options);
+		}
+
+		public void stop() throws BundleException {
+			m_bundle.stop();
+		}
+
+		public void update(InputStream input) throws BundleException {
+			m_bundle.update(input);
+		}
+
+		public void update() throws BundleException {
+			m_bundle.update();
+		}
+
+		public void uninstall() throws BundleException {
+			m_bundle.uninstall();
+		}
+
+		public Dictionary getHeaders() {
+			return m_bundle.getHeaders();
+		}
+
+		public long getBundleId() {
+			return m_bundle.getBundleId();
+		}
+
+		public String getLocation() {
+			return m_bundle.getLocation();
+		}
+
+		public ServiceReference[] getRegisteredServices() {
+			return m_bundle.getRegisteredServices();
+		}
+
+		public ServiceReference[] getServicesInUse() {
+			return m_bundle.getServicesInUse();
+		}
+
+		public boolean hasPermission(Object permission) {
+			return m_bundle.hasPermission(permission);
+		}
+
+		public URL getResource(String name) {
+			return m_bundle.getResource(name);
+		}
+
+		public Dictionary getHeaders(String locale) {
+			return m_bundle.getHeaders(locale);
+		}
+
+		public String getSymbolicName() {
+			return m_bundle.getSymbolicName();
+		}
+
+		public Class loadClass(String name) throws ClassNotFoundException {
+			return m_bundle.loadClass(name);
+		}
+
+		public Enumeration getResources(String name) throws IOException {
+			return m_bundle.getResources(name);
+		}
+
+		public Enumeration getEntryPaths(String path) {
+			return m_bundle.getEntryPaths(path);
+		}
+
+		public URL getEntry(String path) {
+			return m_bundle.getEntry(path);
+		}
+
+		public long getLastModified() {
+			return m_bundle.getLastModified();
+		}
+
+		public Enumeration findEntries(String path, String filePattern,
+				boolean recurse) {
+			return m_bundle.findEntries(path, filePattern, recurse);
+		}
+
+		public BundleContext getBundleContext() {
+			return m_bundle.getBundleContext();
+		}
+
+		public Map getSignerCertificates(int signersType) {
+			return m_bundle.getSignerCertificates(signersType);
+		}
+
+		public Version getVersion() {
+			return m_bundle.getVersion();
+		}
+
+		public FrameworkEvent waitForStop(long timeout)
+				throws InterruptedException {
+			final Object lock = new Object();
+			
+			m_bundle.getBundleContext().addBundleListener(new SynchronousBundleListener() {
+				
+				public void bundleChanged(BundleEvent event) {
+					if ((event.getBundle() == m_bundle) && (event.getType() == BundleEvent.STOPPED)) {
+						synchronized (lock) {
+							lock.notifyAll();
+						}
+					}
+				}
+			});
+			synchronized (lock) {
+				while (m_bundle.getState() != Bundle.RESOLVED) {
+					if (m_bundle.getState() == Bundle.STOPPING ) {
+						lock.wait(100);
+					}
+					else {
+						lock.wait();
+					}
+				}
+			}
+			return new FrameworkEvent(FrameworkEvent.STOPPED, m_bundle, null);
+		}
+		
+		public File getDataFile(String filename) {
+		    return m_bundle.getDataFile(filename);
+		}
+
+        public int compareTo(Bundle o)
+        {
+            if (o == this) 
+            {
+                return 0;
+            }
+            return m_bundle.compareTo(o);
+        }
+
+        public <A> A adapt(Class<A> type)
+        {
+            return m_bundle.adapt(type);
+        }
+
+	}
+}

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/Revision.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/Revision.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/Revision.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/Revision.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,33 @@
+/*
+ * 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 de.kalpatec.pojosr.framework;
+
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.osgi.framework.wiring.BundleRevision;
+
+abstract class Revision
+{
+    public abstract long getLastModified();
+
+    public abstract URL getEntry(String entryName);
+
+    public abstract Enumeration<String> getEntries();
+}
\ No newline at end of file

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/URLRevision.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/URLRevision.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/URLRevision.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/URLRevision.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,70 @@
+/*
+ * 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 de.kalpatec.pojosr.framework;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+
+class URLRevision extends Revision
+{
+    private final URL m_url;
+    private final long m_lastModified;
+
+    public URLRevision(URL url, long lastModified)
+    {
+        m_url = url;
+        if (lastModified > 0)
+        {
+            m_lastModified = lastModified;
+        }
+        else
+        {
+            m_lastModified = System.currentTimeMillis();
+        }
+    }
+
+    @Override
+    public long getLastModified()
+    {
+        return m_lastModified;
+    }
+
+    public Enumeration getEntries()
+    {
+        return new Properties().elements();
+    }
+
+    @Override
+    public URL getEntry(String entryName)
+    {
+        // TODO Auto-generated method stub
+        try
+        {
+            return new URL(m_url, entryName);
+        }
+        catch (MalformedURLException e)
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            return null;
+        }
+    }
+}
\ No newline at end of file

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistrationImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistrationImpl.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistrationImpl.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistrationImpl.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,553 @@
+/*
+ * 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 de.kalpatec.pojosr.framework.felix.framework;
+
+import java.util.*;
+
+import org.osgi.framework.*;
+
+import de.kalpatec.pojosr.framework.felix.framework.capabilityset.Attribute;
+import de.kalpatec.pojosr.framework.felix.framework.capabilityset.Capability;
+import de.kalpatec.pojosr.framework.felix.framework.capabilityset.Directive;
+import de.kalpatec.pojosr.framework.felix.framework.util.MapToDictionary;
+import de.kalpatec.pojosr.framework.felix.framework.util.StringMap;
+import de.kalpatec.pojosr.framework.felix.framework.util.Util;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRevision;
+
+class ServiceRegistrationImpl implements ServiceRegistration
+{
+    // Service registry.
+    private final ServiceRegistry m_registry;
+    // Bundle providing the service.
+    private final Bundle m_bundle;
+    // Interfaces associated with the service object.
+    private final String[] m_classes;
+    // Service Id associated with the service object.
+    private final Long m_serviceId;
+    // Service object.
+    private volatile Object m_svcObj;
+    // Service factory interface.
+    private volatile ServiceFactory m_factory;
+    // Associated property dictionary.
+    private volatile Map m_propMap = new StringMap(false);
+    // Re-usable service reference.
+    private final ServiceReferenceImpl m_ref;
+    // Flag indicating that we are unregistering.
+    private volatile boolean m_isUnregistering = false;
+
+    public ServiceRegistrationImpl(ServiceRegistry registry, Bundle bundle,
+            String[] classes, Long serviceId, Object svcObj, Dictionary dict)
+    {
+        m_registry = registry;
+        m_bundle = bundle;
+        m_classes = classes;
+        m_serviceId = serviceId;
+        m_svcObj = svcObj;
+        m_factory = (m_svcObj instanceof ServiceFactory) ? (ServiceFactory) m_svcObj
+                : null;
+
+        initializeProperties(dict);
+
+        // This reference is the "standard" reference for this
+        // service and will always be returned by getReference().
+        m_ref = new ServiceReferenceImpl();
+    }
+
+    protected synchronized boolean isValid()
+    {
+        return (m_svcObj != null);
+    }
+
+    protected synchronized void invalidate()
+    {
+        m_svcObj = null;
+    }
+
+    public synchronized ServiceReference getReference()
+    {
+        // Make sure registration is valid.
+        if (!isValid())
+        {
+            throw new IllegalStateException(
+                    "The service registration is no longer valid.");
+        }
+        return m_ref;
+    }
+
+    public void setProperties(Dictionary dict)
+    {
+        Map oldProps;
+        synchronized (this)
+        {
+            // Make sure registration is valid.
+            if (!isValid())
+            {
+                throw new IllegalStateException(
+                        "The service registration is no longer valid.");
+            }
+            // Remember old properties.
+            oldProps = m_propMap;
+            // Set the properties.
+            initializeProperties(dict);
+        }
+        // Tell registry about it.
+        m_registry.servicePropertiesModified(this,
+                new MapToDictionary(oldProps));
+    }
+
+    public void unregister()
+    {
+        synchronized (this)
+        {
+            if (!isValid() || m_isUnregistering)
+            {
+                throw new IllegalStateException("Service already unregistered.");
+            }
+            m_isUnregistering = true;
+        }
+        m_registry.unregisterService(m_bundle, this);
+        synchronized (this)
+        {
+            m_svcObj = null;
+            m_factory = null;
+        }
+    }
+
+    //
+    // Utility methods.
+    //
+    Object getProperty(String key)
+    {
+        return m_propMap.get(key);
+    }
+
+    private String[] getPropertyKeys()
+    {
+        Set s = m_propMap.keySet();
+        return (String[]) s.toArray(new String[s.size()]);
+    }
+
+    private Bundle[] getUsingBundles()
+    {
+        return m_registry.getUsingBundles(m_ref);
+    }
+
+    /**
+     * This method provides direct access to the associated service object; it
+     * generally should not be used by anyone other than the service registry
+     * itself.
+     *
+     * @return The service object associated with the registration.
+     **/
+    Object getService()
+    {
+        return m_svcObj;
+    }
+
+    Object getService(Bundle acqBundle)
+    {
+        // If the service object is a service factory, then
+        // let it create the service object.
+        if (m_factory != null)
+        {
+            Object svcObj = null;
+            svcObj = getFactoryUnchecked(acqBundle);
+
+            return svcObj;
+        }
+        else
+        {
+            return m_svcObj;
+        }
+    }
+
+    void ungetService(Bundle relBundle, Object svcObj)
+    {
+        // If the service object is a service factory, then
+        // let it release the service object.
+        if (m_factory != null)
+        {
+            try
+            {
+                ungetFactoryUnchecked(relBundle, svcObj);
+            }
+            catch (Exception ex)
+            {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    private void initializeProperties(Dictionary dict)
+    {
+        // Create a case-insensitive map for the properties.
+        Map props = new StringMap(false);
+
+        if (dict != null)
+        {
+            // Make sure there are no duplicate keys.
+            Enumeration keys = dict.keys();
+            while (keys.hasMoreElements())
+            {
+                Object key = keys.nextElement();
+                if (props.get(key) == null)
+                {
+                    props.put(key, dict.get(key));
+                }
+                else
+                {
+                    throw new IllegalArgumentException(
+                            "Duplicate service property: " + key);
+                }
+            }
+        }
+
+        // Add the framework assigned properties.
+        props.put(Constants.OBJECTCLASS, m_classes);
+        props.put(Constants.SERVICE_ID, m_serviceId);
+
+        // Update the service property map.
+        m_propMap = props;
+    }
+
+    private Object getFactoryUnchecked(Bundle bundle)
+    {
+        Object svcObj = null;
+        try
+        {
+            svcObj = m_factory.getService(bundle, this);
+        }
+        catch (Throwable th)
+        {
+            throw new ServiceException("Service factory exception: "
+                    + th.getMessage(), ServiceException.FACTORY_EXCEPTION, th);
+        }
+        if (svcObj != null)
+        {
+            for (int i = 0; i < m_classes.length; i++)
+            {
+                try {
+                if (!Class.forName(m_classes[i]).isAssignableFrom(svcObj.getClass()))
+                {
+                    throw new ServiceException(
+                            "Service cannot be cast: " + m_classes[i],
+                            ServiceException.FACTORY_ERROR);
+                }
+				} catch (ClassNotFoundException ex) {
+				   throw new ServiceException("Service is missing class: " + m_classes[i], ServiceException.FACTORY_ERROR);
+				}
+
+            }
+        }
+        else
+        {
+            throw new ServiceException("Service factory returned null.",
+                    ServiceException.FACTORY_ERROR);
+        }
+        return svcObj;
+    }
+
+    private void ungetFactoryUnchecked(Bundle bundle, Object svcObj)
+    {
+        m_factory.ungetService(bundle, this, svcObj);
+    }
+
+
+
+    //
+    // ServiceReference implementation
+    //
+
+    class ServiceReferenceImpl implements ServiceReference, BundleCapability
+    {
+        private final ServiceReferenceMap m_map;
+
+        private ServiceReferenceImpl()
+        {
+            m_map = new ServiceReferenceMap();
+        }
+
+        ServiceRegistrationImpl getRegistration()
+        {
+            return ServiceRegistrationImpl.this;
+        }
+
+        //
+        // Capability methods.
+        //
+
+        @Override
+        public BundleRevision getRevision()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public String getNamespace()
+        {
+            return "service-reference";
+        }
+
+        @Override
+        public Map<String, String> getDirectives()
+        {
+            return Collections.EMPTY_MAP;
+        }
+
+        @Override
+        public Map<String,Object> getAttributes()
+        {
+            return m_map;
+        }
+
+        public List<String> getUses()
+        {
+            return Collections.EMPTY_LIST;
+        }
+
+        public Object getProperty(String s)
+        {
+            return ServiceRegistrationImpl.this.getProperty(s);
+        }
+
+        public String[] getPropertyKeys()
+        {
+            return ServiceRegistrationImpl.this.getPropertyKeys();
+        }
+
+        public Bundle getBundle()
+        {
+            // The spec says that this should return null if
+            // the service is unregistered.
+            return (isValid()) ? m_bundle : null;
+        }
+
+        public Bundle[] getUsingBundles()
+        {
+            return ServiceRegistrationImpl.this.getUsingBundles();
+        }
+
+        public String toString()
+        {
+            String[] ocs = (String[]) getProperty("objectClass");
+            String oc = "[";
+            for (int i = 0; i < ocs.length; i++)
+            {
+                oc = oc + ocs[i];
+                if (i < ocs.length - 1)
+                    oc = oc + ", ";
+            }
+            oc = oc + "]";
+            return oc;
+        }
+
+        public boolean isAssignableTo(Bundle requester, String className)
+        {
+            // Always return true if the requester is the same as the provider.
+            if (requester == m_bundle)
+            {
+                return true;
+            }
+
+            // Boolean flag.
+            boolean allow = true;
+            // Get the package.
+            String pkgName = Util.getClassPackage(className);
+            /*
+             * Module requesterModule = ((BundleImpl)
+             * requester).getCurrentModule(); // Get package wiring from service
+             * requester. Wire requesterWire = Util.getWire(requesterModule,
+             * pkgName); // Get package wiring from service provider. Module
+             * providerModule = ((BundleImpl) m_bundle).getCurrentModule(); Wire
+             * providerWire = Util.getWire(providerModule, pkgName);
+             *
+             * // There are four situations that may occur here: // 1. Neither
+             * the requester, nor provider have wires for the package. // 2. The
+             * requester does not have a wire for the package. // 3. The
+             * provider does not have a wire for the package. // 4. Both the
+             * requester and provider have a wire for the package. // For case
+             * 1, if the requester does not have access to the class at // all,
+             * we assume it is using reflection and do not filter. If the //
+             * requester does have access to the class, then we make sure it is
+             * // the same class as the service. For case 2, we do not filter if
+             * the // requester is the exporter of the package to which the
+             * provider of // the service is wired. Otherwise, as in case 1, if
+             * the requester // does not have access to the class at all, we do
+             * not filter, but if // it does have access we check if it is the
+             * same class accessible to // the providing module. For case 3, the
+             * provider will not have a wire // if it is exporting the package,
+             * so we determine if the requester // is wired to it or somehow
+             * using the same class. For case 4, we // simply compare the
+             * exporting modules from the package wiring to // determine if we
+             * need to filter the service reference.
+             *
+             * // Case 1: Both requester and provider have no wire. if
+             * ((requesterWire == null) && (providerWire == null)) { // If
+             * requester has no access then true, otherwise service //
+             * registration must have same class as requester. try { Class
+             * requestClass = requesterModule.getClassByDelegation(className);
+             * allow = getRegistration().isClassAccessible(requestClass); }
+             * catch (Exception ex) { // Requester has no access to the class,
+             * so allow it, since // we assume the requester is using
+             * reflection. allow = true; } } // Case 2: Requester has no wire,
+             * but provider does. else if ((requesterWire == null) &&
+             * (providerWire != null)) { // Allow if the requester is the
+             * exporter of the provider's wire. if
+             * (providerWire.getExporter().equals(requesterModule)) { allow =
+             * true; } // Otherwise, check if the requester has access to the
+             * class and, // if so, if it is the same class as the provider.
+             * else { try { // Try to load class from requester. Class
+             * requestClass = requesterModule.getClassByDelegation(className);
+             * try { // If requester has access to the class, verify it is the
+             * // same class as the provider. allow =
+             * (providerWire.getClass(className) == requestClass); } catch
+             * (Exception ex) { allow = false; } } catch (Exception ex) { //
+             * Requester has no access to the class, so allow it, since // we
+             * assume the requester is using reflection. allow = true; } } } //
+             * Case 3: Requester has a wire, but provider does not. else if
+             * ((requesterWire != null) && (providerWire == null)) { // If the
+             * provider is the exporter of the requester's package, then check
+             * // if the requester is wired to the latest version of the
+             * provider, if so // then allow else don't (the provider has been
+             * updated but not refreshed). if (((BundleImpl)
+             * m_bundle).hasModule(requesterWire.getExporter())) { allow =
+             * providerModule.equals(requesterWire.getExporter()); } // If the
+             * provider is not the exporter of the requester's package, // then
+             * try to use the service registration to see if the requester's //
+             * class is accessible. else { try { // Load the class from the
+             * requesting bundle. Class requestClass =
+             * requesterModule.getClassByDelegation(className); // Get the
+             * service registration and ask it to check // if the service object
+             * is assignable to the requesting // bundle's class. allow =
+             * getRegistration().isClassAccessible(requestClass); } catch
+             * (Exception ex) { // Filter to be safe. allow = false; } } } //
+             * Case 4: Both requester and provider have a wire. else { //
+             * Include service reference if the wires have the // same source
+             * module. allow =
+             * providerWire.getExporter().equals(requesterWire.getExporter()); }
+             */
+
+            return allow;
+        }
+
+        public int compareTo(Object reference)
+        {
+            ServiceReference other = (ServiceReference) reference;
+
+            Long id = (Long) getProperty(Constants.SERVICE_ID);
+            Long otherId = (Long) other.getProperty(Constants.SERVICE_ID);
+
+            if (id.equals(otherId))
+            {
+                return 0; // same service
+            }
+
+            Object rankObj = getProperty(Constants.SERVICE_RANKING);
+            Object otherRankObj = other.getProperty(Constants.SERVICE_RANKING);
+
+            // If no rank, then spec says it defaults to zero.
+            rankObj = (rankObj == null) ? new Integer(0) : rankObj;
+            otherRankObj = (otherRankObj == null) ? new Integer(0)
+                    : otherRankObj;
+
+            // If rank is not Integer, then spec says it defaults to zero.
+            Integer rank = (rankObj instanceof Integer) ? (Integer) rankObj
+                    : new Integer(0);
+            Integer otherRank = (otherRankObj instanceof Integer) ? (Integer) otherRankObj
+                    : new Integer(0);
+
+            // Sort by rank in ascending order.
+            if (rank.compareTo(otherRank) < 0)
+            {
+                return -1; // lower rank
+            }
+            else if (rank.compareTo(otherRank) > 0)
+            {
+                return 1; // higher rank
+            }
+
+            // If ranks are equal, then sort by service id in descending order.
+            return (id.compareTo(otherId) < 0) ? 1 : -1;
+        }
+    }
+
+     private class ServiceReferenceMap implements Map
+    {
+        public int size()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean isEmpty()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean containsKey(Object o)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public boolean containsValue(Object o)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Object get(Object o)
+        {
+            return ServiceRegistrationImpl.this.getProperty((String) o);
+        }
+
+        public Object put(Object k, Object v)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Object remove(Object o)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public void putAll(Map map)
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public void clear()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Set<Object> keySet()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Collection<Object> values()
+        {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Set<Entry<Object, Object>> entrySet()
+        {
+            return Collections.EMPTY_SET;
+        }
+    }
+}
\ No newline at end of file

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistry.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistry.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/ServiceRegistry.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,813 @@
+/*
+ * 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 de.kalpatec.pojosr.framework.felix.framework;
+
+import java.util.*;
+
+import org.osgi.framework.*;
+import org.osgi.framework.hooks.service.*;
+import org.osgi.framework.launch.Framework;
+
+import de.kalpatec.pojosr.framework.felix.framework.capabilityset.Capability;
+import de.kalpatec.pojosr.framework.felix.framework.capabilityset.CapabilitySet;
+import de.kalpatec.pojosr.framework.felix.framework.capabilityset.SimpleFilter;
+import org.osgi.framework.wiring.BundleCapability;
+
+public class ServiceRegistry
+{
+    private long m_currentServiceId = 1L;
+    // Maps bundle to an array of service registrations.
+    private final Map m_regsMap = Collections.synchronizedMap(new HashMap());
+    // Capability set for all service registrations.
+    private final CapabilitySet m_regCapSet;
+    // Maps registration to thread to keep track when a
+    // registration is in use, which will cause other
+    // threads to wait.
+    private final Map m_lockedRegsMap = new HashMap();
+    // Maps bundle to an array of usage counts.
+    private final Map m_inUseMap = new HashMap();
+    private final ServiceRegistryCallbacks m_callbacks;
+    private final WeakHashMap<ServiceReference, ServiceReference> m_blackList =
+        new WeakHashMap<ServiceReference, ServiceReference>();
+    private final static Class<?>[] m_hookClasses =
+    {
+        org.osgi.framework.hooks.bundle.FindHook.class,
+        org.osgi.framework.hooks.bundle.EventHook.class,
+        org.osgi.framework.hooks.service.EventHook.class,
+        org.osgi.framework.hooks.service.EventListenerHook.class,
+        org.osgi.framework.hooks.service.FindHook.class,
+        org.osgi.framework.hooks.service.ListenerHook.class,
+        org.osgi.framework.hooks.weaving.WeavingHook.class,
+        org.osgi.framework.hooks.resolver.ResolverHookFactory.class,
+        org.osgi.service.url.URLStreamHandlerService.class,
+        java.net.ContentHandler.class
+    };
+    private final Map<Class<?>, Set<ServiceReference<?>>> m_allHooks =
+        new HashMap<Class<?>, Set<ServiceReference<?>>>();
+
+    public ServiceRegistry(ServiceRegistryCallbacks callbacks)
+    {
+        m_callbacks = callbacks;
+
+        List indices = new ArrayList();
+        indices.add(Constants.OBJECTCLASS);
+        m_regCapSet = new CapabilitySet(indices, false);
+    }
+
+    public ServiceReference[] getRegisteredServices(Bundle bundle)
+    {
+        ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+        if (regs != null)
+        {
+            List refs = new ArrayList(regs.length);
+            for (int i = 0; i < regs.length; i++)
+            {
+                try
+                {
+                    refs.add(regs[i].getReference());
+                }
+                catch (IllegalStateException ex)
+                {
+                    // Don't include the reference as it is not valid anymore
+                }
+            }
+            return (ServiceReference[]) refs.toArray(new ServiceReference[refs.size()]);
+        }
+        return null;
+    }
+
+    // Caller is expected to fire REGISTERED event.
+    public ServiceRegistration registerService(
+        Bundle bundle, String[] classNames, Object svcObj, Dictionary dict)
+    {
+        ServiceRegistrationImpl reg = null;
+
+        synchronized (this)
+        {
+            // Create the service registration.
+            reg = new ServiceRegistrationImpl(
+                this, bundle, classNames, new Long(m_currentServiceId++), svcObj, dict);
+
+            // Keep track of registered hooks.
+            addHooks(classNames, svcObj, reg.getReference());
+
+            // Get the bundles current registered services.
+            ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+            m_regsMap.put(bundle, addServiceRegistration(regs, reg));
+            m_regCapSet.addCapability((BundleCapability) reg.getReference());
+        }
+
+        // Notify callback objects about registered service.
+        if (m_callbacks != null)
+        {
+            m_callbacks.serviceChanged(new ServiceEvent(
+                ServiceEvent.REGISTERED, reg.getReference()), null);
+        }
+        return reg;
+    }
+
+    public void unregisterService(Bundle bundle, ServiceRegistration reg)
+    {
+        // If this is a hook, it should be removed.
+        removeHook(reg.getReference());
+
+        synchronized (this)
+        {
+            // Note that we don't lock the service registration here using
+            // the m_lockedRegsMap because we want to allow bundles to get
+            // the service during the unregistration process. However, since
+            // we do remove the registration from the service registry, no
+            // new bundles will be able to look up the service.
+
+            // Now remove the registered service.
+            ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+            m_regsMap.put(bundle, removeServiceRegistration(regs, reg));
+            m_regCapSet.removeCapability((BundleCapability) reg.getReference());
+        }
+
+        // Notify callback objects about unregistering service.
+        if (m_callbacks != null)
+        {
+            m_callbacks.serviceChanged(
+                new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()), null);
+        }
+
+        // Now forcibly unget the service object for all stubborn clients.
+        synchronized (this)
+        {
+            Bundle[] clients = getUsingBundles(reg.getReference());
+            for (int i = 0; (clients != null) && (i < clients.length); i++)
+            {
+                while (ungetService(clients[i], reg.getReference()))
+                    ; // Keep removing until it is no longer possible
+            }
+            ((ServiceRegistrationImpl) reg).invalidate();
+        }
+    }
+
+    /**
+     * This method retrieves all services registrations for the specified bundle
+     * and invokes <tt>ServiceRegistration.unregister()</tt> on each one. This
+     * method is only called be the framework to clean up after a stopped
+     * bundle.
+     *
+     * @param bundle the bundle whose services should be unregistered.
+     *
+     */
+    public void unregisterServices(Bundle bundle)
+    {
+        // Simply remove all service registrations for the bundle.
+        ServiceRegistration[] regs = null;
+        synchronized (this)
+        {
+            regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+        }
+
+        // Note, there is no race condition here with respect to the
+        // bundle registering more services, because its bundle context
+        // has already been invalidated by this point, so it would not
+        // be able to register more services.
+
+        // Unregister each service.
+        for (int i = 0; (regs != null) && (i < regs.length); i++)
+        {
+            if (((ServiceRegistrationImpl) regs[i]).isValid())
+            {
+                regs[i].unregister();
+            }
+        }
+
+        // Now remove the bundle itself.
+        synchronized (this)
+        {
+            m_regsMap.remove(bundle);
+        }
+    }
+
+    public synchronized List getServiceReferences(String className, SimpleFilter filter)
+    {
+        if ((className == null) && (filter == null))
+        {
+            // Return all services.
+            filter = new SimpleFilter(Constants.OBJECTCLASS, "*", SimpleFilter.PRESENT);
+        }
+        else if ((className != null) && (filter == null))
+        {
+            // Return services matching the class name.
+            filter = new SimpleFilter(Constants.OBJECTCLASS, className, SimpleFilter.EQ);
+        }
+        else if ((className != null) && (filter != null))
+        {
+            // Return services matching the class name and filter.
+            List filters = new ArrayList(2);
+            filters.add(new SimpleFilter(Constants.OBJECTCLASS, className, SimpleFilter.EQ));
+            filters.add(filter);
+            filter = new SimpleFilter(null, filters, SimpleFilter.AND);
+        }
+        // else just use the specified filter.
+
+        Set<BundleCapability> matches = m_regCapSet.match(filter, false);
+
+        return new ArrayList(matches);
+    }
+
+    public synchronized ServiceReference[] getServicesInUse(Bundle bundle)
+    {
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        if (usages != null)
+        {
+            ServiceReference[] refs = new ServiceReference[usages.length];
+            for (int i = 0; i < refs.length; i++)
+            {
+                refs[i] = usages[i].m_ref;
+            }
+            return refs;
+        }
+        return null;
+    }
+
+    public <S> S getService(Bundle bundle, ServiceReference<S> ref)
+    {
+        UsageCount usage = null;
+        Object svcObj = null;
+
+        // Get the service registration.
+        ServiceRegistrationImpl reg =
+            ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();
+
+        synchronized (this)
+        {
+            // First make sure that no existing operation is currently
+            // being performed by another thread on the service registration.
+            for (Object o = m_lockedRegsMap.get(reg); (o != null); o = m_lockedRegsMap.get(reg))
+            {
+                // We don't allow cycles when we call out to the service factory.
+                if (o.equals(Thread.currentThread()))
+                {
+                    throw new ServiceException(
+                        "ServiceFactory.getService() resulted in a cycle.",
+                        ServiceException.FACTORY_ERROR,
+                        null);
+                }
+
+                // Otherwise, wait for it to be freed.
+                try
+                {
+                    wait();
+                }
+                catch (InterruptedException ex)
+                {
+                }
+            }
+
+            // Lock the service registration.
+            m_lockedRegsMap.put(reg, Thread.currentThread());
+
+            // Make sure the service registration is still valid.
+            if (reg.isValid())
+            {
+                // Get the usage count, if any.
+                usage = getUsageCount(bundle, ref);
+
+                // If we don't have a usage count, then create one and
+                // since the spec says we increment usage count before
+                // actually getting the service object.
+                if (usage == null)
+                {
+                    usage = addUsageCount(bundle, ref);
+                }
+
+                // Increment the usage count and grab the already retrieved
+                // service object, if one exists.
+                usage.m_count++;
+                svcObj = usage.m_svcObj;
+            }
+        }
+
+        // If we have a usage count, but no service object, then we haven't
+        // cached the service object yet, so we need to create one now without
+        // holding the lock, since we will potentially call out to a service
+        // factory.
+        try
+        {
+            if ((usage != null) && (svcObj == null))
+            {
+                svcObj = reg.getService(bundle);
+            }
+        }
+        finally
+        {
+            // If we successfully retrieved a service object, then we should
+            // cache it in the usage count. If not, we should flush the usage
+            // count. Either way, we need to unlock the service registration
+            // so that any threads waiting for it can continue.
+            synchronized (this)
+            {
+                // Before caching the service object, double check to see if
+                // the registration is still valid, since it may have been
+                // unregistered while we didn't hold the lock.
+                if (!reg.isValid() || (svcObj == null))
+                {
+                    flushUsageCount(bundle, ref);
+                }
+                else
+                {
+                    usage.m_svcObj = svcObj;
+                }
+                m_lockedRegsMap.remove(reg);
+                notifyAll();
+            }
+        }
+
+        return (S) svcObj;
+    }
+
+    public boolean ungetService(Bundle bundle, ServiceReference ref)
+    {
+        UsageCount usage = null;
+        ServiceRegistrationImpl reg =
+            ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();
+
+        synchronized (this)
+        {
+            // First make sure that no existing operation is currently
+            // being performed by another thread on the service registration.
+            for (Object o = m_lockedRegsMap.get(reg); (o != null); o = m_lockedRegsMap.get(reg))
+            {
+                // We don't allow cycles when we call out to the service factory.
+                if (o.equals(Thread.currentThread()))
+                {
+                    throw new IllegalStateException(
+                        "ServiceFactory.ungetService() resulted in a cycle.");
+                }
+
+                // Otherwise, wait for it to be freed.
+                try
+                {
+                    wait();
+                }
+                catch (InterruptedException ex)
+                {
+                }
+            }
+
+            // Get the usage count.
+            usage = getUsageCount(bundle, ref);
+            // If there is no cached services, then just return immediately.
+            if (usage == null)
+            {
+                return false;
+            }
+
+            // Lock the service registration.
+            m_lockedRegsMap.put(reg, Thread.currentThread());
+        }
+
+        // If usage count will go to zero, then unget the service
+        // from the registration; we do this outside the lock
+        // since this might call out to the service factory.
+        try
+        {
+            if (usage.m_count == 1)
+            {
+                // Remove reference from usages array.
+                ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
+                    .getRegistration().ungetService(bundle, usage.m_svcObj);
+            }
+        }
+        finally
+        {
+            // Finally, decrement usage count and flush if it goes to zero or
+            // the registration became invalid while we were not holding the
+            // lock. Either way, unlock the service registration so that any
+            // threads waiting for it can continue.
+            synchronized (this)
+            {
+                // Decrement usage count, which spec says should happen after
+                // ungetting the service object.
+                usage.m_count--;
+
+                // If the registration is invalid or the usage count has reached
+                // zero, then flush it.
+                if (!reg.isValid() || (usage.m_count <= 0))
+                {
+                    usage.m_svcObj = null;
+                    flushUsageCount(bundle, ref);
+                }
+
+                // Release the registration lock so any waiting threads can
+                // continue.
+                m_lockedRegsMap.remove(reg);
+                notifyAll();
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * This is a utility method to release all services being used by the
+     * specified bundle.
+     *
+     * @param bundle the bundle whose services are to be released.
+     *
+     */
+    public void ungetServices(Bundle bundle)
+    {
+        UsageCount[] usages;
+        synchronized (this)
+        {
+            usages = (UsageCount[]) m_inUseMap.get(bundle);
+        }
+
+        if (usages == null)
+        {
+            return;
+        }
+
+        // Note, there is no race condition here with respect to the
+        // bundle using more services, because its bundle context
+        // has already been invalidated by this point, so it would not
+        // be able to look up more services.
+
+        // Remove each service object from the
+        // service cache.
+        for (int i = 0; i < usages.length; i++)
+        {
+            // Keep ungetting until all usage count is zero.
+            while (ungetService(bundle, usages[i].m_ref))
+            {
+                // Empty loop body.
+            }
+        }
+    }
+
+    public synchronized Bundle[] getUsingBundles(ServiceReference ref)
+    {
+        Bundle[] bundles = null;
+        for (Iterator iter = m_inUseMap.entrySet().iterator(); iter.hasNext();)
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            Bundle bundle = (Bundle) entry.getKey();
+            UsageCount[] usages = (UsageCount[]) entry.getValue();
+            for (int useIdx = 0; useIdx < usages.length; useIdx++)
+            {
+                if (usages[useIdx].m_ref.equals(ref))
+                {
+                    // Add the bundle to the array to be returned.
+                    if (bundles == null)
+                    {
+                        bundles = new Bundle[]
+                        {
+                            bundle
+                        };
+                    }
+                    else
+                    {
+                        Bundle[] nbs = new Bundle[bundles.length + 1];
+                        System.arraycopy(bundles, 0, nbs, 0, bundles.length);
+                        nbs[bundles.length] = bundle;
+                        bundles = nbs;
+                    }
+                }
+            }
+        }
+        return bundles;
+    }
+
+    void servicePropertiesModified(ServiceRegistration reg, Dictionary oldProps)
+    {
+        updateHook(reg.getReference());
+        if (m_callbacks != null)
+        {
+            m_callbacks.serviceChanged(
+                new ServiceEvent(ServiceEvent.MODIFIED, reg.getReference()), oldProps);
+        }
+    }
+
+    private static ServiceRegistration[] addServiceRegistration(
+        ServiceRegistration[] regs, ServiceRegistration reg)
+    {
+        if (regs == null)
+        {
+            regs = new ServiceRegistration[]
+            {
+                reg
+            };
+        }
+        else
+        {
+            ServiceRegistration[] newRegs = new ServiceRegistration[regs.length + 1];
+            System.arraycopy(regs, 0, newRegs, 0, regs.length);
+            newRegs[regs.length] = reg;
+            regs = newRegs;
+        }
+        return regs;
+    }
+
+    private static ServiceRegistration[] removeServiceRegistration(
+        ServiceRegistration[] regs, ServiceRegistration reg)
+    {
+        for (int i = 0; (regs != null) && (i < regs.length); i++)
+        {
+            if (regs[i].equals(reg))
+            {
+                // If this is the only usage, then point to empty list.
+                if ((regs.length - 1) == 0)
+                {
+                    regs = new ServiceRegistration[0];
+                }
+                // Otherwise, we need to do some array copying.
+                else
+                {
+                    ServiceRegistration[] newRegs = new ServiceRegistration[regs.length - 1];
+                    System.arraycopy(regs, 0, newRegs, 0, i);
+                    if (i < newRegs.length)
+                    {
+                        System.arraycopy(
+                            regs, i + 1, newRegs, i, newRegs.length - i);
+                    }
+                    regs = newRegs;
+                }
+            }
+        }
+        return regs;
+    }
+
+    /**
+     * Utility method to retrieve the specified bundle's usage count for the
+     * specified service reference.
+     *
+     * @param bundle The bundle whose usage counts are being searched.
+     * @param ref The service reference to find in the bundle's usage counts.
+     * @return The associated usage count or null if not found.
+     *
+     */
+    private UsageCount getUsageCount(Bundle bundle, ServiceReference ref)
+    {
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        for (int i = 0; (usages != null) && (i < usages.length); i++)
+        {
+            if (usages[i].m_ref.equals(ref))
+            {
+                return usages[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Utility method to update the specified bundle's usage count array to
+     * include the specified service. This method should only be called to add a
+     * usage count for a previously unreferenced service. If the service already
+     * has a usage count, then the existing usage count counter simply needs to
+     * be incremented.
+     *
+     * @param bundle The bundle acquiring the service.
+     * @param ref The service reference of the acquired service.
+     * @param svcObj The service object of the acquired service.
+     *
+     */
+    private UsageCount addUsageCount(Bundle bundle, ServiceReference ref)
+    {
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+
+        UsageCount usage = new UsageCount();
+        usage.m_ref = ref;
+
+        if (usages == null)
+        {
+            usages = new UsageCount[]
+            {
+                usage
+            };
+        }
+        else
+        {
+            UsageCount[] newUsages = new UsageCount[usages.length + 1];
+            System.arraycopy(usages, 0, newUsages, 0, usages.length);
+            newUsages[usages.length] = usage;
+            usages = newUsages;
+        }
+
+        m_inUseMap.put(bundle, usages);
+
+        return usage;
+    }
+
+    /**
+     * Utility method to flush the specified bundle's usage count for the
+     * specified service reference. This should be called to completely remove
+     * the associated usage count object for the specified service reference. If
+     * the goal is to simply decrement the usage, then get the usage count and
+     * decrement its counter. This method will also remove the specified bundle
+     * from the "in use" map if it has no more usage counts after removing the
+     * usage count for the specified service reference.
+     *
+     * @param bundle The bundle whose usage count should be removed.
+     * @param ref The service reference whose usage count should be removed.
+     *
+     */
+    private void flushUsageCount(Bundle bundle, ServiceReference ref)
+    {
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        for (int i = 0; (usages != null) && (i < usages.length); i++)
+        {
+            if (usages[i].m_ref.equals(ref))
+            {
+                // If this is the only usage, then point to empty list.
+                if ((usages.length - 1) == 0)
+                {
+                    usages = null;
+                }
+                // Otherwise, we need to do some array copying.
+                else
+                {
+                    UsageCount[] newUsages = new UsageCount[usages.length - 1];
+                    System.arraycopy(usages, 0, newUsages, 0, i);
+                    if (i < newUsages.length)
+                    {
+                        System.arraycopy(
+                            usages, i + 1, newUsages, i, newUsages.length - i);
+                    }
+                    usages = newUsages;
+                }
+            }
+        }
+
+        if (usages != null)
+        {
+            m_inUseMap.put(bundle, usages);
+        }
+        else
+        {
+            m_inUseMap.remove(bundle);
+        }
+    }
+
+    //
+    // Hook-related methods.
+    //
+    boolean isHookBlackListed(ServiceReference sr)
+    {
+        return m_blackList.containsKey(sr);
+    }
+
+    void blackListHook(ServiceReference sr)
+    {
+        m_blackList.put(sr, sr);
+    }
+
+    static boolean isHook(String[] classNames, Class<?> hookClass, Object svcObj)
+    {
+        // For a service factory, we can only match names.
+        if (svcObj instanceof ServiceFactory)
+        {
+            for (String className : classNames)
+            {
+                if (className.equals(hookClass.getName()))
+                {
+                    return true;
+                }
+            }
+        }
+
+        // For a service object, check if its class matches.
+        if (hookClass.isAssignableFrom(svcObj.getClass()))
+        {
+            // But still only if it is registered under that interface.
+            String hookName = hookClass.getName();
+            for (String className : classNames)
+            {
+                if (className.equals(hookName))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void addHooks(String[] classNames, Object svcObj, ServiceReference<?> ref)
+    {
+        for (Class<?> hookClass : m_hookClasses)
+        {
+            if (isHook(classNames, hookClass, svcObj))
+            {
+                synchronized (m_allHooks)
+                {
+                    Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
+                    if (hooks == null)
+                    {
+                        hooks = new TreeSet<ServiceReference<?>>(Collections.reverseOrder());
+                        m_allHooks.put(hookClass, hooks);
+                    }
+                    hooks.add(ref);
+                }
+            }
+        }
+    }
+
+    private void updateHook(ServiceReference ref)
+    {
+        // We maintain the hooks sorted, so if ranking has changed for example,
+        // we need to ensure the order remains correct by resorting the hooks.
+        Object svcObj = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
+            .getRegistration().getService();
+        String[] classNames = (String[]) ref.getProperty(Constants.OBJECTCLASS);
+
+        for (Class<?> hookClass : m_hookClasses)
+        {
+            if (isHook(classNames, hookClass, svcObj))
+            {
+                synchronized (m_allHooks)
+                {
+                    Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
+                    if (hooks != null)
+                    {
+                        List<ServiceReference<?>> refs = new ArrayList<ServiceReference<?>>(hooks);
+                        hooks.clear();
+                        hooks.addAll(refs);
+                    }
+                }
+            }
+        }
+    }
+
+    private void removeHook(ServiceReference ref)
+    {
+        Object svcObj = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
+            .getRegistration().getService();
+        String[] classNames = (String[]) ref.getProperty(Constants.OBJECTCLASS);
+
+        for (Class<?> hookClass : m_hookClasses)
+        {
+            if (isHook(classNames, hookClass, svcObj))
+            {
+                synchronized (m_allHooks)
+                {
+                    Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
+                    if (hooks != null)
+                    {
+                        hooks.remove(ref);
+                        if (hooks.isEmpty())
+                        {
+                            m_allHooks.remove(hookClass);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public <S> Set<ServiceReference<S>> getHooks(Class<S> hookClass)
+    {
+        synchronized (m_allHooks)
+        {
+            Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
+            if (hooks != null)
+            {
+                SortedSet sorted = new TreeSet<ServiceReference<?>>(Collections.reverseOrder());
+                sorted.addAll(hooks);
+                return asTypedSortedSet(sorted);
+            }
+            return Collections.EMPTY_SET;
+        }
+    }
+
+    private static <S> SortedSet<ServiceReference<S>> asTypedSortedSet(
+        SortedSet<ServiceReference<?>> ss)
+    {
+        return (SortedSet<ServiceReference<S>>) (SortedSet) ss;
+
+
+    }
+
+    private static class UsageCount
+    {
+        public int m_count = 0;
+        public ServiceReference m_ref = null;
+        public Object m_svcObj = null;
+    }
+
+    public interface ServiceRegistryCallbacks
+    {
+        void serviceChanged(ServiceEvent event, Dictionary oldProps);
+    }
+}
\ No newline at end of file

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Attribute.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Attribute.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Attribute.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Attribute.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,53 @@
+/*
+ * 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 de.kalpatec.pojosr.framework.felix.framework.capabilityset;
+
+public class Attribute
+{
+    private final String m_name;
+    private final Object m_value;
+    private final boolean m_isMandatory;
+
+    public Attribute(String name, Object value, boolean isMandatory)
+    {
+        m_name = name;
+        m_value = value;
+        m_isMandatory = isMandatory;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public Object getValue()
+    {
+        return m_value;
+    }
+
+    public boolean isMandatory()
+    {
+        return m_isMandatory;
+    }
+
+    public String toString()
+    {
+        return m_name + "=" + m_value;
+    }
+}
\ No newline at end of file

Added: felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Capability.java
URL: http://svn.apache.org/viewvc/felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Capability.java?rev=1583367&view=auto
==============================================================================
--- felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Capability.java (added)
+++ felix/trunk/pojosr/src/main/java/de/kalpatec/pojosr/framework/felix/framework/capabilityset/Capability.java Mon Mar 31 16:18:17 2014
@@ -0,0 +1,44 @@
+/*
+ * 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 de.kalpatec.pojosr.framework.felix.framework.capabilityset;
+
+import java.util.List;
+
+public interface Capability
+{
+    static final String MODULE_NAMESPACE = "module";
+    static final String HOST_NAMESPACE = "host";
+    static final String PACKAGE_NAMESPACE = "package";
+    static final String SINGLETON_NAMESPACE = "singleton";
+
+    public static final String PACKAGE_ATTR = "package";
+    public static final String VERSION_ATTR = "version";
+
+    String getNamespace();
+
+    Directive getDirective(String name);
+
+    List<Directive> getDirectives();
+
+    Attribute getAttribute(String name);
+
+    List<Attribute> getAttributes();
+
+    List<String> getUses();
+}
\ No newline at end of file