You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by dj...@apache.org on 2013/05/07 23:50:09 UTC

svn commit: r1480103 - in /felix/trunk/scr/src/main/java/org/apache/felix/scr/impl: ComponentRegistry.java TargetedPID.java config/ConfigurationSupport.java

Author: djencks
Date: Tue May  7 21:50:08 2013
New Revision: 1480103

URL: http://svn.apache.org/r1480103
Log:
FELIX-3651 implement r5 location binding

Added:
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java   (with props)
Modified:
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java?rev=1480103&r1=1480102&r2=1480103&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java Tue May  7 21:50:08 2013
@@ -452,8 +452,9 @@ public class ComponentRegistry implement
      * @param pid the pid candidate
      * @return the set of ComponentHolders matching the singleton pid supplied
      */
-    public final Collection<ComponentHolder> getComponentHoldersByPid(String pid)
+    public final Collection<ComponentHolder> getComponentHoldersByPid(TargetedPID targetedPid)
     {
+        String pid = targetedPid.getServicePid();
         Set<ComponentHolder> componentHoldersUsingPid = new HashSet<ComponentHolder>();
         synchronized (m_componentHoldersByPid)
         {
@@ -461,7 +462,13 @@ public class ComponentRegistry implement
             // only return the entry if non-null and not a reservation
             if (set != null)
             {
-                componentHoldersUsingPid.addAll(set);
+                for (ComponentHolder holder: set)
+                {
+                    if (targetedPid.matchesTarget(holder))
+                    {
+                        componentHoldersUsingPid.add( holder );
+                    }
+                }
             }
         }
         return componentHoldersUsingPid;

Added: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java?rev=1480103&view=auto
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java (added)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java Tue May  7 21:50:08 2013
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl;
+
+import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+
+/**
+ * Copied with modifications from felix configadmin.
+ * 
+ * The <code>TargetedPID</code> class represents a targeted PID as read
+ * from a configuration object.
+ * <p>
+ * For a factory configuration the <code>TargetedPID</code> represents
+ * the factory PID of the configuration. Otherwise it represents the
+ * PID itself of the configuration.
+ */
+public class TargetedPID
+{
+
+    private final String rawPid;
+
+    private final String servicePid;
+
+    private final String symbolicName;
+    private final String version;
+    private final String location;
+
+    /**
+     * The level of binding of this targeted PID:
+     * <ul>
+     * <li><code>0</code> -- this PID is not targeted at all</li>
+     * <li><code>1</code> -- this PID is targeted by the symbolic name</li>
+     * <li><code>2</code> -- this PID is targeted by the symbolic name and version</li>
+     * <li><code>3</code> -- this PID is targeted by the symoblic name, version, and location</li>
+     * </ul>
+     */
+    private final short bindingLevel;
+
+
+    /**
+     * Returns the bundle's version as required for targeted PIDs: If the
+     * bundle has a version the string representation of the version
+     * string converted to a Version object is returned. Otherwise the
+     * string representation of <code>Version.emptyVersion</code> is
+     * returned.
+     * <p>
+     * To remain compatible with pre-R4.2 (Framework API < 1.5) we cannot
+     * use the <code>Bundle.getVersion()</code> method.
+     *
+     * @param bundle The bundle whose version is to be returned.
+     */
+    public static String getBundleVersion( final Bundle bundle )
+    {
+        Object vHeader = bundle.getHeaders().get( Constants.BUNDLE_VERSION );
+        Version version = ( vHeader == null ) ? Version.emptyVersion : new Version( vHeader.toString() );
+        return version.toString();
+    }
+
+
+    public TargetedPID( final String rawPid )
+    {
+        this.rawPid = rawPid;
+
+        if ( rawPid.indexOf( '|' ) < 0 )
+        {
+            this.servicePid = rawPid;
+            this.symbolicName = null;
+            this.version = null;
+            this.location = null;
+            this.bindingLevel = 0;
+        }
+        else
+        {
+            int start = 0;
+            int end = rawPid.indexOf( '|' );
+            this.servicePid = rawPid.substring( start, end );
+
+            start = end + 1;
+            end = rawPid.indexOf( '|', start );
+            if ( end >= 0 )
+            {
+                this.symbolicName = rawPid.substring( start, end );
+                start = end + 1;
+                end = rawPid.indexOf( '|', start );
+                if ( end >= 0 )
+                {
+                    this.version = rawPid.substring( start, end );
+                    this.location = rawPid.substring( end + 1 );
+                    this.bindingLevel = 3;
+                }
+                else
+                {
+                    this.version = rawPid.substring( start );
+                    this.location = null;
+                    this.bindingLevel = 2;
+                }
+            }
+            else
+            {
+                this.symbolicName = rawPid.substring( start );
+                this.version = null;
+                this.location = null;
+                this.bindingLevel = 1;
+            }
+        }
+    }
+
+
+    /**
+     * Returns true if the target of this PID (bundle symbolic name,
+     * version, and location) match the bundle registering the referenced
+     * service.
+     * <p>
+     * This method just checks the target not the PID value itself, so
+     * this method returning <code>true</code> does not indicate whether
+     * the service actually is registered with a service PID equal to the
+     * raw PID of this targeted PID.
+     * <p>
+     * This method also returns <code>false</code> if the service has
+     * concurrently been unregistered and the registering bundle is now
+     * <code>null</code>.
+     *
+     * @param reference <code>ServiceReference</code> to the registered
+     *      service
+     * @return <code>true</code> if the referenced service matches the
+     *      target of this PID.
+     */
+    public boolean matchesTarget( ComponentHolder holder )
+    {
+        // already unregistered
+        final Bundle serviceBundle = holder.getActivator().getBundleContext().getBundle();
+        if ( serviceBundle == null )
+        {
+            return false;
+        }
+
+        // This is not really targeted
+        if ( this.symbolicName == null )
+        {
+            return true;
+        }
+
+        // bundle symbolic names don't match
+        if ( !this.symbolicName.equals( serviceBundle.getSymbolicName() ) )
+        {
+            return false;
+        }
+
+        // no more specific target
+        if ( this.version == null )
+        {
+            return true;
+        }
+
+        // bundle version does not match
+
+        if ( !this.version.equals( getBundleVersion( serviceBundle ) ) )
+        {
+            return false;
+        }
+
+        // assert bundle location match
+        return this.location == null || this.location.equals( serviceBundle.getLocation() );
+    }
+
+
+    /**
+     * Gets the raw PID with which this instance has been created.
+     * <p>
+     * If an actual service PID contains pipe symbols that PID might be
+     * considered being targeted PID without it actually being one. This
+     * method provides access to the raw PID to allow for such services to
+     * be configured.
+     */
+    public String getRawPid()
+    {
+        return rawPid;
+    }
+
+
+    /**
+     * Returns the service PID of this targeted PID which basically is
+     * the targeted PID without the targeting information.
+     */
+    public String getServicePid()
+    {
+        return servicePid;
+    }
+
+
+    /**
+     * Returns <code>true</code> if this targeted PID binds stronger than
+     * the <code>other</code> {@link TargetedPID}.
+     * <p>
+     * This method assumes both targeted PIDs have already been checked for
+     * suitability for the bundle encoded in the targetting.
+     *
+     * @param other The targeted PID to check whether it is binding stronger
+     *      or not.
+     * @return <code>true</code> if the <code>other</code> targeted PID
+     *      is binding strong.
+     */
+    public boolean bindsStronger( final TargetedPID other )
+    {
+        return other == null || this.bindingLevel > other.bindingLevel;
+    }
+
+
+    @Override
+    public int hashCode()
+    {
+        return this.rawPid.hashCode();
+    }
+
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == null )
+        {
+            return false;
+        }
+        else if ( obj == this )
+        {
+            return true;
+        }
+
+        // assume equality if same class and raw PID equals
+        if ( this.getClass() == obj.getClass() )
+        {
+            return this.rawPid.equals( ( ( TargetedPID ) obj ).rawPid );
+        }
+
+        // not the same class or different raw PID
+        return false;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return this.rawPid;
+    }
+}

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/TargetedPID.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java?rev=1480103&r1=1480102&r2=1480103&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java Tue May  7 21:50:08 2013
@@ -22,13 +22,20 @@ import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.felix.scr.impl.Activator;
 import org.apache.felix.scr.impl.BundleComponentActivator;
 import org.apache.felix.scr.impl.ComponentRegistry;
+import org.apache.felix.scr.impl.TargetedPID;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
@@ -38,6 +45,7 @@ import org.osgi.service.cm.Configuration
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.cm.ConfigurationEvent;
 import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.cm.ConfigurationPermission;
 import org.osgi.service.log.LogService;
 
 public class ConfigurationSupport implements ConfigurationListener
@@ -69,7 +77,7 @@ public class ConfigurationSupport implem
 
     // the service m_registration of the ConfigurationListener service
     private ServiceRegistration m_registration;
-
+    
     public ConfigurationSupport(final BundleContext bundleContext, final ComponentRegistry registry)
     {
         this.m_registry = registry;
@@ -114,26 +122,25 @@ public class ConfigurationSupport implem
                         if ( cao instanceof ConfigurationAdmin )
                         {
                             final ConfigurationAdmin ca = ( ConfigurationAdmin ) cao;
-                            final Configuration[] factory = findFactoryConfigurations(ca, confPid);
-                            if (factory != null)
+                            final Collection<Configuration> factory = findFactoryConfigurations(ca, confPid, bundleContext.getBundle());
+                            if (!factory.isEmpty())
                             {
-                                for (int i = 0; i < factory.length; i++)
+                                for (Configuration config: factory)
                                 {
-                                    final String pid = factory[i].getPid();
-                                    final Configuration config = getConfiguration(ca, pid, bundleLocation);
+                                    config = getConfiguration( ca, config.getPid(), bundleContext.getBundle() );
                                     long changeCount = changeCounter.getChangeCount( config, false, -1 );
-                                    holder.configurationUpdated(pid, config.getProperties(), changeCount);
+                                    holder.configurationUpdated(config.getPid(), config.getProperties(), changeCount);
                                 }
                             }
                             else
                             {
                                 // check for configuration and configure the holder
-                                final Configuration singleton = findSingletonConfiguration(ca, confPid);
+                                Configuration singleton = findSingletonConfiguration(ca, confPid, bundleContext.getBundle());
                                 if (singleton != null)
                                 {
-                                    final Configuration config = getConfiguration(ca, confPid, bundleLocation);
-                                    long changeCount = changeCounter.getChangeCount( config, false, -1 );
-                                    holder.configurationUpdated(confPid, config.getProperties(), changeCount);
+                                    singleton = getConfiguration( ca, singleton.getPid(), bundleContext.getBundle() );
+                                    long changeCount = changeCounter.getChangeCount( singleton, false, -1 );
+                                    holder.configurationUpdated(confPid, singleton.getProperties(), changeCount);
                                 }
                             }
                         }
@@ -203,8 +210,9 @@ public class ConfigurationSupport implem
      */
     public void configurationEvent(ConfigurationEvent event)
     {
-        final String pid = event.getPid();
-        final String factoryPid = event.getFactoryPid();
+        final TargetedPID pid = new TargetedPID( event.getPid());
+        String rawFactoryPid = event.getFactoryPid();
+        final TargetedPID factoryPid = rawFactoryPid == null? null: new TargetedPID( rawFactoryPid);
 
         // iterate over all components which must be configured with this pid
         // (since DS 1.2, components may specify a specific configuration PID (112.4.4 configuration-pid)
@@ -229,7 +237,7 @@ public class ConfigurationSupport implem
             {
                 switch (event.getType()) {
                 case ConfigurationEvent.CM_DELETED:
-                    componentHolder.configurationDeleted(pid);
+                    componentHolder.configurationDeleted(pid.getServicePid());
                     break;
 
                 case ConfigurationEvent.CM_UPDATED:
@@ -259,12 +267,11 @@ public class ConfigurationSupport implem
                                     if ( cao instanceof ConfigurationAdmin )
                                     {
                                         final ConfigurationAdmin ca = ( ConfigurationAdmin ) cao;
-                                        final Configuration config = getConfiguration( ca, pid, bundleContext
-                                            .getBundle().getLocation() );
+                                        final Configuration config = getConfiguration( ca, pid.getRawPid(), bundleContext.getBundle() );
                                         if ( config != null )
                                         {
-                                            long changeCount = changeCounter.getChangeCount( config, true, componentHolder.getChangeCount( pid ) );
-                                            componentHolder.configurationUpdated( pid, config.getProperties(), changeCount );
+                                            long changeCount = changeCounter.getChangeCount( config, true, componentHolder.getChangeCount( pid.getServicePid() ) );
+                                            componentHolder.configurationUpdated( pid.getServicePid(), config.getProperties(), changeCount );
                                         }
                                     }
                                     else
@@ -294,8 +301,7 @@ public class ConfigurationSupport implem
                     break;
 
                 case ConfigurationEvent.CM_LOCATION_CHANGED:
-                    // FELIX-3650: Don't log WARNING message
-                    // FELIX-3584: Implement event support
+                        // FELIX-3584: Implement event support
                     break;
 
                 default:
@@ -306,19 +312,19 @@ public class ConfigurationSupport implem
         }
     }
 
-    private Configuration getConfiguration(final ConfigurationAdmin ca, final String pid, final String bundleLocation)
+    private Configuration getConfiguration(final ConfigurationAdmin ca, final String pid, final Bundle bundle)
     {
         try
         {
             final Configuration cfg = ca.getConfiguration(pid);
-            if (bundleLocation.equals(cfg.getBundleLocation()))
+            if (checkBundleLocation( cfg, bundle ))
             {
                 return cfg;
             }
 
             // configuration belongs to another bundle, cannot be used here
-            Activator.log(LogService.LOG_ERROR, null, "Cannot use configuration pid=" + pid + " for bundle "
-                + bundleLocation + " because it belongs to bundle " + cfg.getBundleLocation(), null);
+            Activator.log(LogService.LOG_INFO, null, "Cannot use configuration pid=" + pid + " for bundle "
+                + bundle.getLocation() + " because it belongs to bundle " + cfg.getBundleLocation(), null);
         }
         catch (IOException ioe)
         {
@@ -334,13 +340,33 @@ public class ConfigurationSupport implem
      *
      * @param ca Configuration Admin service
      * @param pid Pid for desired configuration
+     * @param bundle TODO
      * @return configuration with the specified Pid
      */
-    public Configuration findSingletonConfiguration(final ConfigurationAdmin ca, final String pid)
+    public Configuration findSingletonConfiguration(final ConfigurationAdmin ca, final String pid, Bundle bundle)
     {
-        final String filter = "(service.pid=" + pid + ")";
+        final String filter = getTargetedPidFilter( pid, bundle, Constants.SERVICE_PID );
         final Configuration[] cfg = findConfigurations(ca, filter);
-        return (cfg == null || cfg.length == 0) ? null : cfg[0];
+        if (cfg == null)
+        {
+            return null;
+        }
+        String longest = null;
+        Configuration best = null;
+        for (Configuration config: cfg)
+        {
+            if ( checkBundleLocation( config, bundle ) )
+            {
+                String testPid = config.getPid();
+                if ( longest == null || testPid.length() > longest.length())
+                {
+                    longest = testPid;
+                    best = config;
+                }
+            }
+            
+        }
+        return best;
     }
 
     /**
@@ -349,12 +375,54 @@ public class ConfigurationSupport implem
      *
      * @param ca ConfigurationAdmin service
      * @param factoryPid factory Pid we want the configurations for
+     * @param bundle bundle we're working for (for location and location permission)
      * @return the configurations specifying the supplied factory Pid.
      */
-    public Configuration[] findFactoryConfigurations(final ConfigurationAdmin ca, final String factoryPid)
+    private Collection<Configuration> findFactoryConfigurations(final ConfigurationAdmin ca, final String factoryPid, Bundle bundle)
     {
-        final String filter = "(service.factoryPid=" + factoryPid + ")";
-        return findConfigurations(ca, filter);
+        final String filter = getTargetedPidFilter( factoryPid, bundle, ConfigurationAdmin.SERVICE_FACTORYPID );
+        Configuration[] configs = findConfigurations(ca, filter);
+        if (configs == null)
+        {
+            return Collections.emptyList();
+        }
+        Map<String, Configuration> configsByPid = new HashMap<String, Configuration>();
+        for (Configuration config: configs)
+        {
+            if ( checkBundleLocation( config, bundle ) )
+            {
+                Configuration oldConfig = configsByPid.get( config.getPid() );
+                if ( oldConfig == null )
+                {
+                    configsByPid.put( config.getPid(), config );
+                }
+                else
+                {
+                    String newPid = config.getFactoryPid();
+                    String oldPid = oldConfig.getFactoryPid();
+                    if ( newPid.length() > oldPid.length() )
+                    {
+                        configsByPid.put( config.getPid(), config );
+                    }
+                }
+            }
+        }
+        return configsByPid.values();
+    }
+    
+    private boolean checkBundleLocation(Configuration config, Bundle bundle)
+    {
+        String configBundleLocation = config.getBundleLocation();
+        if ( configBundleLocation == null)
+        {
+            return true;
+        }
+        if (configBundleLocation.startsWith( "?" ))
+        {
+            //multilocation
+            return bundle.hasPermission(new ConfigurationPermission(configBundleLocation, ConfigurationPermission.TARGET));
+        }
+        return configBundleLocation.equals(bundle.getLocation());
     }
 
     private Configuration[] findConfigurations(final ConfigurationAdmin ca, final String filter)
@@ -376,6 +444,17 @@ public class ConfigurationSupport implem
         return null;
     }
     
+    private String getTargetedPidFilter(String pid, Bundle bundle, String key)
+    {
+        String bsn = bundle.getSymbolicName();
+        String version = bundle.getVersion().toString();
+        String location = bundle.getLocation();
+        String f = String.format(
+                "(|(%1$s=%2$s)(%1$s=%2$s|%3$s)(%1$s=%2$s|%3$s|%4$s)(%1$s=%2$s|%3$s|%4$s|%5$s))", 
+                key, pid, bsn, version, location );
+        return f;
+    }
+    
     
     private interface ChangeCount {
         long getChangeCount( Configuration configuration, boolean fromEvent, long previous );