You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2015/07/09 00:10:16 UTC
svn commit: r1689973 [12/25] - in
/felix/sandbox/pderop/dependencymanager.ds: cnf/ext/ cnf/localrepo/
cnf/localrepo/org.apache.felix.framework/ cnf/releaserepo/
org.apache.felix.dependencymanager.ds.itest/
org.apache.felix.dependencymanager.ds.itest/.s...
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurationSupport.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurationSupport.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurationSupport.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurationSupport.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,680 @@
+/*
+ * 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.config;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+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;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+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
+{
+ private static final ChangeCount changeCounter;
+ static
+ {
+ ChangeCount cc = null;
+ try
+ {
+ Configuration.class.getMethod( "getChangeCount", (Class<?>[]) null );
+ cc = new R5ChangeCount();
+ }
+ catch ( SecurityException e )
+ {
+ }
+ catch ( NoSuchMethodException e )
+ {
+ }
+ if ( cc == null )
+ {
+ cc = new R4ChangeCount();
+ }
+ changeCounter = cc;
+ }
+
+ // the registry of components to be configured
+ private final ComponentRegistry m_registry;
+
+ // the service m_registration of the ConfigurationListener service
+ private ServiceRegistration<?> m_registration;
+
+ public ConfigurationSupport(final BundleContext bundleContext, final ComponentRegistry registry)
+ {
+ this.m_registry = registry;
+
+ // register as listener for configurations
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(Constants.SERVICE_DESCRIPTION, "Declarative Services Configuration Support Listener");
+ props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+ this.m_registration = bundleContext.registerService(new String[]
+ { "org.osgi.service.cm.ConfigurationListener" }, this, props);
+ }
+
+ public void dispose()
+ {
+ if (this.m_registration != null)
+ {
+ this.m_registration.unregister();
+ this.m_registration = null;
+ }
+ }
+
+ // ---------- BaseConfigurationSupport overwrites
+
+ public boolean configureComponentHolder(final ComponentHolder<?> holder)
+ {
+
+ // 112.7 configure unless configuration not required
+ if (!holder.getComponentMetadata().isConfigurationIgnored())
+ {
+ final BundleContext bundleContext = holder.getActivator().getBundleContext();
+ if ( bundleContext == null )
+ {
+ return false;// bundle was stopped concurrently with configuration deletion
+ }
+ final List<String> confPids = holder.getComponentMetadata().getConfigurationPid();
+
+ final ServiceReference<?> caRef = bundleContext.getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
+ if (caRef != null)
+ {
+ final Object cao = bundleContext.getService(caRef);
+ if (cao != null)
+ {
+ try
+ {
+ if ( cao instanceof ConfigurationAdmin )
+ {
+ final ConfigurationAdmin ca = ( ConfigurationAdmin ) cao;
+ for (final String confPid : confPids )
+ {
+ final Collection<Configuration> factory = findFactoryConfigurations( ca, confPid,
+ bundleContext.getBundle() );
+ if ( !factory.isEmpty() )
+ {
+ for ( Configuration config: factory )
+ {
+ boolean created = false;
+ Activator.log( LogService.LOG_DEBUG, null,
+ "Configuring holder {0} with factory configuration {1}", new Object[] {
+ holder, config }, null );
+ config = getConfiguration( ca, config.getPid() );
+ if ( checkBundleLocation( config, bundleContext.getBundle() ) )
+ {
+ long changeCount = changeCounter.getChangeCount( config, false, -1 );
+ created |= holder.configurationUpdated( new TargetedPID( config.getPid() ),
+ new TargetedPID( config.getFactoryPid() ),
+ config.getProperties(),
+ changeCount );
+ }
+ if ( !created )
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // check for configuration and configure the holder
+ Configuration singleton = findSingletonConfiguration( ca, confPid,
+ bundleContext.getBundle() );
+ if ( singleton != null )
+ {
+ singleton = getConfiguration( ca, singleton.getPid() );
+ Activator.log( LogService.LOG_DEBUG, null,
+ "Configuring holder {0} with configuration {1}", new Object[] { holder,
+ singleton }, null );
+ if ( singleton != null
+ && checkBundleLocation( singleton, bundleContext.getBundle() ) )
+ {
+ long changeCount = changeCounter.getChangeCount( singleton, false, -1 );
+ holder.configurationUpdated( new TargetedPID( singleton.getPid() ), null,
+ singleton.getProperties(), changeCount );
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ return !confPids.isEmpty();
+ }
+ else
+ {
+ Activator.log( LogService.LOG_WARNING, null, "Cannot configure component {0}",
+ new Object[] {holder.getComponentMetadata().getName()}, null );
+ Activator.log( LogService.LOG_WARNING, null,
+ "Component Bundle's Configuration Admin is not compatible with "
+ + "ours. This happens if multiple Configuration Admin API versions "
+ + "are deployed and different bundles wire to different versions", null );
+ return false;
+
+ }
+ }
+ finally
+ {
+ try
+ {
+ bundleContext.ungetService( caRef );
+ }
+ catch ( IllegalStateException e )
+ {
+ // ignore, bundle context was shut down during the above.
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ // ---------- ServiceListener
+
+ public void configureComponentHolders(final ServiceReference<ConfigurationAdmin> configurationAdminReference,
+ final Object configurationAdmin)
+ {
+ if (configurationAdmin instanceof ConfigurationAdmin)
+ {
+ Configuration[] configs = findConfigurations((ConfigurationAdmin) configurationAdmin, null);
+ if (configs != null)
+ {
+ for (int i = 0; i < configs.length; i++)
+ {
+ ConfigurationEvent cfgEvent = new ConfigurationEvent(configurationAdminReference,
+ ConfigurationEvent.CM_UPDATED, configs[i].getFactoryPid(), configs[i].getPid());
+ configurationEvent(cfgEvent);
+ }
+ }
+ }
+ }
+
+ // ---------- ConfigurationListener
+
+ /**
+ * Called by the Configuration Admin service if a configuration is updated
+ * or removed.
+ * <p>
+ * This method is really only called upon configuration changes; it is not
+ * called for existing configurations upon startup of the Configuration
+ * Admin service. To bridge this gap, the
+ * {@link ComponentRegistry#serviceChanged(org.osgi.framework.ServiceEvent)} method called when the
+ * Configuration Admin service is registered calls #configureComponentHolders which calls this method for all
+ * existing configurations to be able to forward existing configurations to
+ * components.
+ *
+ * @param event The configuration change event
+ */
+ public void configurationEvent(ConfigurationEvent event)
+ {
+ 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)
+ Collection<ComponentHolder<?>> holders;
+
+ if (factoryPid == null)
+ {
+ holders = this.m_registry.getComponentHoldersByPid(pid);
+ }
+ else
+ {
+ holders = this.m_registry.getComponentHoldersByPid(factoryPid);
+ }
+
+ Activator.log(LogService.LOG_DEBUG, null, "configurationEvent: Handling {0} of Configuration PID={1} for component holders {2}",
+ new Object[] {getEventType(event), pid, holders},
+ null);
+
+ for ( ComponentHolder<?> componentHolder: holders )
+ {
+ if (!componentHolder.getComponentMetadata().isConfigurationIgnored())
+ {
+ switch (event.getType()) {
+ case ConfigurationEvent.CM_DELETED:
+ if ( factoryPid != null || !configureComponentHolder( componentHolder ) )
+ {
+ componentHolder.configurationDeleted( pid, factoryPid );
+ }
+ break;
+
+ case ConfigurationEvent.CM_UPDATED:
+ {
+ final BundleComponentActivator activator = componentHolder.getActivator();
+ if (activator == null)
+ {
+ break;
+ }
+
+ final BundleContext bundleContext = activator.getBundleContext();
+ if (bundleContext == null)
+ {
+ break;
+ }
+
+ TargetedPID targetedPid = factoryPid == null? pid: factoryPid;
+ TargetedPID oldTargetedPID = componentHolder.getConfigurationTargetedPID(pid, factoryPid);
+ if ( factoryPid != null || targetedPid.equals(oldTargetedPID) || targetedPid.bindsStronger( oldTargetedPID ))
+ {
+ final ConfigurationInfo configInfo = getConfigurationInfo( pid, targetedPid, componentHolder, bundleContext );
+ if ( checkBundleLocation( configInfo.getBundleLocation(), bundleContext.getBundle() ) )
+ {
+ //If this is replacing a weaker targetedPID delete the old one.
+ if ( factoryPid == null && !targetedPid.equals(oldTargetedPID) && oldTargetedPID != null)
+ {
+ componentHolder.configurationDeleted( pid, factoryPid );
+ }
+ componentHolder.configurationUpdated( pid, factoryPid, configInfo.getProps(), configInfo.getChangeCount() );
+ }
+ }
+
+ break;
+ }
+ case ConfigurationEvent.CM_LOCATION_CHANGED:
+ {
+ //TODO is this logic correct for factory pids????
+ final BundleComponentActivator activator = componentHolder.getActivator();
+ if (activator == null)
+ {
+ break;
+ }
+
+ final BundleContext bundleContext = activator.getBundleContext();
+ if (bundleContext == null)
+ {
+ break;
+ }
+
+ TargetedPID targetedPid = factoryPid == null? pid: factoryPid;
+ TargetedPID oldTargetedPID = componentHolder.getConfigurationTargetedPID(pid, factoryPid);
+ if ( targetedPid.equals(oldTargetedPID))
+ {
+ //this sets the location to this component's bundle if not already set. OK here
+ //since it used to be set to this bundle, ok to reset it
+ final ConfigurationInfo configInfo = getConfigurationInfo( pid, targetedPid, componentHolder, bundleContext );
+ Activator.log(LogService.LOG_DEBUG, null, "LocationChanged event, same targetedPID {0}, location now {1}",
+ new Object[] {targetedPid, configInfo.getBundleLocation()},
+ null);
+ if (configInfo.getProps() == null)
+ {
+ throw new IllegalStateException("Existing Configuration with pid " + pid +
+ " has had its properties set to null and location changed. We expected a delete event first.");
+ }
+ //this config was used on this component. Does it still match?
+ if (!checkBundleLocation( configInfo.getBundleLocation(), bundleContext.getBundle() ))
+ {
+ //no, delete it
+ componentHolder.configurationDeleted( pid, factoryPid );
+ //maybe there's another match
+ configureComponentHolder(componentHolder);
+
+ }
+ //else still matches
+ break;
+ }
+ boolean better = targetedPid.bindsStronger( oldTargetedPID );
+ if ( better )
+ {
+ //this sets the location to this component's bundle if not already set. OK here
+ //because if it is set to this bundle we will use it.
+ final ConfigurationInfo configInfo = getConfigurationInfo( pid, targetedPid, componentHolder, bundleContext );
+ Activator.log(LogService.LOG_DEBUG, null, "LocationChanged event, better targetedPID {0} compared to {1}, location now {2}",
+ new Object[] {targetedPid, oldTargetedPID, configInfo.getBundleLocation()},
+ null);
+ if (configInfo.getProps() == null)
+ {
+ //location has been changed before any properties are set. We don't care. Wait for an updated event with the properties
+ break;
+ }
+ //this component was not configured with this config. Should it be now?
+ if ( checkBundleLocation( configInfo.getBundleLocation(), bundleContext.getBundle() ) )
+ {
+ if ( oldTargetedPID != null )
+ {
+ //this is a better match, delete old before setting new
+ componentHolder.configurationDeleted( pid, factoryPid );
+ }
+ componentHolder.configurationUpdated( pid, factoryPid,
+ configInfo.getProps(), configInfo.getChangeCount() );
+ }
+ }
+ //else worse match, do nothing
+ else
+ {
+ Activator.log(LogService.LOG_DEBUG, null, "LocationChanged event, worse targetedPID {0} compared to {1}, do nothing",
+ new Object[] {targetedPid, oldTargetedPID},
+ null);
+ }
+ break;
+ }
+ default:
+ Activator.log(LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type {0}", new Object[] {event.getType()},
+ null);
+ }
+ }
+ }
+ }
+
+
+ private String getEventType(ConfigurationEvent event)
+ {
+ switch (event.getType())
+ {
+ case ConfigurationEvent.CM_UPDATED:
+ return "UPDATED";
+ case ConfigurationEvent.CM_DELETED:
+ return "DELETED";
+ case ConfigurationEvent.CM_LOCATION_CHANGED:
+ return "LOCATION CHANGED";
+ default:
+ return "Unkown event type: " + event.getType();
+ }
+
+ }
+
+ private static class ConfigurationInfo
+ {
+ private final Dictionary<String, Object> props;
+ private final String bundleLocation;
+ private final long changeCount;
+
+ public ConfigurationInfo(Dictionary<String, Object> props, String bundleLocation, long changeCount)
+ {
+ this.props = props;
+ this.bundleLocation = bundleLocation;
+ this.changeCount = changeCount;
+ }
+
+ public long getChangeCount()
+ {
+ return changeCount;
+ }
+
+ public Dictionary<String, Object> getProps()
+ {
+ return props;
+ }
+
+ public String getBundleLocation()
+ {
+ return bundleLocation;
+ }
+
+ }
+
+ /**
+ * This gets config admin, gets the requested configuration, extracts the info we need from it, and ungets config admin.
+ * Some versions of felix config admin do not allow access to configurations after the config admin instance they were obtained from
+ * are ungot. Extracting the info we need into "configInfo" solves this problem.
+ *
+ * @param pid TargetedPID for the desired configuration
+ * @param targetedPid the targeted factory pid for a factory configuration or the pid for a singleton configuration
+ * @param componentHolder ComponentHolder that holds the old change count (for r4 fake change counting)
+ * @param bundleContext BundleContext to get the CA from
+ * @return ConfigurationInfo object containing the info we need from the configuration.
+ */
+ private ConfigurationInfo getConfigurationInfo(final TargetedPID pid, TargetedPID targetedPid,
+ ComponentHolder<?> componentHolder, final BundleContext bundleContext)
+ {
+ final ServiceReference caRef = bundleContext
+ .getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
+ if (caRef != null)
+ {
+ try
+ {
+ final Object cao = bundleContext.getService(caRef);
+ if (cao != null)
+ {
+ try
+ {
+ if ( cao instanceof ConfigurationAdmin )
+ {
+ final ConfigurationAdmin ca = ( ConfigurationAdmin ) cao;
+ final Configuration config = getConfiguration( ca, pid.getRawPid() );
+ return new ConfigurationInfo(config.getProperties(), config.getBundleLocation(),
+ changeCounter.getChangeCount( config, true, componentHolder.getChangeCount( pid, targetedPid ) ) );
+ }
+ else
+ {
+ Activator.log( LogService.LOG_WARNING, null, "Cannot reconfigure component {0}",
+ new Object[] {componentHolder.getComponentMetadata().getName()}, null );
+ Activator.log( LogService.LOG_WARNING, null,
+ "Component Bundle's Configuration Admin is not compatible with " +
+ "ours. This happens if multiple Configuration Admin API versions " +
+ "are deployed and different bundles wire to different versions",
+ null );
+ }
+ }
+ finally
+ {
+ bundleContext.ungetService( caRef );
+ }
+ }
+ }
+ catch (IllegalStateException ise)
+ {
+ // If the bundle has been stopped concurrently
+ Activator.log(LogService.LOG_WARNING, null, "Bundle in unexpected state",
+ ise);
+ }
+ }
+ return null;
+ }
+
+ private Configuration getConfiguration(final ConfigurationAdmin ca, final String pid)
+ {
+ try
+ {
+ return ca.getConfiguration(pid);
+ }
+ catch (IOException ioe)
+ {
+ Activator.log(LogService.LOG_WARNING, null, "Failed reading configuration for pid={0}", new Object[] {pid}, ioe);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the configuration whose PID equals the given pid. If no such
+ * configuration exists, <code>null</code> is returned.
+ *
+ * @param ca Configuration Admin service
+ * @param pid Pid for desired configuration
+ * @param bundle bundle of the component we are configuring (used in targeted pids)
+ * @return configuration with the specified Pid
+ */
+ public Configuration findSingletonConfiguration(final ConfigurationAdmin ca, final String pid, Bundle bundle)
+ {
+ final String filter = getTargetedPidFilter( pid, bundle, Constants.SERVICE_PID );
+ final Configuration[] cfg = findConfigurations(ca, filter);
+ 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;
+ }
+
+ /**
+ * Returns all configurations whose factory PID equals the given factory PID
+ * or <code>null</code> if no such configurations exist
+ *
+ * @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.
+ */
+ private Collection<Configuration> findFactoryConfigurations(final ConfigurationAdmin ca, final String factoryPid, Bundle bundle)
+ {
+ 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)
+ {
+ if (config == null)
+ {
+ return false;
+ }
+ String configBundleLocation = config.getBundleLocation();
+ return checkBundleLocation( configBundleLocation, bundle );
+ }
+
+ private boolean checkBundleLocation(String configBundleLocation, Bundle bundle)
+ {
+ 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)
+ {
+ try
+ {
+ return ca.listConfigurations(filter);
+ }
+ catch (IOException ioe)
+ {
+ Activator.log(LogService.LOG_WARNING, null, "Problem listing configurations for filter={0}", new Object[] {filter}, ioe);
+ }
+ catch (InvalidSyntaxException ise)
+ {
+ Activator.log(LogService.LOG_ERROR, null, "Invalid Configuration selection filter {0}", new Object[] {filter}, ise);
+ }
+
+ // no factories in case of problems
+ return null;
+ }
+
+ private String getTargetedPidFilter(String pid, Bundle bundle, String key)
+ {
+ String bsn = bundle.getSymbolicName();
+ String version = bundle.getVersion().toString();
+ String location = escape(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;
+ }
+
+ /**
+ * see core spec 3.2.7. Escape \*() with preceding \
+ * @param value
+ * @return escaped string
+ */
+ static final String escape(String value)
+ {
+ return value.replaceAll( "([\\\\\\*\\(\\)])", "\\\\$1" );
+ }
+
+
+ private interface ChangeCount {
+ long getChangeCount( Configuration configuration, boolean fromEvent, long previous );
+ }
+
+ private static class R5ChangeCount implements ChangeCount {
+
+ public long getChangeCount(Configuration configuration, boolean fromEvent, long previous)
+ {
+ return configuration.getChangeCount();
+ }
+ }
+
+ private static class R4ChangeCount implements ChangeCount {
+
+ public long getChangeCount(Configuration configuration, boolean fromEvent, long previous)
+ {
+ return fromEvent? previous + 1:0;
+ }
+
+ }
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ReferenceManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ReferenceManager.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ReferenceManager.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ReferenceManager.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,49 @@
+/*
+ * 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.config;
+
+import java.util.List;
+
+import org.osgi.framework.ServiceReference;
+
+public interface ReferenceManager<S, T> {
+
+ /**
+ * Returns an array of <code>ServiceReference</code> instances of all
+ * services this instance is bound to or <code>null</code> if no services
+ * are actually bound.
+ */
+ List<ServiceReference<?>> getServiceReferences();
+
+ /**
+ * Returns the name of the service reference.
+ */
+ String getName();
+
+ /**
+ * Returns the target filter of this dependency as a string or
+ * <code>null</code> if this dependency has no target filter set.
+ *
+ * @return The target filter of this dependency or <code>null</code> if
+ * none is set.
+ */
+ String getTarget();
+
+ boolean isSatisfied();
+}
\ No newline at end of file
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrConfiguration.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrConfiguration.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrConfiguration.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrConfiguration.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,360 @@
+/*
+ * 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.config;
+
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.scr.impl.Activator;
+import org.apache.felix.scr.impl.ScrCommand;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+
+
+/**
+ * The <code>ScrConfiguration</code> class conveys configuration for the
+ * Felix DS implementation bundle.
+ * <p>
+ * <b>Configuration Source</b>
+ * <p>
+ * <ol>
+ * <li>Framework properties: These are read when the Declarative Services
+ * implementation is first started.</li>
+ * <li>Configuration Admin Service: Properties are provided by means of a
+ * <code>ManagedService</code> with Service PID
+ * <code>org.apache.felix.scr.ScrService</code>. This class uses an OSGi
+ * Service Factory ({@link ScrManagedServiceServiceFactory}) to register the
+ * managed service without requiring the Configuration Admin Service API to be
+ * required upfront.
+ * </li>
+ * </ol>
+ * <p>
+ * See the <i>Configuration</i> section of the
+ * <a href="http://felix.apache.org/site/apache-felix-service-component-runtime.html">Apache Felix Service Component Runtime</a>
+ * documentation page for detailed information.
+ */
+public class ScrConfiguration
+{
+
+ private static final String VALUE_TRUE = Boolean.TRUE.toString();
+
+ public static final String PID = "org.apache.felix.scr.ScrService";
+
+ public static final String PROP_FACTORY_ENABLED = "ds.factory.enabled";
+
+ public static final String PROP_DELAYED_KEEP_INSTANCES = "ds.delayed.keepInstances";
+
+ public static final String PROP_INFO_SERVICE = "ds.info.service";
+
+ public static final String PROP_LOCK_TIMEOUT = "ds.lock.timeout.milliseconds";
+
+ public static final String PROP_STOP_TIMEOUT = "ds.stop.timeout.milliseconds";
+
+ public static final long DEFAULT_LOCK_TIMEOUT_MILLISECONDS = 5000;
+
+ public static final long DEFAULT_STOP_TIMEOUT_MILLISECONDS = 60000;
+
+ public static final String PROP_LOGLEVEL = "ds.loglevel";
+
+ private static final String LOG_LEVEL_DEBUG = "debug";
+
+ private static final String LOG_LEVEL_INFO = "info";
+
+ private static final String LOG_LEVEL_WARN = "warn";
+
+ private static final String LOG_LEVEL_ERROR = "error";
+
+ private static final String PROP_SHOWTRACE = "ds.showtrace";
+
+ private static final String PROP_SHOWERRORS = "ds.showerrors";
+
+ public static final String PROP_GLOBAL_EXTENDER="ds.global.extender";
+
+ private final Activator activator;
+
+ private int logLevel;
+
+ private boolean factoryEnabled;
+
+ private boolean keepInstances;
+
+ private boolean infoAsService;
+
+ private long lockTimeout = DEFAULT_LOCK_TIMEOUT_MILLISECONDS;
+
+ private long stopTimeout = DEFAULT_STOP_TIMEOUT_MILLISECONDS;
+
+ private Boolean globalExtender;
+
+ private BundleContext bundleContext;
+
+ private ServiceRegistration<ManagedService> managedService;
+
+ private ScrCommand scrCommand;
+
+ public ScrConfiguration( Activator activator )
+ {
+ this.activator = activator;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void start(final BundleContext bundleContext)
+ {
+ this.bundleContext = bundleContext;
+
+ // listen for Configuration Admin configuration
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(Constants.SERVICE_PID, PID);
+ props.put(Constants.SERVICE_DESCRIPTION, "SCR Configurator");
+ props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+
+
+ // Process configure from bundle context properties so they can be predictably
+ // overriden by configuration admin later.
+ // Note that if the managed service is registered first then it is random which will win since
+ // configuration may be delivered asynchronously
+ configure( null, false );
+
+ managedService = ( ServiceRegistration<ManagedService> ) bundleContext.registerService("org.osgi.service.cm.ManagedService", new ScrManagedServiceServiceFactory(this),
+ props);
+ }
+
+ public void stop() {
+ if (this.managedService != null) {
+ this.managedService.unregister();
+ this.managedService = null;
+ }
+
+ this.bundleContext = null;
+ }
+
+ public void setScrCommand(ScrCommand scrCommand)
+ {
+ this.scrCommand = scrCommand;
+ scrCommand.update(infoAsService());
+ }
+
+ // Called from the ScrManagedService.updated method to reconfigure
+ void configure( Dictionary<String, ?> config, boolean fromConfig )
+ {
+ Boolean newGlobalExtender;
+ Boolean oldGlobalExtender;
+ synchronized (this)
+ {
+ if ( config == null )
+ {
+ if (!fromConfig)
+ {
+ if (this.bundleContext == null)
+ {
+ logLevel = LogService.LOG_ERROR;
+ factoryEnabled = false;
+ keepInstances = false;
+ infoAsService = false;
+ lockTimeout = DEFAULT_LOCK_TIMEOUT_MILLISECONDS;
+ stopTimeout = DEFAULT_STOP_TIMEOUT_MILLISECONDS;
+ newGlobalExtender = false;
+ }
+ else
+ {
+ logLevel = getDefaultLogLevel();
+ factoryEnabled = getDefaultFactoryEnabled();
+ keepInstances = getDefaultKeepInstances();
+ infoAsService = getDefaultInfoAsService();
+ lockTimeout = getDefaultLockTimeout();
+ stopTimeout = getDefaultStopTimeout();
+ newGlobalExtender = getDefaultGlobalExtender();
+ }
+ }
+ else
+ {
+ newGlobalExtender = this.globalExtender;
+ }
+ }
+ else
+ {
+ logLevel = getLogLevel( config.get( PROP_LOGLEVEL ) );
+ factoryEnabled = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_FACTORY_ENABLED ) ) );
+ keepInstances = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_DELAYED_KEEP_INSTANCES ) ) );
+ infoAsService = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_INFO_SERVICE) ) );
+ Long timeout = ( Long ) config.get( PROP_LOCK_TIMEOUT );
+ lockTimeout = timeout == null? DEFAULT_LOCK_TIMEOUT_MILLISECONDS: timeout;
+ timeout = ( Long ) config.get( PROP_STOP_TIMEOUT );
+ stopTimeout = timeout == null? DEFAULT_STOP_TIMEOUT_MILLISECONDS: timeout;
+ newGlobalExtender = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_GLOBAL_EXTENDER) ) );
+ }
+ if ( scrCommand != null )
+ {
+ scrCommand.update( infoAsService() );
+ }
+ oldGlobalExtender = this.globalExtender;
+ this.globalExtender = newGlobalExtender;
+ }
+ if ( newGlobalExtender != oldGlobalExtender )
+ {
+ activator.restart( newGlobalExtender );
+ }
+ }
+
+ /**
+ * Returns the current log level.
+ * @return
+ */
+ public int getLogLevel()
+ {
+ return logLevel;
+ }
+
+
+ public boolean isFactoryEnabled()
+ {
+ return factoryEnabled;
+ }
+
+
+ public boolean keepInstances()
+ {
+ return keepInstances;
+ }
+
+ public boolean infoAsService()
+ {
+ return infoAsService;
+ }
+
+ public long lockTimeout()
+ {
+ return lockTimeout;
+ }
+
+ public long stopTimeout()
+ {
+ return stopTimeout;
+ }
+
+ public boolean globalExtender()
+ {
+ return globalExtender;
+ }
+
+ private boolean getDefaultFactoryEnabled()
+ {
+ return VALUE_TRUE.equals( bundleContext.getProperty( PROP_FACTORY_ENABLED ) );
+ }
+
+
+ private boolean getDefaultKeepInstances()
+ {
+ return VALUE_TRUE.equals( bundleContext.getProperty( PROP_DELAYED_KEEP_INSTANCES ) );
+ }
+
+
+ private int getDefaultLogLevel()
+ {
+ return getLogLevel( bundleContext.getProperty( PROP_LOGLEVEL ) );
+ }
+
+ private boolean getDefaultInfoAsService()
+ {
+ return VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty( PROP_INFO_SERVICE) );
+ }
+
+ private long getDefaultLockTimeout()
+ {
+ String val = bundleContext.getProperty( PROP_LOCK_TIMEOUT);
+ if ( val == null)
+ {
+ return DEFAULT_LOCK_TIMEOUT_MILLISECONDS;
+ }
+ return Long.parseLong( val );
+ }
+
+ private long getDefaultStopTimeout()
+ {
+ String val = bundleContext.getProperty( PROP_STOP_TIMEOUT);
+ if ( val == null)
+ {
+ return DEFAULT_STOP_TIMEOUT_MILLISECONDS;
+ }
+ return Long.parseLong( val );
+ }
+
+
+ private boolean getDefaultGlobalExtender()
+ {
+ return VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty( PROP_GLOBAL_EXTENDER) );
+ }
+
+ private int getLogLevel( final Object levelObject )
+ {
+ if ( levelObject != null )
+ {
+ if ( levelObject instanceof Number )
+ {
+ return ( ( Number ) levelObject ).intValue();
+ }
+
+ String levelString = levelObject.toString();
+ try
+ {
+ return Integer.parseInt( levelString );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ // might be a descriptive name
+ }
+
+ if ( LOG_LEVEL_DEBUG.equalsIgnoreCase( levelString ) )
+ {
+ return LogService.LOG_DEBUG;
+ }
+ else if ( LOG_LEVEL_INFO.equalsIgnoreCase( levelString ) )
+ {
+ return LogService.LOG_INFO;
+ }
+ else if ( LOG_LEVEL_WARN.equalsIgnoreCase( levelString ) )
+ {
+ return LogService.LOG_WARNING;
+ }
+ else if ( LOG_LEVEL_ERROR.equalsIgnoreCase( levelString ) )
+ {
+ return LogService.LOG_ERROR;
+ }
+ }
+
+ // check ds.showtrace property
+ if ( VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty( PROP_SHOWTRACE ) ) )
+ {
+ return LogService.LOG_DEBUG;
+ }
+
+ // next check ds.showerrors property
+ if ( "false".equalsIgnoreCase( bundleContext.getProperty( PROP_SHOWERRORS ) ) )
+ {
+ return -1; // no logging at all !!
+ }
+
+ // default log level (errors only)
+ return LogService.LOG_ERROR;
+ }
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedService.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedService.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedService.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedService.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,57 @@
+/*
+ * 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.config;
+
+import java.util.Dictionary;
+
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * The <code>ScrManagedService</code> receives configuration for the Declarative
+ * Services Runtime itself.
+ * <p>
+ * This class is instantiated in a ServiceFactory manner by the
+ * {@link ScrManagedServiceServiceFactory} when the Configuration Admin service
+ * implementation and API is available.
+ * <p>
+ * Requires OSGi Configuration Admin Service API available
+ *
+ * @see ScrManagedServiceServiceFactory
+ */
+public class ScrManagedService implements ManagedService
+{
+
+ private final ScrConfiguration scrConfiguration;
+
+ protected final ScrConfiguration getScrConfiguration()
+ {
+ return scrConfiguration;
+ }
+
+ public ScrManagedService(final ScrConfiguration scrConfiguration)
+ {
+ this.scrConfiguration = scrConfiguration;
+ }
+
+ public void updated(Dictionary<String, ?> properties) throws ConfigurationException
+ {
+ this.scrConfiguration.configure(properties, true);
+ }
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,247 @@
+/*
+ * 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.config;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * The <code>ScrManagedServiceMetaTypeProvider</code> receives the Declarative
+ * Services Runtime configuration (by extending the {@link ScrManagedService}
+ * class but also provides a MetaType Service ObjectClassDefinition.
+ * <p>
+ * This class is instantiated in a ServiceFactory manner by the
+ * {@link ScrManagedServiceServiceFactory} when the Configuration Admin service
+ * implementation and API is available and if the Metatype Service API is also
+ * available.
+ * <p>
+ * Requires OSGi Metatype Service API available
+ *
+ * @see ScrManagedServiceServiceFactory
+ */
+class ScrManagedServiceMetaTypeProvider extends ScrManagedService
+ implements MetaTypeProvider
+{
+
+ static ScrManagedService create(final ScrConfiguration scrConfiguration)
+ {
+ return new ScrManagedServiceMetaTypeProvider(scrConfiguration);
+ }
+
+ private ScrManagedServiceMetaTypeProvider(final ScrConfiguration scrConfiguration)
+ {
+ super(scrConfiguration);
+ }
+
+ /**
+ * @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
+ */
+ public String[] getLocales()
+ {
+ return null;
+ }
+
+ /**
+ * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String, java.lang.String)
+ */
+ public ObjectClassDefinition getObjectClassDefinition( String id, String locale )
+ {
+ if ( !ScrConfiguration.PID.equals( id ) )
+ {
+ return null;
+ }
+
+ final ArrayList<AttributeDefinition> adList = new ArrayList<AttributeDefinition>();
+
+ adList.add(new AttributeDefinitionImpl(ScrConfiguration.PROP_LOGLEVEL, "SCR Log Level",
+ "Allows limiting the amount of logging information sent to the OSGi LogService."
+ + " Supported values are DEBUG, INFO, WARN, and ERROR. Default is ERROR.", AttributeDefinition.INTEGER,
+ new String[]
+ { String.valueOf(this.getScrConfiguration().getLogLevel()) }, 0, new String[]
+ { "Debug", "Information", "Warnings", "Error" }, new String[]
+ { "4", "3", "2", "1" }));
+
+ adList
+ .add(new AttributeDefinitionImpl(
+ ScrConfiguration.PROP_FACTORY_ENABLED,
+ "Extended Factory Components",
+ "Whether or not to enable the support for creating Factory Component instances based on factory configuration."
+ + " This is an Apache Felix SCR specific extension, explicitly not supported by the Declarative Services "
+ + "specification. Reliance on this feature prevent the component from being used with other Declarative "
+ + "Services implementations. The default value is false to disable this feature.", this
+ .getScrConfiguration().isFactoryEnabled()));
+
+ adList.add( new AttributeDefinitionImpl(
+ ScrConfiguration.PROP_DELAYED_KEEP_INSTANCES,
+ "Keep Component Instances",
+ "Whether or not to keep instances of delayed components once they are not referred to any more. The "
+ + "Declarative Services specifications suggests that instances of delayed components are disposed off "
+ + "if there is not used any longer. Setting this flag causes the components to not be disposed off "
+ + "and thus prevent them from being constantly recreated if often used. Examples of such components "
+ + "may be EventHandler services. The default is to dispose of unused components.", this
+ .getScrConfiguration().keepInstances() ) );
+
+ adList.add( new AttributeDefinitionImpl(
+ ScrConfiguration.PROP_LOCK_TIMEOUT,
+ "Lock timeout milliseconds",
+ "How long a lock is held before releasing due to suspected deadlock",
+ AttributeDefinition.LONG,
+ new String[] { String.valueOf(this.getScrConfiguration().lockTimeout())},
+ 0, null, null) );
+
+ adList.add( new AttributeDefinitionImpl(
+ ScrConfiguration.PROP_STOP_TIMEOUT,
+ "Stop timeout milliseconds",
+ "How long stopping a bundle is waited for before continuing due to suspected deadlock",
+ AttributeDefinition.LONG,
+ new String[] { String.valueOf(this.getScrConfiguration().stopTimeout())},
+ 0, null, null) );
+
+ adList.add( new AttributeDefinitionImpl(
+ ScrConfiguration.PROP_GLOBAL_EXTENDER,
+ "Global Extender",
+ "Whether to extend all bundles whether or not visible to this bundle.",
+ false ) );
+
+ return new ObjectClassDefinition()
+ {
+
+ private final AttributeDefinition[] attrs = adList
+ .toArray(new AttributeDefinition[adList.size()]);
+
+ public String getName()
+ {
+ return "Apache Felix Declarative Service Implementation";
+ }
+
+ public InputStream getIcon(int arg0)
+ {
+ return null;
+ }
+
+ public String getID()
+ {
+ return ScrConfiguration.PID;
+ }
+
+ public String getDescription()
+ {
+ return "Configuration for the Apache Felix Declarative Services Implementation."
+ + " This configuration overwrites configuration defined in framework properties of the same names.";
+ }
+
+ public AttributeDefinition[] getAttributeDefinitions(int filter)
+ {
+ return (filter == OPTIONAL) ? null : attrs;
+ }
+ };
+ }
+
+ private static class AttributeDefinitionImpl implements AttributeDefinition
+ {
+
+ private final String id;
+ private final String name;
+ private final String description;
+ private final int type;
+ private final String[] defaultValues;
+ private final int cardinality;
+ private final String[] optionLabels;
+ private final String[] optionValues;
+
+
+ AttributeDefinitionImpl( final String id, final String name, final String description, final boolean defaultValue )
+ {
+ this( id, name, description, BOOLEAN, new String[]
+ { String.valueOf(defaultValue) }, 0, null, null );
+ }
+
+ AttributeDefinitionImpl( final String id, final String name, final String description, final int type,
+ final String[] defaultValues, final int cardinality, final String[] optionLabels,
+ final String[] optionValues )
+ {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ this.type = type;
+ this.defaultValues = defaultValues;
+ this.cardinality = cardinality;
+ this.optionLabels = optionLabels;
+ this.optionValues = optionValues;
+ }
+
+
+ public int getCardinality()
+ {
+ return cardinality;
+ }
+
+
+ public String[] getDefaultValue()
+ {
+ return defaultValues;
+ }
+
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+
+ public String getID()
+ {
+ return id;
+ }
+
+
+ public String getName()
+ {
+ return name;
+ }
+
+
+ public String[] getOptionLabels()
+ {
+ return optionLabels;
+ }
+
+
+ public String[] getOptionValues()
+ {
+ return optionValues;
+ }
+
+
+ public int getType()
+ {
+ return type;
+ }
+
+
+ public String validate( String arg0 )
+ {
+ return null;
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,72 @@
+/*
+ * 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.config;
+
+import org.apache.felix.scr.impl.Activator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+
+/**
+ * The <code>ScrManagedServiceServiceFactory</code> is the ServiceFactory
+ * registered on behalf of the {@link ScrManagedService} (or
+ * {@link ScrManagedServiceMetaTypeProvider}, resp.) to create the instance on
+ * demand once it is used by the Configuration Admin Service or the MetaType
+ * Service.
+ * <p>
+ * In contrast to the {@link ScrManagedService} and
+ * {@link ScrManagedServiceMetaTypeProvider} classes, this class only requires
+ * core OSGi API and thus may be instantiated without the Configuration Admin
+ * and/or MetaType Service API actually available at the time of instantiation.
+ */
+public class ScrManagedServiceServiceFactory implements ServiceFactory<ScrManagedService>
+{
+ private final ScrConfiguration scrConfiguration;
+
+ public ScrManagedServiceServiceFactory(final ScrConfiguration scrConfiguration)
+ {
+ this.scrConfiguration = scrConfiguration;
+ }
+
+ public ScrManagedService getService(Bundle bundle, ServiceRegistration<ScrManagedService> registration)
+ {
+ try
+ {
+ return ScrManagedServiceMetaTypeProvider.create( this.scrConfiguration );
+ }
+ catch ( Throwable t )
+ {
+ // assume MetaType Service API not available
+ Activator
+ .log(
+ LogService.LOG_ERROR,
+ null,
+ "Cannot create MetaType providing ManagedService; not providing Metatype information but just accepting configuration",
+ t );
+ }
+ return new ScrManagedService( this.scrConfiguration );
+ }
+
+ public void ungetService(Bundle bundle, ServiceRegistration<ScrManagedService> registration, ScrManagedService service)
+ {
+ // nothing really todo; GC will do the rest
+ }
+
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivateMethod.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivateMethod.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivateMethod.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivateMethod.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,300 @@
+/*
+ * 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.helper;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.impl.metadata.DSVersion;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.log.LogService;
+
+
+public class ActivateMethod extends BaseMethod<ActivatorParameter>
+{
+
+ protected static final Class<?> COMPONENT_CONTEXT_CLASS = ComponentContext.class;
+ protected static final Class<?> BUNDLE_CONTEXT_CLASS = BundleContext.class;
+ protected static final Class<?> INTEGER_CLASS = Integer.class;
+
+ protected final boolean m_supportsInterfaces;
+
+
+ public ActivateMethod( final String methodName,
+ final boolean methodRequired,
+ final Class<?> componentClass,
+ final DSVersion dsVersion,
+ final boolean configurableServiceProperties,
+ boolean supportsInterfaces )
+ {
+ super( methodName, methodRequired, componentClass, dsVersion, configurableServiceProperties );
+ m_supportsInterfaces = supportsInterfaces;
+ }
+
+
+ @Override
+ protected Method doFindMethod( Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
+ throws SuitableMethodNotAccessibleException, InvocationTargetException
+ {
+
+ boolean suitableMethodNotAccessible = false;
+
+ try
+ {
+ // find the declared method in this class
+ final Method method = getMethod( targetClass, getMethodName(), new Class[]
+ { COMPONENT_CONTEXT_CLASS }, acceptPrivate, acceptPackage, logger );
+ if ( method != null )
+ {
+ return method;
+ }
+ }
+ catch ( SuitableMethodNotAccessibleException thrown )
+ {
+ logger.log( LogService.LOG_DEBUG, "SuitableMethodNotAccessible", thrown );
+ suitableMethodNotAccessible = true;
+ }
+ if (getDSVersion().isDS11())
+ {
+ List<Method> methods = getSortedMethods( targetClass);
+ for (Method m: methods)
+ {
+ final Class<?>[] parameterTypes = m.getParameterTypes();
+ if (parameterTypes.length == 1)
+ {
+ Class<?> type = parameterTypes[0];
+ //single parameter method with parameter ComponentContext will already have been found.
+ if (type == BUNDLE_CONTEXT_CLASS)
+ {
+ if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+ {
+ return m;
+ }
+ suitableMethodNotAccessible = true;
+ }
+ if (getDSVersion().isDS13() && isAnnotation(type))
+ {
+ if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+ {
+ return m;
+ }
+ suitableMethodNotAccessible = true;
+ }
+ if (type == ClassUtils.MAP_CLASS)
+ {
+ if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+ {
+ return m;
+ }
+ suitableMethodNotAccessible = true;
+ }
+ if (type == int.class)
+ {
+ if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+ {
+ return m;
+ }
+ suitableMethodNotAccessible = true;
+ }
+ if (type == Integer.class)
+ {
+ if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+ {
+ return m;
+ }
+ suitableMethodNotAccessible = true;
+ }
+
+ }
+ else if (parameterTypes.length > 1)
+ {
+ boolean accept = true;
+ for (Class<?> type: parameterTypes)
+ {
+ accept = type == COMPONENT_CONTEXT_CLASS
+ || type == BUNDLE_CONTEXT_CLASS
+ || type == ClassUtils.MAP_CLASS
+ || ( isDeactivate() && ( type == int.class || type == Integer.class))
+ || ( getDSVersion().isDS13() && isAnnotation(type));
+ if ( !accept )
+ {
+ break;
+ }
+
+ }
+ if (accept)
+ {
+ if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+ {
+ return m;
+ }
+ suitableMethodNotAccessible = true;
+ }
+
+ }
+ else //no parameters
+ {
+ if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+ {
+ return m;
+ }
+ suitableMethodNotAccessible = true;
+ }
+
+ }
+ }
+
+ if ( suitableMethodNotAccessible )
+ {
+ throw new SuitableMethodNotAccessibleException();
+ }
+
+ return null;
+ }
+
+
+ boolean isDeactivate()
+ {
+ return false;
+ }
+
+
+ /**
+ * returns the declared methods of the target class, with the correct name, sorted by number of parameters ( no parameters last)
+ * @param targetClass class to examine methods of
+ * @return sorted methods of correct name;
+ */
+ List<Method> getSortedMethods(Class<?> targetClass)
+ {
+ List<Method> result = new ArrayList<Method>();
+ Method[] methods = targetClass.getDeclaredMethods();
+ for (Method m: methods)
+ {
+ if (m.getName().equals(getMethodName()))
+ {
+ result.add(m);
+ }
+ }
+ Collections.sort(result, new Comparator<Method>(){
+
+ public int compare(Method m1, Method m2)
+ {
+ final int l1 = m1.getParameterTypes().length;
+ final int l2 = m2.getParameterTypes().length;
+ if ( l1 == 0)
+ {
+ return l2;
+ }
+ if ( l2 == 0)
+ {
+ return -l1;
+ }
+ if (l1 == 1 && l2 == 1)
+ {
+ final Class<?> t1 = m1.getParameterTypes()[0];
+ final Class<?> t2 = m2.getParameterTypes()[0];
+ //t1, t2 can't be equal
+ if (t1 == COMPONENT_CONTEXT_CLASS) return -1;
+ if (t2 == COMPONENT_CONTEXT_CLASS) return 1;
+ if (t1 == BUNDLE_CONTEXT_CLASS) return -1;
+ if (t2 == BUNDLE_CONTEXT_CLASS) return 1;
+ if (isAnnotation(t1)) return isAnnotation(t2)? 0: -1;
+ if (isAnnotation(t2)) return 1;
+ if (t1 == ClassUtils.MAP_CLASS) return -1;
+ if (t2 == ClassUtils.MAP_CLASS) return 1;
+ if (t1 == int.class) return -1;
+ if (t2 == int.class) return 1;
+ if (t1 == Integer.class) return -1;
+ if (t2 == Integer.class) return 1;
+ return 0;
+ }
+ return l1 - l2;
+ }
+
+ });
+ return result;
+ }
+
+ private boolean isAnnotation(final Class<?> t1)
+ {
+ return t1.isAnnotation() || (m_supportsInterfaces && t1.isInterface() && !(t1 == ClassUtils.MAP_CLASS));
+ }
+
+
+ @Override
+ protected Object[] getParameters( Method method, ActivatorParameter rawParameter )
+ {
+ final Class<?>[] parameterTypes = method.getParameterTypes();
+ final ActivatorParameter ap = rawParameter;
+ final Object[] param = new Object[parameterTypes.length];
+ for ( int i = 0; i < param.length; i++ )
+ {
+ if ( parameterTypes[i] == COMPONENT_CONTEXT_CLASS )
+ {
+ param[i] = ap.getComponentContext();
+ }
+ else if ( parameterTypes[i] == BUNDLE_CONTEXT_CLASS )
+ {
+ param[i] = ap.getComponentContext().getBundleContext();
+ }
+ else if ( parameterTypes[i] == ClassUtils.MAP_CLASS )
+ {
+ // note: getProperties() returns a ReadOnlyDictionary which is a Map
+ param[i] = ap.getComponentContext().getProperties();
+ }
+ else if ( parameterTypes[i] == INTEGER_CLASS || parameterTypes[i] == Integer.TYPE )
+ {
+ param[i] = ap.getReason();
+ }
+ else
+ {
+ param[i] = Annotations.toObject(parameterTypes[i],
+ (Map<String, Object>) ap.getComponentContext().getProperties(),
+ ap.getComponentContext().getBundleContext().getBundle(), m_supportsInterfaces);
+ }
+ }
+
+ return param;
+ }
+
+
+ @Override
+ protected String getMethodNamePrefix()
+ {
+ return "activate";
+ }
+
+ @Override
+ public MethodResult invoke( Object componentInstance, ActivatorParameter rawParameter, final MethodResult methodCallFailureResult, SimpleLogger logger )
+ {
+ if (methodExists( logger ))
+ {
+ return super.invoke(componentInstance, rawParameter, methodCallFailureResult, logger );
+ }
+ return null;
+ }
+
+}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivatorParameter.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivatorParameter.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivatorParameter.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/ActivatorParameter.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,45 @@
+/*
+ * 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.helper;
+
+import org.osgi.service.component.ComponentContext;
+
+public final class ActivatorParameter
+{
+ private final ComponentContext m_componentContext;
+ private final int m_reason;
+
+ public ActivatorParameter( ComponentContext componentContext, int reason )
+ {
+ this.m_componentContext = componentContext;
+ this.m_reason = reason;
+ }
+
+
+ public ComponentContext getComponentContext()
+ {
+ return m_componentContext;
+ }
+
+
+ public int getReason()
+ {
+ return m_reason;
+ }
+}
\ No newline at end of file
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/Annotations.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/Annotations.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/Annotations.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/helper/Annotations.java Wed Jul 8 22:10:14 2015
@@ -0,0 +1,227 @@
+/*
+ * 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.helper;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.Bundle;
+
+public class Annotations
+{
+
+ static public <T> T toObject(Class<T> clazz, Map<String, Object> props, Bundle b, boolean supportsInterfaces )
+ {
+ Map<String, Object> m = new HashMap<String, Object>();
+
+ Method[] methods = clazz.getMethods();
+ Map<String, Method> complexFields = new HashMap<String, Method>();
+ for ( Method method: methods )
+ {
+ String name = method.getName();
+ String key = fixup(name);
+ Object raw = props.get(key);
+ Class<?> returnType = method.getReturnType();
+ Object cooked;
+ if ( returnType.isInterface() || returnType.isAnnotation())
+ {
+ complexFields.put(key, method);
+ continue;
+ }
+ if (returnType.isArray())
+ {
+ Class<?> componentType = returnType.getComponentType();
+ if ( componentType.isInterface() || componentType.isAnnotation())
+ {
+ complexFields.put(key, method);
+ continue;
+ }
+ cooked = coerceToArray(componentType, raw, b);
+ }
+ else
+ {
+ cooked = Coercions.coerce( returnType, raw, b );
+ }
+ m.put( name, cooked );
+ }
+ if (!complexFields.isEmpty())
+ {
+ if (!supportsInterfaces )
+ {
+ //error
+ return null;//??
+ }
+ Map<String, List<Map<String, Object>>> nested = extractSubMaps(complexFields.keySet(), props);
+ for (Map.Entry<String, Method> entry: complexFields.entrySet())
+ {
+ List<Map<String, Object>> proplist = nested.get(entry.getKey());
+ Method method = entry.getValue();
+ Class<?> returnType = method.getReturnType();
+ if (returnType.isArray())
+ {
+ Class<?> componentType = returnType.getComponentType();
+ Object result = Array.newInstance(componentType, proplist.size());
+ for (int i = 0; i < proplist.size(); i++)
+ {
+ Map<String, Object> rawElement = proplist.get(i);
+ Object cooked = toObject(componentType, rawElement, b, supportsInterfaces);
+ Array.set(result, i, cooked);
+ }
+ m.put(method.getName(), result);
+ }
+ else
+ {
+ if (!proplist.isEmpty())
+ {
+ Object cooked = toObject(returnType, proplist.get(0), b, supportsInterfaces);
+ m.put(method.getName(), cooked);
+ }
+ }
+ }
+ }
+
+ InvocationHandler h = new Handler(m);
+ return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, h);
+ }
+
+ private static Map<String, List<Map<String, Object>>> extractSubMaps(Collection<String> keys, Map<String, Object> map)
+ {
+ Map<String, List<Map<String, Object>>> result = new HashMap<String, List<Map<String, Object>>>();
+ //Form a regexp to recognize all the keys as prefixes in the map keys.
+ StringBuilder b = new StringBuilder("(");
+ for (String key: keys)
+ {
+ b.append(key).append("|");
+ }
+ b.deleteCharAt(b.length() -1);
+ b.append(")\\.([0-9]*)\\.(.*)");
+ Pattern p = Pattern.compile(b.toString());
+ for (Map.Entry<String, Object> entry: map.entrySet())
+ {
+ String longKey = entry.getKey();
+ Matcher m = p.matcher(longKey);
+ if (m.matches())
+ {
+ String key = m.group(1);
+ int index = Integer.parseInt(m.group(2));
+ String subkey = m.group(3);
+ List<Map<String, Object>> subMapsForKey = result.get(key);
+ if (subMapsForKey == null)
+ {
+ subMapsForKey = new ArrayList<Map<String, Object>>();
+ result.put(key, subMapsForKey);
+ }
+ //make sure there is room for the possible new submap
+ for (int i = subMapsForKey.size(); i <= index; i++)
+ {
+ subMapsForKey.add(new HashMap<String, Object>());
+ }
+ Map<String, Object> subMap = subMapsForKey.get(index);
+ subMap.put(subkey, entry.getValue());
+ }
+ }
+ return result;
+ }
+
+ private static Object coerceToArray(Class<?> componentType, Object raw, Bundle bundle)
+ {
+ if (raw == null)
+ {
+ return null;
+ }
+ if (raw.getClass().isArray())
+ {
+ int size = Array.getLength(raw);
+ Object result = Array.newInstance(componentType, size);
+ for (int i = 0; i < size; i++)
+ {
+ Object rawElement = Array.get(raw, i);
+ Object cooked = Coercions.coerce(componentType, rawElement, bundle);
+ Array.set(result, i, cooked);
+ }
+ return result;
+ }
+ if (raw instanceof Collection)
+ {
+ Collection raws = (Collection) raw;
+ int size = raws.size();
+ Object result = Array.newInstance(componentType, size);
+ int i = 0;
+ for (Object rawElement: raws)
+ {
+ Object cooked = Coercions.coerce(componentType, rawElement, bundle);
+ Array.set(result, i++, cooked);
+ }
+ return result;
+
+ }
+ Object cooked = Coercions.coerce(componentType, raw, bundle);
+ Object result = Array.newInstance(componentType, 1);
+ Array.set(result, 0, cooked);
+ return result;
+
+ }
+
+ private static final Pattern p = Pattern.compile("(\\$\\$)|(\\$)|(__)|(_)");
+
+ static String fixup(String name)
+ {
+ Matcher m = p.matcher(name);
+ StringBuffer b = new StringBuffer();
+ while (m.find())
+ {
+ String replacement = "";//null;
+ if (m.group(1) != null) replacement = "\\$";
+ if (m.group(2) != null) replacement = "";
+ if (m.group(3) != null) replacement = "_";
+ if (m.group(4) != null) replacement = ".";
+
+ m.appendReplacement(b, replacement);
+ }
+ m.appendTail(b);
+ return b.toString();
+ }
+
+ private static class Handler implements InvocationHandler
+ {
+
+ private final Map<String, Object> values;
+
+ public Handler(Map<String, Object> values)
+ {
+ this.values = values;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+ {
+ return values.get(method.getName());
+ }
+
+ }
+
+}