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