blob: 0d8d5b5c647cbe267e634f2118967963a3efe05b [file] [log] [blame]
/*
* 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.karaf.scr.management.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
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.dto.ServiceReferenceDTO;
import org.osgi.service.component.ComponentInstance;
import org.osgi.service.component.runtime.ServiceComponentRuntime;
import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
import org.osgi.service.component.runtime.dto.ReferenceDTO;
import org.osgi.service.component.runtime.dto.SatisfiedReferenceDTO;
public class ScrService
{
private final BundleContext context;
private final ServiceComponentRuntime runtime;
public ScrService(BundleContext context, final ServiceComponentRuntime runtime)
{
// we always use the system bundle to avoid problems if subsystems etc.
// are used and the SCR implemented extends those "invisible" bundles
this.context = context.getBundle(0).getBundleContext();
this.runtime = runtime;
}
// ScrService
public Component[] getComponents()
{
List<Component> result = new ArrayList<>();
final Collection<ComponentDescriptionDTO> descriptions = this.runtime.getComponentDescriptionDTOs();
for(final ComponentDescriptionDTO descDTO : descriptions )
{
final Collection<ComponentConfigurationDTO> configs = this.runtime.getComponentConfigurationDTOs(descDTO);
ComponentConfigurationDTO configDTO = null;
if ( !configs.isEmpty() )
{
configDTO = configs.iterator().next();
}
result.add(new Component(this.context, this.runtime, descDTO, configDTO));
}
return result.toArray( new Component[result.size()] );
}
public Component[] getComponents(final String componentName )
{
List<Component> result = new ArrayList<Component>();
final Collection<ComponentDescriptionDTO> descriptions = this.runtime.getComponentDescriptionDTOs();
for(final ComponentDescriptionDTO descDTO : descriptions )
{
if ( descDTO.name.equals(componentName) ) {
final Collection<ComponentConfigurationDTO> configs = this.runtime.getComponentConfigurationDTOs(descDTO);
ComponentConfigurationDTO configDTO = null;
if ( !configs.isEmpty() )
{
configDTO = configs.iterator().next();
}
result.add(new Component(this.context, this.runtime, descDTO, configDTO));
}
}
return result.isEmpty() ? null : result.toArray( new Component[result.size()] );
}
public static final class Component
{
/**
* The Component has just been created and is still disabled or it has
* been disabled by calling the {@link #disable()} method (value is 1).
*/
public static final int STATE_DISABLED = 1;
/**
* The Component is being enabled (value is 512). After the component has
* been enabled it enters the {@link #STATE_UNSATISFIED} state.
* @since 1.2
* @deprecated since 1.8.0
*/
@Deprecated
public static final int STATE_ENABLING = 512;
/**
* The Component has been enabled and is now going to be activated (value
* is 2).
* @deprecated as of version 1.2 the enabled state is collapsed into the
* {@link #STATE_UNSATISFIED} state. This status code is never returned
* from the {@link #getState()} method.
*/
@Deprecated
public static final int STATE_ENABLED = 2;
/**
* The Component activation failed because any dependency is not satisfied
* (value is 4).
*/
public static final int STATE_UNSATISFIED = 4;
/**
* The Component is currently being activated either because it has been
* enabled or because any dependency which was previously unsatisfied has
* become satisfied (value is 8).
* @deprecated since 1.8.0 transient states are no longer used
*/
@Deprecated
public static final int STATE_ACTIVATING = 8;
/**
* The Component has successfully been activated and is fully functional
* (value is 16). This is the state of immediate components after
* successful activation. Delayed and Service Factory Components enter
* this state when the service instance has actually been instantiated because
* the service has been acquired.
*/
public static final int STATE_ACTIVE = 16;
/**
* The Component has successfully been activated but is a Delayed or Service
* Factory Component pending instantiation on first use (value is 32).
*/
public static final int STATE_REGISTERED = 32;
/**
* The Component is a Component Factory ready to create Component instances
* with the <code>ComponentFactory.newInstance(Dictionary)</code> method
* or (if enabled with the <code>ds.factory.enabled</code> configuration) to
* manage Component instances from configuration data received from the
* Configuration Admin Service (value is 64).
*/
public static final int STATE_FACTORY = 64;
/**
* The Component is being deactivated either because it is being disabled
* or because a dependency is not satisfied any more (value is 128). After
* deactivation the Component enters the {@link #STATE_UNSATISFIED} state.
* @deprecated since 1.8.0 transient states are no longer used
*/
@Deprecated
public static final int STATE_DEACTIVATING = 128;
/**
* The Component is being disabled (value is 1024). After the component has
* been disabled it enters the {@link #STATE_DISABLED} state.
* @since 1.2
* @deprecated since 1.8.0 transient states are no longer used
*/
@Deprecated
public static final int STATE_DISABLING = 1024;
/**
* The Component is being disposed off (value is 2048). After the component
* has been disposed off it enters the {@link #STATE_DESTROYED} state.
* @since 1.2
* @deprecated since 1.8.0 transient states are no longer used
*/
@Deprecated
public static final int STATE_DISPOSING = 2048;
/**
* The Component has been destroyed and cannot be used any more (value is
* 256). This state is only used when the bundle declaring the component
* is being stopped and all components have to be removed.
* @deprecated as of version 1.2 this constant has been renamed to
* {@link #STATE_DISPOSED}.
*/
@Deprecated
public static final int STATE_DESTROYED = 256;
/**
* The Component has been disposed off and cannot be used any more (value is
* 256). This state is used when the bundle declaring the component
* is being stopped and all components have to be removed. This status is
* also the final status of a component after the
* <code>ComponentInstance.dispose()</code> method has been called.
* @since 1.2
*/
public static final int STATE_DISPOSED = 256;
private final ComponentDescriptionDTO description;
private final ComponentConfigurationDTO configuration;
private final BundleContext bundleContext;
private final ServiceComponentRuntime runtime;
public Component(final BundleContext bundleContext,
final ServiceComponentRuntime runtime,
final ComponentDescriptionDTO description,
final ComponentConfigurationDTO configuration)
{
this.bundleContext = bundleContext;
this.description = description;
this.configuration = configuration;
this.runtime = runtime;
}
public long getId()
{
return configuration != null ? configuration.id : -1;
}
public String getName()
{
return description.name;
}
public int getState()
{
if ( configuration == null )
{
return STATE_UNSATISFIED; // TODO Check!
}
final int s = configuration.state;
switch ( s )
{
case ComponentConfigurationDTO.ACTIVE : return STATE_ACTIVE;
case ComponentConfigurationDTO.SATISFIED : return STATE_ENABLED;
case ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION : return STATE_UNSATISFIED;
case ComponentConfigurationDTO.UNSATISFIED_REFERENCE : return STATE_UNSATISFIED;
default: // satisfied
return STATE_ENABLED;
}
}
public Bundle getBundle()
{
return this.bundleContext.getBundle(this.description.bundle.id);
}
public String getFactory()
{
return this.description.factory;
}
public boolean isServiceFactory()
{
return !"singleton".equals(this.description.scope);
}
public String getClassName()
{
return this.description.implementationClass;
}
public boolean isDefaultEnabled()
{
return this.description.defaultEnabled;
}
public boolean isImmediate()
{
return this.description.immediate;
}
public String[] getServices()
{
return this.description.serviceInterfaces.length == 0 ? null : this.description.serviceInterfaces;
}
public Dictionary getProperties()
{
return new Hashtable<>(this.description.properties);
}
public Reference[] getReferences()
{
if ( this.configuration == null )
{
return null;
}
final List<Reference> result = new ArrayList<Reference>();
for(final ReferenceDTO dto : this.description.references)
{
SatisfiedReferenceDTO sRef = null;
for(final SatisfiedReferenceDTO r : this.configuration.satisfiedReferences)
{
if ( r.name.equals(dto.name) )
{
sRef = r;
break;
}
}
result.add(new Reference(this.bundleContext, dto, sRef));
}
if ( result.isEmpty() )
{
return null;
}
return result.toArray(new Reference[result.size()]);
}
public ComponentInstance getComponentInstance()
{
// returning null as we should have never returned this in the first place
return null;
}
public String getActivate()
{
return this.description.activate;
}
public boolean isActivateDeclared()
{
return this.description.activate != null;
}
public String getDeactivate()
{
return this.description.deactivate;
}
public boolean isDeactivateDeclared()
{
return this.description.deactivate != null;
}
public String getModified()
{
return this.description.modified;
}
public String getConfigurationPolicy()
{
return this.description.configurationPolicy;
}
public String getConfigurationPid()
{
final String[] pids = this.description.configurationPid;
return pids[0];
}
public boolean isConfigurationPidDeclared()
{
return true;
}
public void enable()
{
// noop as the old model was broken
}
public void disable()
{
// noop as the old model was broken
}
}
public static final class Reference
{
// constant for option single reference - 0..1
private static final String CARDINALITY_0_1 = "0..1";
// constant for option multiple reference - 0..n
private static final String CARDINALITY_0_N = "0..n";
// constant for required multiple reference - 1..n
private static final String CARDINALITY_1_N = "1..n";
// constant for static policy
private static final String POLICY_STATIC = "static";
// constant for reluctant policy option
private static final String POLICY_OPTION_RELUCTANT = "reluctant";
private final ReferenceDTO dto;
private final SatisfiedReferenceDTO satisfiedDTO;
private final BundleContext bundleContext;
public Reference(
final BundleContext bundleContext,
final ReferenceDTO dto,
final SatisfiedReferenceDTO satisfied)
{
this.bundleContext = bundleContext;
this.dto = dto;
this.satisfiedDTO = satisfied;
}
public String getName()
{
return dto.name;
}
public String getServiceName()
{
return dto.interfaceName;
}
public ServiceReference[] getServiceReferences()
{
if ( this.satisfiedDTO == null )
{
return null;
}
final List<ServiceReference<?>> refs = new ArrayList<ServiceReference<?>>();
for(ServiceReferenceDTO dto : this.satisfiedDTO.boundServices)
{
try
{
final ServiceReference<?>[] serviceRefs = this.bundleContext.getServiceReferences((String)null,
"(" + Constants.SERVICE_ID + "=" + String.valueOf(dto.id) + ")");
if ( serviceRefs != null && serviceRefs.length > 0 )
{
refs.add(serviceRefs[0]);
}
}
catch ( final InvalidSyntaxException ise)
{
// ignore
}
}
return refs.toArray(new ServiceReference<?>[refs.size()]);
}
public ServiceReference<?>[] getBoundServiceReferences()
{
return this.getServiceReferences();
}
public boolean isSatisfied()
{
return this.satisfiedDTO != null;
}
public boolean isOptional()
{
return CARDINALITY_0_1.equals(dto.cardinality) || CARDINALITY_0_N.equals(dto.cardinality);
}
public boolean isMultiple()
{
return CARDINALITY_1_N.equals(dto.cardinality) || CARDINALITY_0_N.equals(dto.cardinality);
}
public boolean isStatic()
{
return POLICY_STATIC.equals(dto.policy);
}
public boolean isReluctant()
{
return POLICY_OPTION_RELUCTANT.equals(dto.policyOption);
}
public String getTarget()
{
return this.dto.target;
}
public String getBindMethodName()
{
return this.dto.bind;
}
public String getUnbindMethodName()
{
return this.dto.unbind;
}
public String getUpdatedMethodName()
{
return this.dto.unbind;
}
}
}