felix-scr-2.1.20/0000755000175000017500000000000013675426212012532 5ustar sudipsudipfelix-scr-2.1.20/bnd.bnd0000644000175000017500000000372013675426212013764 0ustar sudipsudipBundle-Category: osgi Bundle-DocURL: http://felix.apache.org/site/apache-felix-service-component-runtime.html Bundle-Activator: org.apache.felix.scr.impl.Activator Provide-Capability: osgi.extender;\ osgi.extender="osgi.component";\ uses:="org.osgi.service.component";\ version:Version="1.4",\ osgi.service;\ objectClass:List="org.osgi.service.component.runtime.ServiceComponentRuntime";\ uses:="org.osgi.service.component.runtime" Require-Capability: osgi.ee;\ filter:="(|(&(osgi.ee=JavaSE)(version=1.7))(&(osgi.ee=JavaSE/compact1)(version=1.8)))" Export-Package: org.apache.felix.scr.component;version=1.1.0;provide:=true, \ org.apache.felix.scr.info;version=1.0.0;provide:=true, \ org.osgi.service.component;version=1.4;provide:=true, \ org.osgi.service.component.runtime;version=1.4;provide:=true, \ org.osgi.service.component.runtime.dto;version=1.4;provide:=true Private-Package: org.apache.felix.scr.impl.* # Configuration Admin is optional and dynamic, but allow eager wiring by importing it # LogService is optional but if present the R4.0 version 1.3 is sufficient. # Metatype import is optional and dynamic, but allow eager wiring by importing it # PackageAdmin is used to find reference types if the component's bundle does not import it. # R4.0 version 1.2 is sufficient. # optional import for Gogo annotations Import-Package: \ org.osgi.service.cm;version="[1.6,2)";resolution:=optional, \ org.osgi.service.log;version="[1.3,2)";resolution:=optional, \ org.osgi.service.metatype;version="[1.2,2)";resolution:=optional, \ org.osgi.service.packageadmin;version="[1.2,2)";resolution:=optional,\ org.apache.felix.service.command;resolution:=optional, \ * DynamicImport-Package: \ org.osgi.service.cm;version="[1.6,2)", \ org.osgi.service.log;version="[1.3,2)", \ org.osgi.service.metatype;version="[1.1,2)" felix-scr-2.1.20/obr.xml0000644000175000017500000000322413675426212014037 0ustar sudipsudip Import Service org.osgi.service.log.LogService

felix-scr-2.1.20/pom.xml0000644000175000017500000003355613675426212014063 0ustar sudipsudip org.apache.felix felix-parent 6 4.0.0 bundle Apache Felix Declarative Services Implementation of the Declarative Services specification 1.4 org.apache.felix.scr 2.1.20 scm:git:https://github.com/apache/felix-dev.git scm:git:https://github.com/apache/felix-dev.git https://gitbox.apache.org/repos/asf?p=felix-dev.git org.apache.felix.scr-2.1.20 ${basedir}/target ${bundle.build.name}/${project.build.finalName}.jar 1.9.0 org.osgi osgi.core 6.0.0 provided org.osgi osgi.annotation 6.0.1 provided org.osgi org.osgi.service.component 1.4.0 provided org.osgi org.osgi.service.cm 1.6.0 provided org.osgi org.osgi.service.log 1.3.0 provided org.osgi org.osgi.service.metatype 1.3.0 provided org.osgi org.osgi.namespace.extender 1.0.1 provided org.osgi org.osgi.util.promise 1.0.0 provided org.osgi org.osgi.util.function 1.0.0 provided org.apache.felix org.apache.felix.gogo.runtime 1.0.0 provided junit junit 4.12 test org.mockito mockito-core 2.28.2 test org.ops4j.pax.exam pax-exam-container-forked 3.2.0 test org.ops4j.pax.exam pax-exam-junit4 3.2.0 test org.ops4j.pax.exam pax-exam-link-mvn 3.2.0 test org.ops4j.pax.url pax-url-aether 2.6.2 test org.ops4j.pax.url pax-url-wrap 2.6.2 test org.ops4j.pax.logging pax-logging-api 1.6.3 test org.ops4j.pax.logging pax-logging-service 1.6.3 test ch.qos.logback logback-core 1.2.0 test ch.qos.logback logback-classic 1.2.0 test org.apache.geronimo.specs geronimo-atinject_1.0_spec 1.0 test org.apache.servicemix.bundles org.apache.servicemix.bundles.junit 4.9_2 test org.ops4j.base ops4j-base-lang 1.2.3 provided org.ops4j.base ops4j-base-net 1.2.3 provided org.ops4j.pax.tinybundles tinybundles 1.0.0 test org.codehaus.mojo animal-sniffer-annotations 1.9 compile org.ow2.asm asm-debug-all 5.0.4 test ${bundle.build.name} org.apache.felix maven-bundle-plugin 3.2.0 true <_include>-bnd.bnd maven-surefire-plugin **/integration/** **/components/** **/instances/** **/instances2/** maven-failsafe-plugin 2.12 integration-test verify ${bundle.file.name} ${felix.ca.version} **/components/** **/integration/** org.apache.maven.plugins maven-release-plugin 2.5.2 org.apache.maven.plugins maven-javadoc-plugin ${project.build.sourceEncoding} *.impl org.codehaus.mojo findbugs-maven-plugin 2.5.2 Max Low ide maven-antrun-plugin scr-file-create package run felix true org.apache.felix org.apache.felix.framework 4.6.0 test equinox org.eclipse org.eclipse.osgi 3.8.0.v20120529-1548 test felix-scr-2.1.20/README.md0000644000175000017500000002446613675426212014025 0ustar sudipsudip# Apache Felix Service Component Runtime (SCR) The Apache Felix Service Component Runtime described by the [OSGi Declarative Services Specification](https://osgi.org/specification/osgi.cmpn/7.0.0/service.component.html) is implemented by this bundle. The service component model described by `Declarative Services` uses a declarative way for publishing, finding and binding to OSGi services The Java annotations defined by the specification make implementing components easy and reduce the amount of code that needs be written. These annotations are processed at build time and translated into XML descriptor files which in turn are listed in the `Service-Component` header of the declaring bundle. But the good news is, you usually don't have to worry about this XML, however in case things don't work as expected , it's good to know how these things work. The Apache Felix Declarative Services implementation is the reference implementation for the OSGi Declarative Services Specification Version 1.4 (R7) and therefore passes the OSGi CT. ## Example Usage To help you get a head start, here is an example of using Declarative Services. As mentioned the used annotations are processed at build time, creating XML descriptor files. These component declarations are read when the declaring bundle is started and the respective components are verified and activated depending on their declaration. ### Component First of all the component must be implemented in a simple Java class. The Declarative Services Specification basically places no restrictions on the contents of this class. Lets define a very simple class, which implements a `java.util.Comparator` service: ```java package sample; import java.util.Comparator; import org.osgi.service.component.annotations.Component; @Component(service = Comparator.class) public class SampleComparator implements Comparator { public int compare( Object o1, Object o2 ) { // TODO: calculate the result return o1.equals( o2 ) ? 0 : -1; } } ``` This is of course a very simple and not very intelligently implemented comparator... ### Activation It may well be that the component needs to be notified, when it is activated and deactivated. For this, the component may implement an `activate` method/constructor and a `deactivate` method. Both methods must be `public` or `protected` and can take a variety of parameters. Here is the initial class extended with activation and deactivation methods: ```java package sample; import java.util.Comparator; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Deactivate; @Component(service = Comparator.class) public class SampleComparator implements Comparator { public SampleComparator() { // TODO: Do something on activation } public int compare( Object o1, Object o2 ) { // TODO: calculate the result return o1.equals( o2 ) ? 0 : -1; } @Deactivate protected void deactivate() { // TODO: Do something on deactivation } } ``` ### Service Binding The next step would probably be to do some service binding. This is somewhat more overhead, as the referenced services must be declared. On the other hand, you do not have to care to listen for these services. As examples of these strategies we will use the event strategy to access an OSGi `LogService`. ### Looking up the Service To use the service, the reference must be declared by using the @Reference annotation. Here is the respective declaration for a log service to lookup: ```java private LogService log; @Reference protected void bindLog(LogService log) { this.log = log; } protected void unbindLog(LogService log) { this.log = null; } ``` Or if you want to use field injection, it is just: ```java @Reference private LogService log; ``` You can also use contructor injection: ```java private final LogService log; @Activate public Comparator(@Reference LogService logService) { this.log = logService; } ``` ## Apache Maven Support Both, the [maven-bundle-plugin](http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html) as well as the [bnd-maven-plugin](https://github.com/bndtools/bnd/tree/master/maven) supports processing the annotations and creating the XML component descriptors. ## Configuration The Apache Felix Declarative Services implementation can be configured with Framework properties which are read on startup of the implementation bundle and Configuration Admin Service configuration which is provided by the Configuration Admin Service to the service PID `org.apache.felix.scr.ScrService`. The following properties are supported: | Property | Default Value | Description | |--|--|--| | `ds.loglevel` | 1 | Defines a logging level at which messages are logged. This configuration property is converted to an `int` number used as the OSGi Log Service logging level. | | `ds.showtrace` | `false` | sets the log level to `debug` if set to `true` and the `ds.loglevel` cannot be converted to a value log level | | `ds.showerrors` | `true` | Disables logging completely if set to `false` and the `ds.loglevel` cannot be converted to a value log level and the `ds.showtrace` is not set to `true` | | `ds.factory.enabled` | `false` | Enables Component Factory functionality not compliant with the Declarative Services specification if set to `true`. Only set this if you really know you need this. See the *Non-Standard Component Factory Behaviour* section below for more details. | | `ds.delayed.keepInstances` | `false` | 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 off unused components. See [FELIX-3039](https://issues.apache.org/jira/browse/FELIX-3039) for details. | The `ds.loglevel` property is treated as follows: * If the property is a number, the `int` value of the number is used * If the property is a string parseable to an `int` the parsed value is used * If the property is any of the strings *debug*, *info*, *warn*, or *error*, the respective log level of `4`, `3`, `2`, or `1` is used * Otherwise, unless the `ds.showtrace` or `ds.showerrors` property is set, the default value is assumed This configuration mechanism is implemented in the [ScrConfiguration](https://github.com/apache/felix-dev/blob/master/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfigurationImpl.java) and its helper classes. ## Non-Standard Component Factory Behaviour

If you don't know what this section is about, just ignore it and leave the ds.factory.enabled configuration property unconfigured.
This behaviour assumes the component name of the Component Factory component to be Service Factory PID and each configuration with this Service Factory PID causes the service component runtime to actually create and activate an instance of the Component Factory component automatically. This is not foreseen by the specification which defines instantiation of Component Factory components as being purely application controled and not configuration induced. To have components instantiated with factory configurations, regular components should be used. This case each factory configuration instance will create a component instance. If you know that you are using Component Factory components depending on this non-standard behaviour you may set the `ds.factory.enabled` configuration property to `true` (the default of this property is `false` thus disabling this functionality for specification compliance). For details also refer to [FELIX-1416](https://issues.apache.org/jira/browse/FELIX-1416) ## Administration The OSGi Compendium specification defines an administrative API for Declarative Services through the [Service Component Runtime](https://osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#service.component-service.component.runtime). This bundle implements that service, too. Based on the runtime api, the [Declarative Service Plugin](https://github.com/apache/felix-dev/tree/master/webconsole-plugins/ds) for the [Apache Felix Web Console](http://felix.apache.org/documentation/subprojects/apache-felix-web-console.html) provides support for Declarative Services administration through a browser. This bundle itself also has a Felix Shell Command providing easy commands to introspect the states of the registered components. ### Shell Command The management API is made available to the Felix Shell as the `scr` command with a short list of subcommands: | Synopsis | Description | |--|--| | `scr help [ ]` | Show help of the specific `` or list all known subcommands | | `scr list [ ]` | List registered components of the bundle specified by `` or list all components. Each component is listed with its component ID, the state and the name. `` man be either the ID of a bundle or the symbolic name of a bundle. | | `scr info ` | Show a complete information dump of the given component. This dump includes the name, status, provided services and information on the service references. `` may be either the ID of a component or the component's name. The component name must be used for disabled components. | | `scr enable ` | Enable the given component if not already enabled. If the component is already destroyed or enabled, this command has no effect. `` may be either the ID of a component or the component's name. The component name must be used for disabled components. | | `scr disable ` | Disable the given component if not already disabled. If the component is already destroyed or disabled, this command has no effect. `` may be either the ID of a component or the component's name. The component name must be used for disabled components. | The administrative API commands are also available in the Gogo shell where the subcommand names must be prefixed with the name space `scr`. Thus the `list` command corresponds to `scr:list` in the Gogo shell. felix-scr-2.1.20/src/0000755000175000017500000000000013675426212013321 5ustar sudipsudipfelix-scr-2.1.20/src/main/0000755000175000017500000000000013675426212014245 5ustar sudipsudipfelix-scr-2.1.20/src/main/appended-resources/0000755000175000017500000000000013675426212020035 5ustar sudipsudipfelix-scr-2.1.20/src/main/appended-resources/META-INF/0000755000175000017500000000000013675426212021175 5ustar sudipsudipfelix-scr-2.1.20/src/main/appended-resources/META-INF/LICENSE0000644000175000017500000000261613675426212022207 0ustar sudipsudip APACHE FELIX DECLARATIVE SERVICES SUBCOMPONENTS: The Apache Felix Declarative Services includes a number of subcomponents with separate copyright notices and license terms. Your use of the source code for the these subcomponents is subject to the terms and conditions of the following licenses. For the KXml component: Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. felix-scr-2.1.20/src/main/appended-resources/META-INF/DEPENDENCIES0000644000175000017500000000155213675426212022751 0ustar sudipsudipI. Included Software This product includes software developed at The Apache Software Foundation (http://www.apache.org/). Licensed under the Apache License 2.0. This product includes software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. This product includes software from http://kxml.sourceforge.net. Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany. Licensed under BSD License. II. Used Software This product uses software developed at The Apache Software Foundation (http://www.apache.org/). Licensed under the Apache License 2.0. This product uses software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. III. License Summary - Apache License 2.0 - BSD License felix-scr-2.1.20/src/main/appended-resources/META-INF/NOTICE0000644000175000017500000000025013675426212022076 0ustar sudipsudipThis product includes software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. felix-scr-2.1.20/src/main/java/0000755000175000017500000000000013675426212015166 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/0000755000175000017500000000000013675426212015755 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/osgi/0000755000175000017500000000000013675426212016716 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/osgi/service/0000755000175000017500000000000013675426212020356 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/osgi/service/log/0000755000175000017500000000000013675426212021137 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/osgi/service/log/LoggerFactory.java0000644000175000017500000000174713675426212024562 0ustar sudipsudip/* * Copyright (c) OSGi Alliance (2016). All Rights Reserved. * * Licensed 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.osgi.service.log; import org.osgi.annotation.versioning.ProviderType; /** * This is a stripped down copy of the LogService 1.4 API (R7). It's * trimmed down to the methods used by the optional support for * R7 logging. */ @ProviderType public interface LoggerFactory { L getLogger(String name, Class loggerType); } felix-scr-2.1.20/src/main/java/org/osgi/service/log/Logger.java0000644000175000017500000000247713675426212023233 0ustar sudipsudip/* * Copyright (c) OSGi Alliance (2016, 2017). All Rights Reserved. * * Licensed 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.osgi.service.log; import org.osgi.annotation.versioning.ProviderType; /** * This is a stripped down copy of the LogService 1.4 API (R7). It's * trimmed down to the methods used by the optional support for * R7 logging. */ @ProviderType public interface Logger { String ROOT_LOGGER_NAME = "ROOT"; boolean isDebugEnabled(); void debug(String message); void debug(String format, Object arg); boolean isInfoEnabled(); void info(String message); void info(String format, Object arg); boolean isWarnEnabled(); void warn(String message); void warn(String format, Object arg); boolean isErrorEnabled(); void error(String message); void error(String format, Object arg); } felix-scr-2.1.20/src/main/java/org/apache/0000755000175000017500000000000013675426212017176 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/0000755000175000017500000000000013675426212020305 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/0000755000175000017500000000000013675426212021074 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/component/0000755000175000017500000000000013675426212023076 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/component/ExtFactoryComponentInstance.java0000644000175000017500000000206113675426212031400 0ustar sudipsudip/* * 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.component; import java.util.Dictionary; import org.osgi.service.component.ComponentInstance; public interface ExtFactoryComponentInstance extends ComponentInstance { void modify( Dictionary properties ); } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/component/ExtComponentContext.java0000644000175000017500000000402613675426212027733 0ustar sudipsudip/* * 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.component; import java.util.Dictionary; import org.osgi.service.component.ComponentContext; /** * The ExtComponentContext is a custom extension of the * standard ComponentContext allowing to update the service registration * properties of a component registered as a service. */ public interface ExtComponentContext extends ComponentContext { /** * Sets the service registration properties of the component * registered as a service. If the component is not registered as * a service, this method has no effect. *

* The component.id and component.name * property are set by the Service Component Runtime and cannot be * removed or replaced. * * @param properties properties to update the default component * properties with. If this is null or empty the * default set of properties as defined in Section 112.6, * Component Properties, are used as the service registration * properties. * * @throws IllegalStateException if this method is called for a * Component Factory component */ void setServiceProperties( Dictionary properties ); } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/info/0000755000175000017500000000000013675426212022027 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/info/ScrInfo.java0000644000175000017500000000360613675426212024242 0ustar sudipsudip/* * 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.info; import java.io.PrintWriter; /** * Abstraction of command interface. * */ public interface ScrInfo { /** * List in text the components for the bundle specified, or all components if null, sorted by component ID * @param bundleIdentifier bundle the components are in or null for all components * @param out PrintStream for normal output * @throws IllegalArgumentException if nothing can be found */ void list(String bundleIdentifier, PrintWriter out); /** * List in text detailed information about the specified components. Components can be specified by * numeric componentId, component name, a regexp to match for component name, or null for all components. * @param componentId specifier for desired components * @param out PrintStream for normal output * @throws IllegalArgumentException if nothing can be found */ void info(String componentId, PrintWriter out); /** * List in text the current SCR configuration * @param out PrintStream for output. */ void config(PrintWriter out); }felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/0000755000175000017500000000000013675426212022035 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/ComponentCommandsScrInfo.java0000644000175000017500000001013213675426212027605 0ustar sudipsudip/* * 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.info.ScrInfo; import org.apache.felix.service.command.Converter; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO; import java.io.PrintWriter; public class ComponentCommandsScrInfo implements ScrInfo { private final ComponentCommands commands; private final BundleContext context; ComponentCommandsScrInfo(ComponentCommands commands, BundleContext context) { this.commands = commands; this.context = context; } @Override public void list(String bundleIdentifier, PrintWriter out) { final CharSequence formatted; try { ComponentDescriptionDTO[] dtos = bundleIdentifier == null ? commands.list() : commands.list(getBundleID(bundleIdentifier)); if (dtos != null) { formatted = commands.format(dtos, 1); } else { formatted = "No components found for bundle " + bundleIdentifier; } } catch (Exception e) { throw new RuntimeException("Error listing or formatting SCR runtime information", e); } out.println(formatted); } private long getBundleID(String bundleIdentifier) { try { return Long.parseLong(bundleIdentifier); } catch (NumberFormatException e) { // might be a BSN Bundle bundle = findBundle(bundleIdentifier); if (bundle == null) throw new IllegalArgumentException("Cannot find bundle with ID: " + bundleIdentifier); return bundle.getBundleId(); } } @Override public void info(String componentId, PrintWriter out) { if (componentId != null) { Object infoObj; try { long configId = Long.parseLong(componentId); infoObj = commands.info(configId); } catch (NumberFormatException e) { infoObj = commands.info(componentId); } CharSequence formatted = format(infoObj, out, Converter.INSPECT); if (formatted == null) { out.println("No component found with ID " + componentId); } else { out.println(formatted); } return; } ComponentDescriptionDTO[] components = commands.list(); if (components.length > 0) { for (ComponentDescriptionDTO componentDescriptionDTO : components) { out.println(format(componentDescriptionDTO, out, Converter.INSPECT)); } } else { out.println("No component found."); } } private CharSequence format(Object info, PrintWriter out, int level) { if (info != null) { try { return commands.format(info, level); } catch (Exception e) { throw new RuntimeException("Error formatting SCR runtime information", e); } } return null; } @Override public void config(PrintWriter out) { out.println(commands.config()); } private Bundle findBundle(String bsn) { for (Bundle b : context.getBundles()) { if (b.getSymbolicName().equals(bsn)) return b; } return null; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/ComponentRegistryKey.java0000644000175000017500000000412413675426212027045 0ustar sudipsudip/* * 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.osgi.framework.Bundle; /** * The ComponentRegistryKey is used as the key in the * component registry to register components by their names. *

* Two instances of this class are equal if they are the same or if there * component name and bundle ID is equal. */ final class ComponentRegistryKey { private final long bundleId; private final String componentName; ComponentRegistryKey( final Bundle bundle, final String componentName ) { this.bundleId = bundle.getBundleId(); this.componentName = componentName; } public int hashCode() { int code = ( int ) this.bundleId; code += 31 * this.componentName.hashCode(); return code; } public boolean equals( Object obj ) { if ( this == obj ) { return true; } if ( obj instanceof ComponentRegistryKey ) { ComponentRegistryKey other = ( ComponentRegistryKey ) obj; return this.bundleId == other.bundleId && this.componentName.equals( other.componentName ); } return false; } public long getBundleId() { return bundleId; } public String getComponentName() { return componentName; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/0000755000175000017500000000000013675426212023615 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java0000644000175000017500000006334613675426212030033 0ustar sudipsudip/* * 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.metadata; import static org.apache.felix.scr.impl.metadata.MetadataStoreHelper.addString; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Set; import java.util.TreeSet; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataReader; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataWriter; /** * Information associated to a dependency * */ public class ReferenceMetadata { public enum ReferenceScope {bundle, prototype, prototype_required} // constant for option single reference - 0..1 public static final String CARDINALITY_0_1 = "0..1"; // constant for option multiple reference - 0..n public static final String CARDINALITY_0_N = "0..n"; // constant for required single reference - 1..1 public static final String CARDINALITY_1_1 = "1..1"; // constant for required multiple reference - 1..n public static final String CARDINALITY_1_N = "1..n"; // set of valid cardinality settings private static final Set CARDINALITY_VALID; // constant for static policy public static final String POLICY_STATIC = "static"; // constant for dynamic policy public static final String POLICY_DYNAMIC = "dynamic"; // set of valid policy settings private static final Set POLICY_VALID; // constant for reluctant policy option public static final String POLICY_OPTION_RELUCTANT = "reluctant"; // constant for greedy policy option public static final String POLICY_OPTION_GREEDY = "greedy"; // set of valid policy option settings private static final Set POLICY_OPTION_VALID; // constant for update field strategy private static final String FIELD_STRATEGY_UPDATE = "update"; // constant for replace field strategy private static final String FIELD_STRATEGY_REPLACE = "replace"; // set of valid field strategy settings private static final Set FIELD_STRATEGY_VALID; // constant for field value type service public static final String FIELD_VALUE_TYPE_SERVICE = "service"; // constant for field value type properties public static final String FIELD_VALUE_TYPE_PROPERTIES = "properties"; // constant for field value type reference public static final String FIELD_VALUE_TYPE_REFERENCE = "reference"; // constant for field value type serviceobjects public static final String FIELD_VALUE_TYPE_SERVICEOBJECTS = "serviceobjects"; // constant for field value type tuple public static final String FIELD_VALUE_TYPE_TUPLE = "tuple"; // set of valid field value type settings private static final Set FIELD_VALUE_TYPE_VALID; // Name for the reference (required) private String m_name; // Interface name (required) private String m_interface; // Cardinality (optional, default="1..1") private String m_cardinality; // Target (optional) private String m_target; // Name of the bind method (optional) private String m_bind; // Name of the updated method (optional, since DS 1.1-felix) private String m_updated; // Name of the unbind method (optional) private String m_unbind; // Name of the field (optional, since DS 1.3) private String m_field; // Name of the strategy for the field (optional, since DS 1.3) private String m_field_option; // Name of the value type for the field (optional, since DS 1.3) // Since 1.4 also used for the parameter collection type (constructor) private String m_collection_type; // Policy attribute (optional, default = static) private String m_policy; // Policy option attribute (optional, default = reluctant) private String m_policy_option; private String m_scopeName; private ReferenceScope m_scope = ReferenceScope.bundle; // Parameter value (optional, since DS 1.4) private String m_parameter; // Parameter index, set based on {@code m_parameter} after validation // (optional, since DS 1.4) private Integer m_parameterIndex; // Flags that store the values passed as strings private boolean m_isStatic = true; private boolean m_isOptional = false; private boolean m_isMultiple = false; private boolean m_isReluctant = true; private boolean m_isReplace = true; // Flag that is set once the component is verified (its properties cannot be changed) private boolean m_validated = false; static { CARDINALITY_VALID = new TreeSet<>(); CARDINALITY_VALID.add( CARDINALITY_0_1 ); CARDINALITY_VALID.add( CARDINALITY_0_N ); CARDINALITY_VALID.add( CARDINALITY_1_1 ); CARDINALITY_VALID.add( CARDINALITY_1_N ); POLICY_VALID = new TreeSet<>(); POLICY_VALID.add( POLICY_DYNAMIC ); POLICY_VALID.add( POLICY_STATIC ); POLICY_OPTION_VALID = new TreeSet<>(); POLICY_OPTION_VALID.add( POLICY_OPTION_RELUCTANT ); POLICY_OPTION_VALID.add( POLICY_OPTION_GREEDY ); FIELD_STRATEGY_VALID = new TreeSet<>(); FIELD_STRATEGY_VALID.add( FIELD_STRATEGY_REPLACE ); FIELD_STRATEGY_VALID.add( FIELD_STRATEGY_UPDATE ); FIELD_VALUE_TYPE_VALID = new TreeSet<>(); FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_PROPERTIES ); FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_REFERENCE ); FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_SERVICE ); FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_SERVICEOBJECTS ); FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_TUPLE ); } /////////////////////////////////////////////// setters /////////////////////////////////// /** * Setter for the name attribute * * @param name */ public void setName( String name ) { if ( m_validated ) { return; } m_name = name; } /** * Setter for the interfaceName attribute * * @param interfaceName */ public void setInterface( String interfaceName ) { if ( m_validated ) { return; } m_interface = interfaceName; } /** * Setter for the cardinality attribute * * @param cardinality */ public void setCardinality( String cardinality ) { if ( m_validated ) { return; } m_cardinality = cardinality; // secondary properties m_isOptional = CARDINALITY_0_1.equals( cardinality ) || CARDINALITY_0_N.equals( cardinality ); m_isMultiple = CARDINALITY_0_N.equals( cardinality ) || CARDINALITY_1_N.equals( cardinality ); } /** * Setter for the policy attribute * * @param policy */ public void setPolicy( String policy ) { if ( m_validated ) { return; } m_policy = policy; // secondary property m_isStatic = POLICY_STATIC.equals( policy ); } /** * Setter for the policy option attribute * * @param policyOption */ public void setPolicyOption( String policyOption ) { if ( m_validated ) { return; } m_policy_option = policyOption; // secondary property m_isReluctant = POLICY_OPTION_RELUCTANT.equals( policyOption ); } /** * Setter for the target attribute (filter) * * @param target */ public void setTarget( String target ) { if ( m_validated ) { return; } m_target = ( target == null || target.length() == 0 ) ? null : target; } /** * Setter for the bind method attribute * * @param bind */ public void setBind( String bind ) { if ( m_validated ) { return; } m_bind = bind; } /** * Setter for the updated method attribute * * @param updated */ public void setUpdated( String updated ) { if ( m_validated ) { return; } m_updated = updated; } /** * Setter for the unbind method attribute * * @param unbind */ public void setUnbind( String unbind ) { if ( m_validated ) { return; } m_unbind = unbind; } /** * Setter for the field attribute * * @param field the field name */ public void setField( final String field ) { if ( m_validated ) { return; } m_field = field; } /** * Setter for the field strategy attribute * * @param strategy the field strategy */ public void setFieldOption( final String strategy ) { if ( m_validated ) { return; } m_field_option = strategy; m_isReplace = FIELD_STRATEGY_REPLACE.equals(strategy); } /** * Setter for the field value type attribute * * @param valuetype the field value type */ public void setFieldCollectionType( final String valuetype ) { if ( m_validated ) { return; } m_collection_type = valuetype; } public void setScope(String scopeName) { if ( m_validated ) { return; } this.m_scopeName = scopeName; } /** * Setter for the parameter value * DS 1.4 * @param attribute value */ public void setParameter(String val) { if ( m_validated ) { return; } this.m_parameter = val; } /////////////////////////////////////////////// getters /////////////////////////////////// /** * Returns the name of the reference * * @return A string containing the reference's name **/ public String getName() { return m_name; } /** * Returns the fully qualified name of the class that is used by the component to access the service * * @return A string containing a fully qualified name **/ public String getInterface() { return m_interface; } /** * Get the cardinality as a string * * @return A string with the cardinality **/ public String getCardinality() { return m_cardinality; } /** * Get the policy as a string * * @return A string with the policy **/ public String getPolicy() { return m_policy; } /** * Get the policy option as a string * * @return A string with the policy option **/ public String getPolicyOption() { return m_policy_option; } /** * Returns the filter expression that further constrains the set of target services * * @return A string with a filter **/ public String getTarget() { return m_target; } /** * Get the name of a method in the component implementation class that is used to notify that * a service is bound to the component configuration * * @return a String with the name of the bind method **/ public String getBind() { return m_bind; } /** * Get the name of a method in the component implementation class that is used to notify that * the service properties of a bound service have been updated * * @return a String with the name of the updated method **/ public String getUpdated() { return m_updated; } /** * Get the name of a method in the component implementation class that is used to notify that * a service is unbound from the component configuration * * @return a String with the name of the unbind method **/ public String getUnbind() { return m_unbind; } /** * Get the name of a field in the component implementation class that is used to hold * the reference * * @return a String with the name of the field */ public String getField() { return m_field; } /** * Get the strategy of a field in the component implementation class that is used to hold * the reference * * @return a String with the strategy name for the field */ public String getFieldOption() { return m_field_option; } /** * Get the value type of a field in the component implementation class that is used to hold * the reference * * @return a String with the value type for the field */ public String getFieldCollectionType() { return m_collection_type; } /** * Get the parameter index, if specified. * This method returns the correct value only after this metadata object has been validated * by a call to {@link #validate(ComponentMetadata, Logger)} and the validation has been * successful. * DS 1.4 * @return The parameter index , if no parameter is set this returns {@code -null} */ public Integer getParameterIndex() { return m_parameterIndex; } /** * Get the value type of a parameter in the component implementation class that is used to hold * the reference * DS 1.4 * @return a String with the value type for the parameter */ public String getParameterCollectionType() { return m_collection_type; } // Getters for boolean values that determine both policy and cardinality /** * Test if dependency's binding policy is static * * @return true if static **/ public boolean isStatic() { return m_isStatic; } /** * Test if dependency is optional (0..1 or 0..n) * * @return true if the dependency is optional **/ public boolean isOptional() { return m_isOptional; } /** * Test if dependency is multiple (0..n or 1..n) * * @return true if the dependency is multiple **/ public boolean isMultiple() { return m_isMultiple; } /** * Test if policy option is reluctant * * @return true if policy option is reluctant */ public boolean isReluctant() { return m_isReluctant; } /** * Test if field strategy is replace. * * @return true if field strategy is replace */ public boolean isReplace() { return m_isReplace; } /** * Returns the name of the component property referring to the {@link #getTarget() target} * property of this reference. * * @return the name of the target property which is the name of this referene * suffixed with the string ".target". */ public String getTargetPropertyName() { return getName() + ".target"; } public String getMinCardinalityName() { return getName() + ".cardinality.minimum"; } public ReferenceScope getScope() { return m_scope; } /** * Method used to verify if the semantics of this metadata are correct * */ void validate(final ComponentMetadata componentMetadata ) { final DSVersion dsVersion = componentMetadata.getDSVersion(); if ( m_name == null ) { // 112.10 name attribute is optional, defaults to interface since DS 1.1 if ( !dsVersion.isDS11() ) { throw componentMetadata.validationFailure( "A name must be declared for the reference" ); } setName( getInterface() ); } if ( m_interface == null ) { throw componentMetadata.validationFailure( "An interface must be declared for the reference" ); } if ( m_cardinality == null ) { setCardinality( CARDINALITY_1_1 ); } else if ( !CARDINALITY_VALID.contains( m_cardinality ) ) { throw componentMetadata.validationFailure( "Cardinality must be one of " + CARDINALITY_VALID ); } if ( m_policy == null ) { setPolicy( POLICY_STATIC ); } else if ( !POLICY_VALID.contains( m_policy ) ) { throw componentMetadata.validationFailure( "Policy must be one of " + POLICY_VALID ); } if ( m_policy_option == null ) { setPolicyOption( POLICY_OPTION_RELUCTANT ); } else if ( !POLICY_OPTION_VALID.contains( m_policy_option ) ) { throw componentMetadata.validationFailure( "Policy option must be one of " + POLICY_OPTION_VALID ); } else if ( !dsVersion.isDS12() && !POLICY_OPTION_RELUCTANT.equals( m_policy_option ) ) { throw componentMetadata.validationFailure( "Policy option must be reluctant for DS < 1.2" ); } if (m_scopeName != null) { if ( !dsVersion.isDS13() ) { throw componentMetadata.validationFailure( "reference scope can be set only for DS >= 1.3"); } try { m_scope = ReferenceScope.valueOf(m_scopeName); } catch (final IllegalArgumentException e) { throw componentMetadata.validationFailure( "reference scope must be 'bundle' or 'prototype' not " + m_scopeName); } } // checks for event based injection // updated method is only supported in namespace xxx and later if ( m_updated != null && !(dsVersion.isDS12() || dsVersion == DSVersion.DS11Felix) ) { // FELIX-3648 validation must fail (instead of just ignore) throw componentMetadata.validationFailure( "updated method declaration requires DS 1.2 or later namespace " ); } // checks for field injection if ( m_field != null ) { // field reference requires DS 1.3 if ( !dsVersion.isDS13() ) { throw componentMetadata.validationFailure( "Field reference requires DS >= 1.3" ); } // field strategy if ( m_field_option == null ) { setFieldOption( FIELD_STRATEGY_REPLACE ); } else if ( !FIELD_STRATEGY_VALID.contains( m_field_option ) ) { throw componentMetadata.validationFailure( "Field strategy must be one of " + FIELD_STRATEGY_VALID ); } if ( !m_isMultiple ) { // update is not allowed for unary references if ( m_field_option.equals(FIELD_STRATEGY_UPDATE) ) { throw componentMetadata.validationFailure( "Field strategy update not allowed for unary field references." ); } } // field value type if ( !m_isMultiple ) { // value type must not be specified for unary references if ( m_collection_type != null ) { // spec says to ignore this this.m_collection_type = null; } } else { if ( m_collection_type == null ) { setFieldCollectionType( FIELD_VALUE_TYPE_SERVICE ); } else if ( !FIELD_VALUE_TYPE_VALID.contains( m_collection_type ) ) { throw componentMetadata.validationFailure( "Field value type must be one of " + FIELD_VALUE_TYPE_VALID ); } } } if ( m_parameter != null ) { // parameter requires DS 1.4 if ( !dsVersion.isDS14() ) { throw componentMetadata.validationFailure( "Reference parameter requires DS >= 1.4" ); } try { m_parameterIndex = Integer.valueOf(m_parameter); } catch ( final NumberFormatException nfe) { throw componentMetadata.validationFailure( "Reference parameter is not a number: " + m_parameter ); } if ( m_parameterIndex < 0 ) { throw componentMetadata.validationFailure( "Reference parameter value must be zero or higher: " + m_parameter ); } // parameter value type if ( !m_isMultiple ) { // value type must not be specified for unary references if ( m_collection_type != null ) { // spec says to ignore this this.m_collection_type = null; } } else { if ( m_collection_type == null ) { setFieldCollectionType( FIELD_VALUE_TYPE_SERVICE ); } else if ( !FIELD_VALUE_TYPE_VALID.contains( m_collection_type ) ) { throw componentMetadata.validationFailure( "Collection value type must be one of " + FIELD_VALUE_TYPE_VALID ); } } } m_validated = true; } public String getDebugInfo() { return getName() + "interface=" + this.getInterface() + ", filter=" + this.getTarget() + ", policy=" + this.getPolicy() + ", cardinality=" + this.getCardinality() + ", bind=" + this.getBind() + ", unbind=" + this.getUnbind() + ", updated=" + this.getUpdated() + ", field=" + this.getField() + ", field-option=" + this.getFieldOption() + ", collection-type=" + this.getFieldCollectionType() + ", parameter=" + this.getParameterIndex(); } void collectStrings(Set strings) { addString(m_bind, strings); addString(m_cardinality, strings); addString(m_collection_type, strings); addString(m_field, strings); addString(m_field_option, strings); addString(m_interface, strings); addString(m_name, strings); addString(m_parameter, strings); addString(m_policy, strings); addString(m_policy_option, strings); addString(m_scopeName, strings); addString(m_scope.toString(), strings); addString(m_target, strings); addString(m_unbind, strings); addString(m_updated, strings); } void store(DataOutputStream out, MetaDataWriter metaDataWriter) throws IOException { metaDataWriter.writeString(m_bind, out); metaDataWriter.writeString(m_cardinality, out); metaDataWriter.writeString(m_collection_type, out); metaDataWriter.writeString(m_field, out); metaDataWriter.writeString(m_field_option, out); metaDataWriter.writeString(m_interface, out); out.writeBoolean(m_isMultiple); out.writeBoolean(m_isOptional); out.writeBoolean(m_isReluctant); out.writeBoolean(m_isReplace); out.writeBoolean(m_isStatic); metaDataWriter.writeString(m_name, out); metaDataWriter.writeString(m_parameter, out); out.writeBoolean(m_parameterIndex != null); if (m_parameterIndex != null) { out.writeInt(m_parameterIndex.intValue()); } metaDataWriter.writeString(m_policy, out); metaDataWriter.writeString(m_policy_option, out); metaDataWriter.writeString(m_scopeName, out); metaDataWriter.writeString(m_scope.toString(), out); metaDataWriter.writeString(m_target, out); metaDataWriter.writeString(m_unbind, out); metaDataWriter.writeString(m_updated, out); } static ReferenceMetadata load(DataInputStream in, MetaDataReader metaDataReader) throws IOException { ReferenceMetadata result = new ReferenceMetadata(); result.m_bind = metaDataReader.readString(in); result.m_cardinality = metaDataReader.readString(in); result.m_collection_type = metaDataReader.readString(in); result.m_field = metaDataReader.readString(in); result.m_field_option = metaDataReader.readString(in); result.m_interface = metaDataReader.readString(in); result.m_isMultiple = in.readBoolean(); result.m_isOptional = in.readBoolean(); result.m_isReluctant = in.readBoolean(); result.m_isReplace = in.readBoolean(); result.m_isStatic = in.readBoolean(); result.m_name = metaDataReader.readString(in); result.m_parameter = metaDataReader.readString(in); if (in.readBoolean()) { result.m_parameterIndex = Integer.valueOf(in.readInt()); } result.m_policy = metaDataReader.readString(in); result.m_policy_option = metaDataReader.readString(in); result.m_scopeName = metaDataReader.readString(in); result.m_scope = ReferenceScope.valueOf(metaDataReader.readString(in)); result.m_target = metaDataReader.readString(in); result.m_unbind = metaDataReader.readString(in); result.m_updated = metaDataReader.readString(in); // only stored valid metadata result.m_validated = true; return result; } }felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/PropertyMetadata.java0000644000175000017500000002342113675426212027747 0ustar sudipsudip/* * 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.metadata; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; /** * A property descriptor that contains the information for properties * defined in the descriptor * */ public class PropertyMetadata { // Name of the property (required) private String m_name; // Type of the property (optional) private String m_type; // Value of the type (optional) // - before validate: raw value from XML (String or String[]) // - after validate: converted value provided to component private Object m_value; // Flag that indicates if this PropertyMetadata has been validated and thus has become immutable private boolean m_validated = false; /** * Set the name * * @param name */ public void setName(String name) { if (m_validated == true) { return; } m_name = name; } /** * Set the type * * @param type */ public void setType(String type) { if (m_validated == true) { return; } m_type = type; } /** * Set the value * * @param value */ public void setValue(String value) { if (m_validated == true) { return; } m_value = value; } /** * Set multiple values as an array, where the values are contained in * the string as one value per line. * * @param values */ public void setValues(String values) { if (m_validated == true) { return; } // splite th values List valueList = new ArrayList(); StringTokenizer tokener = new StringTokenizer(values, "\r\n"); while (tokener.hasMoreTokens()) { String value = tokener.nextToken().trim(); if (value.length() > 0) { valueList.add( value ); } } m_value = valueList.toArray( new String[valueList.size()] ); } /** * Get the name of the property * * @return the name of the property */ public String getName() { return m_name; } /** * Get the type of the property * * @return the type of the property */ public String getType() { return m_type; } /** * Get the value of the property * * @return the value of the property as an Object */ public Object getValue() { return m_value; } /** * Method used to verify if the semantics of this metadata are correct */ public void validate( ComponentMetadata componentMetadata ) { if ( m_name == null ) { throw componentMetadata.validationFailure( "Property name attribute is mandatory" ); } // check character type name if ( m_type == null ) { m_type = "String"; } else if ( componentMetadata.getDSVersion().isDS11() && m_type.equals( "Char" ) ) { throw componentMetadata .validationFailure( "Illegal property type 'Char' used for DS 1.1 descriptor, use 'Character' instead" ); } else if ( !componentMetadata.getDSVersion().isDS11() && m_type.equals( "Character" ) ) { throw componentMetadata .validationFailure( "Illegal property type 'Character' used for DS 1.0 descriptor, use 'Char' instead" ); } // validate and covert value if ( m_value != null ) { try { if ( m_value instanceof String ) { m_value = toType( ( String ) m_value ); } else { m_value = toTypeArray( ( String[] ) m_value ); } } catch ( NumberFormatException nfe ) { throw componentMetadata.validationFailure( getName() + ": Cannot convert property value to " + getType() ); } catch ( IllegalArgumentException e ) { throw componentMetadata.validationFailure( getName() + ": " + e.getMessage() ); } } m_validated = true; } /** * @throws IllegalArgumentException if the property type is not valid * according to the spec * @throws NumberFormatException if the string value cannot be converted * to the numeric type indicated by the property type */ private Object toType( String value ) { // 112.4.5 Parsing of the value is done by the valueOf(String) method (P. 291) // Should the type accept lowercase too? if ( m_type.equals( "String" ) ) { return value; } else if ( m_type.equals( "Long" ) ) { return Long.valueOf( value ); } else if ( m_type.equals( "Double" ) ) { return Double.valueOf( value ); } else if ( m_type.equals( "Float" ) ) { return Float.valueOf( value ); } else if ( m_type.equals( "Integer" ) ) { return Integer.valueOf( value ); } else if ( m_type.equals( "Byte" ) ) { return Byte.valueOf( value ); } else if ( m_type.equals( "Char" ) || m_type.equals( "Character" ) ) { // DS 1.1 changes the "Char" type to "Character", here we support both // For Character types, the conversion is handled by Integer.valueOf method. // (since valueOf is defined in terms of parseInt we directly call // parseInt to prevent unneeded Object creation) return Character.valueOf( ( char ) Integer.parseInt( value ) ); } else if ( m_type.equals( "Boolean" ) ) { return Boolean.valueOf( value ); } else if ( m_type.equals( "Short" ) ) { return Short.valueOf( value ); } else { throw new IllegalArgumentException( "Undefined property type '" + m_type + "'" ); } } /** * @throws IllegalArgumentException if the property type is not valid * according to the spec * @throws NumberFormatException if the string value cannot be converted * to the numeric type indicated by the property type */ private Object toTypeArray( String[] valueList ) { // 112.4.5 Except for String objects, the result will be translated to an array of primitive types. if ( m_type.equals( "String" ) ) { return valueList; } else if ( m_type.equals( "Double" ) ) { double[] array = new double[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Double.parseDouble( valueList[i] ); } return array; } else if ( m_type.equals( "Float" ) ) { float[] array = new float[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Float.parseFloat( valueList[i] ); } return array; } else if ( m_type.equals( "Long" ) ) { long[] array = new long[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Long.parseLong( valueList[i] ); } return array; } else if ( m_type.equals( "Integer" ) ) { int[] array = new int[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Integer.parseInt( valueList[i] ); } return array; } else if ( m_type.equals( "Short" ) ) { short[] array = new short[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Short.parseShort( valueList[i] ); } return array; } else if ( m_type.equals( "Byte" ) ) { byte[] array = new byte[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Byte.parseByte( valueList[i] ); } return array; } else if ( m_type.equals( "Char" ) || m_type.equals( "Character" ) ) { // DS 1.1 changes the "Char" type to "Character", here we support both char[] array = new char[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = ( char ) Integer.parseInt( valueList[i] ); } return array; } else if ( m_type.equals( "Boolean" ) ) { boolean[] array = new boolean[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Boolean.valueOf( valueList[i] ); } return array; } else { throw new IllegalArgumentException( "Undefined property type '" + m_type + "'" ); } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/MetadataStoreHelper.java0000644000175000017500000001211613675426212030356 0ustar sudipsudip/* * 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.metadata; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; public class MetadataStoreHelper { // The version of the component metadata store. If the // stored metadata is not this version then the cache is ignored static final int STORE_VERSION = 1; static final byte STRING_NULL = 0; static final byte STRING_OBJECT = 1; static final byte STRING_INDEX = 2; static final byte STRING_LONG = 3; public static class MetaDataReader { private final List stringTable = new ArrayList(); public boolean isVersionSupported(DataInputStream in) throws IOException { return STORE_VERSION == in.readInt(); } public String readIndexedString(DataInputStream in) throws IOException { String s = readString(in); addToStringTable(s, in.readInt()); return s; } public String readString(DataInputStream in) throws IOException { byte type = in.readByte(); if (type == STRING_INDEX) { int index = in.readInt(); return (String) stringTable.get(index); } if (type == STRING_NULL) { return null; } String s; if (type == STRING_LONG) { int length = in.readInt(); byte[] data = new byte[length]; in.readFully(data); s = new String(data, "UTF-8"); } else { s = in.readUTF(); } return s; } private void addToStringTable(String s, int index) { if (index == stringTable.size()) { stringTable.add(s); } else if (index < stringTable.size()) { stringTable.set(index, s); } else { while (stringTable.size() < index) { stringTable.add(null); } stringTable.add(s); } } } public static class MetaDataWriter { private final Map stringTable = new HashMap<>(); public void writeVersion(DataOutputStream out) throws IOException { out.writeInt(STORE_VERSION); } public void writeIndexedString(String s, DataOutputStream out) throws IOException { writeString(s, out); out.writeInt(addToStringTable(s)); } public void writeString(String s, DataOutputStream out) throws IOException { Integer index = s != null ? stringTable.get(s) : null; if (index != null) { out.writeByte(STRING_INDEX); out.writeInt(index); return; } if (s == null) out.writeByte(STRING_NULL); else { byte[] data = s.getBytes("UTF-8"); if (data.length > 65535) { out.writeByte(STRING_LONG); out.writeInt(data.length); out.write(data); } else { out.writeByte(STRING_OBJECT); out.writeUTF(s); } } } private int addToStringTable(String s) { if (s == null) { throw new NullPointerException(); } Integer cur = stringTable.get(s); if (cur != null) throw new IllegalStateException( "String is already in the write table: " + s); int index = stringTable.size(); stringTable.put(s, Integer.valueOf(index)); // return the index of the object just added return index; } } public static void addString(String s, Set strings) { if (s != null) { strings.add(s); } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java0000644000175000017500000014135113675426212030070 0ustar sudipsudip/* * 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.metadata; import static org.apache.felix.scr.impl.metadata.MetadataStoreHelper.addString; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataReader; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataWriter; import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope; import org.osgi.service.component.ComponentException; /** * This class holds the information associated to a component in the descriptor */ public class ComponentMetadata { // Configuration required for component activation (since DS 1.1) public static final String CONFIGURATION_POLICY_REQUIRE = "require"; // Configuration not provided to component (since DS 1.1) public static final String CONFIGURATION_POLICY_IGNORE = "ignore"; // Configuration optional (default) (since DS 1.1) public static final String CONFIGURATION_POLICY_OPTIONAL = "optional"; // set of valid configuration policy settings private static final Set CONFIGURATION_POLICY_VALID; // marker value indicating duplicate implementation class setting private static final String IMPLEMENTATION_CLASS_DUPLICATE = "icd"; // marker value indicating duplicate service setting private static final ServiceMetadata SERVICE_DUPLICATE = new ServiceMetadata(); // the namespace code of the namespace declaring this component private final DSVersion m_dsVersion; // 112.4.3: A Globally unique component name (required) private String m_name; // 112.4.3: Controls whether the component is enabled when the bundle is started. (optional, default is true). private boolean m_enabled = true; // 112.4.3: Factory identified. If set to a non empty string, it indicates that the component is a factory component (optional). private String m_factory; // 112.4.3: Controls whether component configurations must be immediately activated after becoming // satisfied or whether activation should be delayed. (optional, default value depends // on whether the component has a service element or not). private Boolean m_immediate; // 112.4.4 Implementation Element (required) private String m_implementationClassName; // 112.5.8 activate can be specified (since DS 1.1) private String m_activate; // 112.5.8 whether activate has been specified private boolean m_activateDeclared = false; // 112.5.12 deactivate can be specified (since DS 1.1) private String m_deactivate; // 112.5.12 whether deactivate has been specified private boolean m_deactivateDeclared = false; // 112.??.?? modified method (configuration update, since DS 1.1) private String m_modified; // 112.4.3 configuration-policy (since DS 1.1) private String m_configurationPolicy; // 112.4.4 configuration-pid (since DS 1.2) private List m_configurationPid; // activation fields (since DS 1.4) private List m_activationFields; // Associated properties (0..*) private final Map m_properties = new HashMap<>(); // Associated factory properties (0..*) private final Map m_factoryProperties = new HashMap<>(); // List of Property metadata - used while building the meta data // while validating the properties contained in the PropertyMetadata // instances are copied to the m_properties Dictionary while this // list will be cleared private final List m_propertyMetaData = new ArrayList<>(); // List of Property metadata - used while building the meta data // while validating the properties contained in the PropertyMetadata // instances are copied to the m_factoryProperties Dictionary while this // list will be cleared private final List m_factoryPropertyMetaData = new ArrayList<>(); // Provided services (0..1) private ServiceMetadata m_service; // List of service references, (required services 0..*) private final List m_references = new ArrayList<>(); private boolean m_configurableServiceProperties; private boolean m_persistentFactoryComponent; private boolean m_deleteCallsModify; private Boolean m_obsoleteFactoryComponentFactory; private boolean m_configureWithInterfaces; private boolean m_delayedKeepInstances; private String m_init; // Flag that is set once the component is verified (its properties cannot be changed) private boolean m_validated = false; static { CONFIGURATION_POLICY_VALID = new TreeSet<>(); CONFIGURATION_POLICY_VALID.add( CONFIGURATION_POLICY_IGNORE ); CONFIGURATION_POLICY_VALID.add( CONFIGURATION_POLICY_OPTIONAL ); CONFIGURATION_POLICY_VALID.add( CONFIGURATION_POLICY_REQUIRE ); } public ComponentMetadata( final DSVersion dsVersion ) { this.m_dsVersion = dsVersion; } /////////////////////////////////////////// SETTERS ////////////////////////////////////// /** * Setter for the configuration-pid component (since DS 1.2) * @param configurationPid */ public void setConfigurationPid( String[] configurationPid ) { if ( m_validated ) { return; } m_configurationPid = new ArrayList<>( Arrays.asList( configurationPid ) ); } /** * Setter for the name * * @param name */ public void setName( String name ) { if ( m_validated ) { return; } m_name = name; } /** * Setter for the enabled property * * @param enabled */ public void setEnabled( boolean enabled ) { if ( m_validated ) { return; } m_enabled = enabled; } /** * * @param factoryIdentifier */ public void setFactoryIdentifier( String factoryIdentifier ) { if ( m_validated ) { return; } m_factory = factoryIdentifier; } /** * Setter for the immediate property * * @param immediate */ public void setImmediate( boolean immediate ) { if ( m_validated ) { return; } m_immediate = immediate ? Boolean.TRUE : Boolean.FALSE; } /** * Sets the name of the implementation class * * @param implementationClassName a class name */ public void setImplementationClassName( String implementationClassName ) { if ( m_validated ) { return; } // set special flag value if implementation class is already set if ( m_implementationClassName != null ) { m_implementationClassName = IMPLEMENTATION_CLASS_DUPLICATE; } else { m_implementationClassName = implementationClassName; } } /** * Sets the configuration policy * * @param configurationPolicy configuration policy * @since 1.2.0 (DS 1.1) */ public void setConfigurationPolicy( String configurationPolicy ) { if ( m_validated ) { return; } m_configurationPolicy = configurationPolicy; } /** * Sets the name of the activate method * * @param activate a method name * @since 1.2.0 (DS 1.1) */ public void setActivate( String activate ) { if ( m_validated ) { return; } m_activate = activate; m_activateDeclared = true; } /** * Sets the name of the deactivate method * * @param deactivate a method name * @since 1.2.0 (DS 1.1) */ public void setDeactivate( String deactivate ) { if ( m_validated ) { return; } m_deactivate = deactivate; m_deactivateDeclared = true; } /** * Sets the name of the modified method * * @param modified a method name * @since 1.2.0 (DS 1.1) */ public void setModified( String modified ) { if ( m_validated ) { return; } m_modified = modified; } /** * Used to add a property to the instance * * @param newProperty a property metadata object */ public void addProperty( PropertyMetadata newProperty ) { if ( m_validated ) { return; } if ( newProperty == null ) { throw new IllegalArgumentException( "Cannot add a null property" ); } m_propertyMetaData.add( newProperty ); } /** * Used to add a factory property to the instance * * @param newProperty a property metadata object */ public void addFactoryProperty( PropertyMetadata newProperty ) { if ( m_validated ) { return; } if ( newProperty == null ) { throw new IllegalArgumentException( "Cannot add a null property" ); } m_factoryPropertyMetaData.add( newProperty ); } /** * Used to set a ServiceMetadata object. * * @param service a ServiceMetadata */ public void setService( ServiceMetadata service ) { if ( m_validated ) { return; } // set special flag value if implementation class is already set if ( m_service != null ) { m_service = SERVICE_DUPLICATE; } else { m_service = service; } } /** * Used to add a reference metadata to the component * * @param newReference a new ReferenceMetadata to be added */ public void addDependency( ReferenceMetadata newReference ) { if ( m_validated ) { return; } if ( newReference == null ) { throw new IllegalArgumentException( "Cannot add a null ReferenceMetadata" ); } m_references.add( newReference ); } public void setConfigurableServiceProperties( boolean configurableServiceProperties) { if ( m_validated ) { return; } this.m_configurableServiceProperties = configurableServiceProperties; } public void setPersistentFactoryComponent(boolean persistentFactoryComponent) { if ( m_validated ) { return; } this.m_persistentFactoryComponent = persistentFactoryComponent; } public void setDeleteCallsModify(boolean deleteCallsModify) { if ( m_validated ) { return; } this.m_deleteCallsModify = deleteCallsModify; } public void setObsoleteFactoryComponentFactory( boolean obsoleteFactoryComponentFactory) { if ( m_validated ) { return; } this.m_obsoleteFactoryComponentFactory = obsoleteFactoryComponentFactory; } public void setConfigureWithInterfaces(boolean configureWithInterfaces) { this.m_configureWithInterfaces = configureWithInterfaces; } public void setDelayedKeepInstances(boolean delayedKeepInstances) { if ( m_validated ) { return; } this.m_delayedKeepInstances = delayedKeepInstances; } public void setActivationFields( final String[] fields ) { if ( !m_validated ) { this.m_activationFields = new ArrayList<>( Arrays.asList( fields ) ); } } public void setInit( final String value ) { if ( !m_validated ) { this.m_init = value; } } /////////////////////////////////////////// GETTERS ////////////////////////////////////// /** * Returns the namespace code of the namespace of the component element * declaring this component. This is one of the XmlHandler.DS_VERSION_* * constants. */ public DSVersion getDSVersion() { return m_dsVersion; } /** * Returns the name of the component * * @return A string containing the name of the component */ public String getName() { // FELIX-2325: Be lenient here and return the name if set or // the implementation class name. This allows for the // BundleComponentActivator.loadComponents method to access the // name before validating the component, which then makes sure // that the name may only be unset for DS 1.1 and newer components if ( m_name != null ) { return m_name; } // return the implementation class name if the name is not set return getImplementationClassName(); } /** * Returns the configuration pid for the component. The pid is the one specified in the * component's configuration-pid DS 1.2 attribute, if specified. Else the component name is used * as the pid by default. */ public List getConfigurationPid() { if ( !m_validated ) { throw new IllegalStateException("not yet validated"); } return m_configurationPid; } public int getPidIndex(TargetedPID pid) { if ( !m_validated ) { throw new IllegalStateException("not yet validated"); } if (m_configurationPid == null ) { throw new IllegalStateException( "Apparently trying to configure a component " + m_name + " without a configurationPid using " + pid); } return m_configurationPid.indexOf(pid.getServicePid()); } /** * Returns whether the configuration-pid has been declared in the descriptor * or not. * * @return whether the configuration-pid has method has been declared in the descriptor * or not. * @since DS 1.2 */ public boolean isConfigurationPidDeclared() { return m_configurationPid != null; } /** * Returns the value of the enabled flag * * @return a boolean containing the value of the enabled flag */ public boolean isEnabled() { return m_enabled; } /** * Returns the factory identifier * * @return A string containing a factory identifier or null */ public String getFactoryIdentifier() { return m_factory; } /** * Returns the flag that defines the activation policy for the component. *

* This method may only be trusted after this instance has been validated * by the {@link #validate( )} call. Else it will either return the value * of an explicitly set "immediate" attribute or return false if a service * element or the factory attribute is set or true otherwise. This latter * default value deduction may be unsafe while the descriptor has not been * completely read. * * @return a boolean that defines the activation policy */ public boolean isImmediate() { // return explicit value if known if ( m_immediate != null ) { return m_immediate.booleanValue(); } // deduce default from service element and factory attribute presence return m_service == null && m_factory == null; } /** * Returns the name of the implementation class * * @return the name of the implementation class */ public String getImplementationClassName() { return m_implementationClassName; } /** * Returns the configuration Policy * * @return the configuration policy * @since 1.2.0 (DS 1.1) */ public String getConfigurationPolicy() { return m_configurationPolicy; } /** * Returns the name of the activate method * * @return the name of the activate method * @since 1.2.0 (DS 1.1) */ public String getActivate() { return m_activate; } /** * Returns whether the activate method has been declared in the descriptor * or not. * * @return whether the activate method has been declared in the descriptor * or not. * @since 1.2.0 (DS 1.1) */ public boolean isActivateDeclared() { return m_activateDeclared; } /** * Returns the number of constructor parameters (0 is default) * @return The number of constructor parameters * @since 2.1.0 (DS 1.4) */ public int getNumberOfConstructorParameters() { // validate() ensures this is a valid integer return m_init == null ? 0 : Integer.valueOf(m_init); } /** * Returns the names of the activation fields * * @return the list of activation fields or {@code null} * @since 2.1.0 (DS 1.4) */ public List getActivationFields() { return m_activationFields; } /** * Returns the name of the deactivate method * * @return the name of the deactivate method * @since 1.2.0 (DS 1.1) */ public String getDeactivate() { return m_deactivate; } /** * Returns whether the deactivate method has been declared in the descriptor * or not. * * @return whether the deactivate method has been declared in the descriptor * or not. * @since 1.2.0 (DS 1.1) */ public boolean isDeactivateDeclared() { return m_deactivateDeclared; } /** * Returns the name of the modified method * * @return the name of the modified method * @since 1.2.0 (DS 1.1) */ public String getModified() { return m_modified; } /** * Returns the associated ServiceMetadata * * @return a ServiceMetadata object or null if the Component does not provide any service */ public ServiceMetadata getServiceMetadata() { return m_service; } public Scope getServiceScope() { if (m_service == null) { return Scope.singleton; } return m_service.getScope(); } /** * Returns the properties. * * @return the properties as a Dictionary */ public Map getProperties() { return m_properties; } /** * Returns the factory properties. * * @return the factory properties as a Dictionary */ public Map getFactoryProperties() { return m_factoryProperties; } /** * Returns the list of property meta data. * Note: This method is intended for unit testing only * * @return the list of property meta data. */ List getPropertyMetaData() { return m_propertyMetaData; } /** * Returns the list of factory property meta data. * Note: This method is intended for unit testing only * * @return the list of property meta data. */ List getFactoryPropertyMetaData() { return m_factoryPropertyMetaData; } /** * Returns the dependency descriptors * * @return a Collection of dependency descriptors */ public List getDependencies() { return m_references; } /** * Test to see if this service is a factory * * @return true if it is a factory, false otherwise */ public boolean isFactory() { return m_factory != null; } /** * Returns true if the configuration policy is configured to * {@link #CONFIGURATION_POLICY_REQUIRE}. */ public boolean isConfigurationRequired() { return CONFIGURATION_POLICY_REQUIRE.equals( m_configurationPolicy ); } /** * Returns true if the configuration policy is configured to * {@link #CONFIGURATION_POLICY_IGNORE}. */ public boolean isConfigurationIgnored() { return CONFIGURATION_POLICY_IGNORE.equals( m_configurationPolicy ); } /** * Returns true if the configuration policy is configured to * {@link #CONFIGURATION_POLICY_OPTIONAL}. */ public boolean isConfigurationOptional() { return CONFIGURATION_POLICY_OPTIONAL.equals( m_configurationPolicy ); } public boolean isConfigurableServiceProperties() { return m_configurableServiceProperties; } public boolean isPersistentFactoryComponent() { return m_persistentFactoryComponent; } public boolean isDeleteCallsModify() { return m_deleteCallsModify; } public boolean isObsoleteFactoryComponentFactory() { return m_obsoleteFactoryComponentFactory == null ? false : m_obsoleteFactoryComponentFactory; } public boolean isConfigureWithInterfaces() { return m_configureWithInterfaces; } public boolean isDelayedKeepInstances() { return m_delayedKeepInstances; } /** * Method used to verify if the semantics of this metadata are correct */ public void validate( ) { // nothing to do if already validated if ( m_validated ) { return; } // 112.10 The name of the component is required if ( m_name == null ) { // 112.4.3 name is optional defaulting to implementation class name since DS 1.1 if ( !m_dsVersion.isDS11() ) { throw new ComponentException( "The component name has not been set" ); } setName( getImplementationClassName() ); } // 112.10 There must be one implementation element and the class atribute is required if ( m_implementationClassName == null ) { throw validationFailure( "Implementation class name missing" ); } else if ( m_implementationClassName == IMPLEMENTATION_CLASS_DUPLICATE ) { throw validationFailure( "Implementation element must occur exactly once" ); } // 112.4.3 configuration-policy (since DS 1.1) if ( m_configurationPolicy == null ) { // default if not specified or pre DS 1.1 m_configurationPolicy = CONFIGURATION_POLICY_OPTIONAL; } else if ( !m_dsVersion.isDS11() ) { throw validationFailure( "configuration-policy declaration requires DS 1.1 or later namespace " ); } else if ( !CONFIGURATION_POLICY_VALID.contains( m_configurationPolicy ) ) { throw validationFailure( "configuration-policy must be one of " + CONFIGURATION_POLICY_VALID ); } // 112.5.8 activate can be specified (since DS 1.1) if ( m_activate == null ) { // default if not specified or pre DS 1.1 m_activate = "activate"; } else if ( !m_dsVersion.isDS11() ) { throw validationFailure( "activate method declaration requires DS 1.1 or later namespace " ); } // 112.5.12 deactivate can be specified (since DS 1.1) if ( m_deactivate == null ) { // default if not specified or pre DS 1.1 m_deactivate = "deactivate"; } else if ( !m_dsVersion.isDS11() ) { throw validationFailure( "deactivate method declaration requires DS 1.1 or later namespace " ); } // 112.??.?? modified can be specified (since DS 1.1) if ( m_modified != null && !m_dsVersion.isDS11() ) { throw validationFailure( "modified method declaration requires DS 1.1 or later namespace " ); } // 112.4.4 configuration-pid can be specified since DS 1.2 if ( m_configurationPid == null ) { m_configurationPid = Collections.singletonList( getName() ); } else { if ( !m_dsVersion.isDS12() ) { throw validationFailure( "configuration-pid attribute requires DS 1.2 or later namespace " ); } if (m_configurationPid.isEmpty()) { throw validationFailure( "configuration-pid nust not be empty string " ); } if (m_configurationPid.size() > 1 && !m_dsVersion.isDS13()) { throw validationFailure( "multiple configuration-pid requires DS 1.3 or later namespace " ); } for (int i = 0; i < m_configurationPid.size(); i++) { if ("$".equals( m_configurationPid.get(i))) { if (!m_dsVersion.isDS13()) { throw validationFailure( "Use of '$' configuration-pid wildcard requires DS 1.3 or later namespace " ); } m_configurationPid.set( i, getName() ); } } if ( new HashSet<>( m_configurationPid ).size() != m_configurationPid.size()) { throw validationFailure( "Duplicate pids not allowed: " + m_configurationPid ); } } // Next check if the properties are valid (and extract property values) for ( PropertyMetadata propMeta: m_propertyMetaData ) { propMeta.validate( this ); m_properties.put( propMeta.getName(), propMeta.getValue() ); } m_propertyMetaData.clear(); // Next check if the factory properties are valid (and extract property values) if ( !m_dsVersion.isDS14() && !m_factoryPropertyMetaData.isEmpty() ) { throw validationFailure( "Use of factory properties requires DS 1.4 or later namespace " ); } if ( m_dsVersion.isDS14() && isFactory() ) { for ( PropertyMetadata propMeta: m_factoryPropertyMetaData ) { propMeta.validate( this ); m_factoryProperties.put( propMeta.getName(), propMeta.getValue() ); } } // if this is not a factory, these props are ignored, so nothing else to do m_factoryPropertyMetaData.clear(); // Check that the provided services are valid too if ( m_service == SERVICE_DUPLICATE ) { throw validationFailure( "Service element must occur at most once" ); } else if ( m_service != null ) { m_service.validate( this ); } // Check that the references are ok Set refs = new HashSet<>(); for ( ReferenceMetadata refMeta: m_references ) { refMeta.validate( this ); // flag duplicates if ( !refs.add( refMeta.getName() ) ) { throw validationFailure( "Detected duplicate reference name: ''" + refMeta.getName() + "''" ); } } // verify value of immediate attribute if set if ( m_immediate != null ) { if ( isImmediate() ) { // FELIX-593: 112.4.3 clarification, immediate is false for factory if ( isFactory() ) { throw validationFailure( "Factory cannot be immediate" ); } } else { // 112.2.3 A delayed component specifies a service, is not specified to be a factory component // and does not have the immediate attribute of the component element set to true. // FELIX-593: 112.4.3 clarification, immediate may be true for factory if ( m_service == null && !isFactory() ) { throw validationFailure( "Delayed must provide a service or be a factory" ); } } } // 112.4.6 The serviceFactory attribute (of a provided service) must not be true if // the component is a factory component or an immediate component if ( m_service != null ) { if ( (m_service.getScope() != ServiceMetadata.Scope.singleton) && ( isFactory() || isImmediate() ) ) { throw validationFailure( "factory or immediate must be scope singleton not " + m_service.getScope()); } } // activation fields require DS 1.4 if ( m_activationFields != null && !m_dsVersion.isDS14() ) { throw validationFailure( "Activation fields require version 1.4 or later"); } // constructor injection requires DS 1.4 if ( this.m_init != null ) { if ( !m_dsVersion.isDS14() ) { throw validationFailure( "Constructor injection requires version 1.4 or later"); } int constructorParameters = 0; try { constructorParameters = Integer.valueOf(m_init); if ( constructorParameters < 0) { throw validationFailure( "Init parameter must have non negative value: " + m_init); } } catch ( final NumberFormatException nfe) { throw validationFailure( "Init parameter is not a number: " + m_init); } } if (m_dsVersion == DSVersion.DS12Felix) { m_configurableServiceProperties = true; } if ( m_configurableServiceProperties && getServiceScope() != Scope.singleton ) { throw validationFailure( "configurable service properties only allowed with singleton scope" ); } if (m_dsVersion.isDS13()) { m_deleteCallsModify = true; //spec behavior as of 1.3 } if ( !m_dsVersion.isDS13() && m_configureWithInterfaces) { throw validationFailure("Configuration with interfaces or annotations only possible with version 1.3 or later"); } if (m_dsVersion.isDS13() && m_obsoleteFactoryComponentFactory != null) { throw validationFailure("Configuration of component factory instances through config admin factory pids supported only through the 1.2 namespace"); } if (m_persistentFactoryComponent && !isFactory()) { throw validationFailure("Only a factory component can be a persistent factory component"); } m_validated = true; } /** * Returns a ComponentException for this component with the * given explanation for failure. * * @param reason The explanation for failing to validate this component. */ ComponentException validationFailure( String reason ) { return new ComponentException( "Component " + getName() + " validation failed: " + reason ); } public void collectStrings(Set strings) { addString(m_dsVersion.toString(), strings); addString(m_activate, strings); if (m_activationFields != null) { for (String s : m_activationFields) { addString(s, strings); } } if (m_configurationPid != null) { for (String s : m_configurationPid) { addString(s, strings); } } addString(m_configurationPolicy, strings); addString(m_deactivate, strings); addString(m_factory, strings); addString(m_implementationClassName, strings); addString(m_init, strings); addString(m_modified, strings); addString(m_name, strings); for (Entry entry : m_factoryProperties.entrySet()) { collectStrings(entry, strings); } for (Entry entry : m_properties.entrySet()) { collectStrings(entry, strings); } for (ReferenceMetadata rMeta : m_references) { rMeta.collectStrings(strings); } if (m_service != null) { m_service.collectStrings(strings); } } private void collectStrings(Entry entry, Set strings) { addString(entry.getKey(), strings); Object v = entry.getValue(); if (v instanceof String) { addString((String) v, strings); } else if (v instanceof String[]) { for (String s : (String[]) v) { addString(s, strings); } } } public void store(DataOutputStream out, MetaDataWriter metaDataWriter) throws IOException { metaDataWriter.writeString(m_dsVersion.toString(), out); metaDataWriter.writeString(m_activate, out); out.writeBoolean(m_activationFields != null); if (m_activationFields != null) { out.writeInt(m_activationFields.size()); for (String s : m_activationFields) { metaDataWriter.writeString(s, out); } } out.writeBoolean(m_configurationPid != null); if (m_configurationPid != null) { out.writeInt(m_configurationPid.size()); for (String s : m_configurationPid) { metaDataWriter.writeString(s, out); } } metaDataWriter.writeString(m_configurationPolicy, out); metaDataWriter.writeString(m_deactivate, out); metaDataWriter.writeString(m_factory, out); metaDataWriter.writeString(m_implementationClassName, out); metaDataWriter.writeString(m_init, out); metaDataWriter.writeString(m_modified, out); metaDataWriter.writeString(m_name, out); out.writeInt(m_factoryProperties.size()); for (Entry prop : m_factoryProperties.entrySet()) { metaDataWriter.writeString(prop.getKey(), out); storePropertyValue(prop.getValue(), out, metaDataWriter); } out.writeInt(m_properties.size()); for (Entry prop : m_properties.entrySet()) { metaDataWriter.writeString(prop.getKey(), out); storePropertyValue(prop.getValue(), out, metaDataWriter); } out.writeInt(m_references.size()); for (ReferenceMetadata rMeta : m_references) { rMeta.store(out, metaDataWriter); } out.writeBoolean(m_service != null); if (m_service != null) { m_service.store(out, metaDataWriter); } out.writeBoolean(m_activateDeclared); out.writeBoolean(m_configurableServiceProperties); out.writeBoolean(m_configureWithInterfaces); out.writeBoolean(m_deactivateDeclared); out.writeBoolean(m_delayedKeepInstances); out.writeBoolean(m_deleteCallsModify); out.writeBoolean(m_enabled); out.writeBoolean(m_immediate != null); if (m_immediate != null) { out.writeBoolean(m_immediate.booleanValue()); } } public static ComponentMetadata load(DataInputStream in, MetaDataReader metaDataReader) throws IOException { ComponentMetadata result = new ComponentMetadata( DSVersion.valueOf(metaDataReader.readString(in))); result.m_activate = metaDataReader.readString(in); if (in.readBoolean()) { int size = in.readInt(); String[] activationFields = new String[size]; for (int i = 0; i < size; i++) { activationFields[i] = metaDataReader.readString(in); } result.setActivationFields(activationFields); } if (in.readBoolean()) { int size = in.readInt(); String[] configPids = new String[size]; for (int i = 0; i < size; i++) { configPids[i] = metaDataReader.readString(in); } result.setConfigurationPid(configPids); } result.m_configurationPolicy = metaDataReader.readString(in); result.m_deactivate = metaDataReader.readString(in); result.m_factory = metaDataReader.readString(in); result.m_implementationClassName = metaDataReader.readString(in); result.m_init = metaDataReader.readString(in); result.m_modified = metaDataReader.readString(in); result.m_name = metaDataReader.readString(in); int numFProps = in.readInt(); for (int i = 0; i < numFProps; i++) { result.m_factoryProperties.put(metaDataReader.readString(in), loadPropertyValue(in, metaDataReader)); } int numProps = in.readInt(); for (int i = 0; i < numProps; i++) { result.m_properties.put(metaDataReader.readString(in), loadPropertyValue(in, metaDataReader)); } int numRefs = in.readInt(); for (int i = 0; i < numRefs; i++) { result.addDependency(ReferenceMetadata.load(in, metaDataReader)); } if (in.readBoolean()) { result.m_service = ServiceMetadata.load(in, metaDataReader); } result.m_activateDeclared = in.readBoolean(); result.m_configurableServiceProperties = in.readBoolean(); result.m_configureWithInterfaces = in.readBoolean(); result.m_deactivateDeclared = in.readBoolean(); result.m_delayedKeepInstances = in.readBoolean(); result.m_deleteCallsModify = in.readBoolean(); result.m_enabled = in.readBoolean(); if (in.readBoolean()) { result.m_immediate = in.readBoolean(); } // we only store valid metadata result.m_validated = true; return result; } private static final byte TypeString = 1; private static final byte TypeLong = 2; private static final byte TypeDouble = 3; private static final byte TypeFloat = 4; private static final byte TypeInteger = 5; private static final byte TypeByte = 6; private static final byte TypeChar = 7; private static final byte TypeBoolean = 8; private static final byte TypeShort = 9; static Object loadPropertyValue(DataInputStream in, MetaDataReader metaDataReader) throws IOException { boolean isArray = in.readBoolean(); byte valueType = in.readByte(); switch (valueType) { case TypeBoolean: if (isArray) { boolean[] vArray = new boolean[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readBoolean(); } return vArray; } else { return Boolean.valueOf(in.readBoolean()); } case TypeByte: if (isArray) { byte[] vArray = new byte[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readByte(); } return vArray; } else { return Byte.valueOf(in.readByte()); } case TypeChar: if (isArray) { char[] vArray = new char[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readChar(); } return vArray; } else { return Character.valueOf(in.readChar()); } case TypeDouble: if (isArray) { double[] vArray = new double[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readDouble(); } return vArray; } else { return Double.valueOf(in.readDouble()); } case TypeFloat: if (isArray) { float[] vArray = new float[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readFloat(); } return vArray; } else { return Float.valueOf(in.readFloat()); } case TypeInteger: if (isArray) { int[] vArray = new int[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readInt(); } return vArray; } else { return Integer.valueOf(in.readInt()); } case TypeLong: if (isArray) { long[] vArray = new long[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readLong(); } return vArray; } else { return Long.valueOf(in.readLong()); } case TypeShort: if (isArray) { short[] vArray = new short[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = in.readShort(); } return vArray; } else { return Short.valueOf(in.readShort()); } case TypeString: if (isArray) { String[] vArray = new String[in.readInt()]; for (int i = 0; i < vArray.length; i++) { vArray[i] = metaDataReader.readString(in); } return vArray; } else { return metaDataReader.readString(in); } } return null; } void storePropertyValue(Object value, DataOutputStream out, MetaDataWriter metaDataWriter) throws IOException { if (value == null) { // handle null value as a string out.writeBoolean(false); out.writeByte(TypeString); metaDataWriter.writeString(null, out); return; } Class arrayType = value.getClass().getComponentType(); boolean isArray = arrayType != null; out.writeBoolean(isArray); byte valueType = getType(arrayType == null ? value.getClass() : arrayType); out.writeByte(valueType); switch (valueType) { case TypeBoolean: if (isArray) { boolean[] vArray = (boolean[]) value; out.writeInt(vArray.length); for (boolean v : vArray) { out.writeBoolean(v); } } else { out.writeBoolean((boolean) value); } break; case TypeByte: if (isArray) { byte[] vArray = (byte[]) value; out.writeInt(vArray.length); for (byte v : vArray) { out.writeByte(v); } } else { out.writeByte((byte) value); } break; case TypeChar: if (isArray) { char[] vArray = (char[]) value; out.writeInt(vArray.length); for (char v : vArray) { out.writeChar(v); } } else { out.writeChar((char) value); } break; case TypeDouble: if (isArray) { double[] vArray = (double[]) value; out.writeInt(vArray.length); for (double v : vArray) { out.writeDouble(v); } } else { out.writeDouble((double) value); } break; case TypeFloat: if (isArray) { float[] vArray = (float[]) value; out.writeInt(vArray.length); for (float v : vArray) { out.writeFloat(v); } } else { out.writeFloat((float) value); } break; case TypeInteger: if (isArray) { int[] vArray = (int[]) value; out.writeInt(vArray.length); for (int v : vArray) { out.writeInt(v); } } else { out.writeInt((int) value); } break; case TypeLong: if (isArray) { long[] vArray = (long[]) value; out.writeInt(vArray.length); for (long v : vArray) { out.writeLong(v); } } else { out.writeLong((long) value); } break; case TypeShort: if (isArray) { short[] vArray = (short[]) value; out.writeInt(vArray.length); for (short v : vArray) { out.writeShort(v); } } else { out.writeShort((short) value); } break; case TypeString: if (isArray) { String[] vArray = (String[]) value; out.writeInt(vArray.length); for (String v : vArray) { metaDataWriter.writeString(v, out); } } else { metaDataWriter.writeString((String) value, out); } break; } } private byte getType(Class typeClass) { if (Boolean.class.equals(typeClass) || boolean.class.equals(typeClass)) { return TypeBoolean; } if (Byte.class.equals(typeClass) || byte.class.equals(typeClass)) { return TypeByte; } if (Character.class.equals(typeClass) || char.class.equals(typeClass)) { return TypeChar; } if (Double.class.equals(typeClass) || double.class.equals(typeClass)) { return TypeDouble; } if (Float.class.equals(typeClass) || float.class.equals(typeClass)) { return TypeFloat; } if (Integer.class.equals(typeClass) || int.class.equals(typeClass)) { return TypeInteger; } if (Long.class.equals(typeClass) || long.class.equals(typeClass)) { return TypeLong; } if (Short.class.equals(typeClass) || short.class.equals(typeClass)) { return TypeShort; } if (String.class.equals(typeClass)) { return TypeString; } throw new IllegalArgumentException("Unsupported type: " + typeClass); } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/DSVersion.java0000644000175000017500000000273413675426212026342 0ustar sudipsudip/* * 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.metadata; public enum DSVersion { DSnone(-1), DS10(0), DS11(1), DS11Felix(2), DS12(3), DS12Felix(4), DS13(5), DS14(6); private final int version; DSVersion(int version) { this.version = version; } public boolean isDS10() { return version >=DS10.version; } public boolean isDS11() { return version >=DS11.version; } public boolean isDS12() { return version >=DS12.version; } public boolean isDS13() { return version >=DS13.version; } public boolean isDS14() { return version >=DS14.version; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/TargetedPID.java0000644000175000017500000001665113675426212026565 0ustar sudipsudip/* * 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.metadata; import org.osgi.framework.Bundle; import org.osgi.framework.Version; /** * Copied with modifications from felix configadmin. * * The TargetedPID class represents a targeted PID as read * from a configuration object. *

* For a factory configuration the TargetedPID 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: *

    *
  • 0 -- this PID is not targeted at all
  • *
  • 1 -- this PID is targeted by the symbolic name
  • *
  • 2 -- this PID is targeted by the symbolic name and version
  • *
  • 3 -- this PID is targeted by the symbolic name, version, and location
  • *
*/ 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 Version.emptyVersion is * returned. * * @param bundle The bundle whose version is to be returned. */ public static String getBundleVersion( final Bundle bundle ) { Version version = bundle.getVersion(); 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. *

* This method just checks the target not the PID value itself, so * this method returning true does not indicate whether * the service actually is registered with a service PID equal to the * raw PID of this targeted PID. *

* This method also returns false if the service has * concurrently been unregistered and the registering bundle is now * null. * * @param serviceBundle Bundle to the registered * service * @return true if the referenced service matches the * target of this PID. */ public boolean matchesTarget( Bundle serviceBundle ) { // already unregistered 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. *

* 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 true if this targeted PID binds stronger than * the other {@link TargetedPID}. *

* 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 true if the other 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; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/metadata/ServiceMetadata.java0000644000175000017500000001347713675426212027535 0ustar sudipsudip/* * 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.metadata; import static org.apache.felix.scr.impl.metadata.MetadataStoreHelper.addString; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataReader; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataWriter; /** * This class contains the metadata associated to a service that is provided * by a component * */ public class ServiceMetadata { public enum Scope { singleton, bundle, prototype} // 112.4.6 Flag that indicates if the service is a ServiceFactory private Boolean m_serviceFactory; private String m_scopeName; private Scope m_scope = Scope.singleton; // List of provided interfaces private List m_provides = new ArrayList(); // Flag that indicates if this metadata has been validated and has become immutable private boolean m_validated = false; /** * Setter for the servicefactory attribute of the service element * * @param serviceFactory */ public void setServiceFactory(boolean serviceFactory) { if (m_validated) { return; } m_serviceFactory = serviceFactory; } public void setScope(String scopeName) { if(m_validated) { return; } this.m_scopeName = scopeName; } public Scope getScope() { return m_scope; } /** * Add a provided interface to this service * * @param provide a String containing the name of the provided interface */ public void addProvide(String provide) { if(m_validated) { return; } m_provides.add(provide); } /** * Returns the implemented interfaces * * @return the implemented interfaces as a string array */ public String [] getProvides() { return m_provides.toArray( new String[m_provides.size()] ); } /** * Verify if the semantics of this metadata are correct * */ void validate( ComponentMetadata componentMetadata ) { if ( m_provides.size() == 0 ) { throw componentMetadata .validationFailure( "At least one provided interface must be declared in the service element" ); } for ( String provide: m_provides ) { if ( provide == null ) { throw componentMetadata .validationFailure( "Null provides. Possibly service is not specified as value of attribute 'interface'" ); } } if (m_serviceFactory != null) { if ( componentMetadata.getDSVersion().isDS13() ) { throw componentMetadata.validationFailure("service-factory can only be specified in version 1.2 and earlier"); } m_scope = m_serviceFactory? Scope.bundle: Scope.singleton; } if ( m_scopeName != null ) { if ( !componentMetadata.getDSVersion().isDS13() ) { throw componentMetadata.validationFailure("service scope can only be specified in version 1.3 and later"); } try { m_scope = Scope.valueOf(m_scopeName); } catch (IllegalArgumentException e) { throw componentMetadata.validationFailure("Service scope may be only 'singleton' 'bundle' or 'prototype' not " + m_scopeName); } } m_validated = true; } void collectStrings(Set strings) { for (String s : m_provides) { addString(s, strings); } addString(m_scopeName, strings); addString(m_scope.toString(), strings); } void store(DataOutputStream out, MetaDataWriter metaDataWriter) throws IOException { out.writeInt(m_provides.size()); for (String s : m_provides) { metaDataWriter.writeString(s, out); } metaDataWriter.writeString(m_scopeName, out); metaDataWriter.writeString(m_scope.toString(), out); out.writeBoolean(m_serviceFactory != null); if (m_serviceFactory != null) { out.writeBoolean(m_serviceFactory.booleanValue()); } } static ServiceMetadata load(DataInputStream in, MetaDataReader metaDataReader) throws IOException { ServiceMetadata result = new ServiceMetadata(); int providerSize = in.readInt(); for (int i = 0; i < providerSize; i++) { result.addProvide(metaDataReader.readString(in)); } result.m_scopeName = metaDataReader.readString(in); result.m_scope = Scope.valueOf(metaDataReader.readString(in)); if (in.readBoolean()) { result.m_serviceFactory = in.readBoolean(); } // only stored valid metadata result.m_validated = true; return result; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java0000644000175000017500000007042313675426212027657 0ustar sudipsudip/* * 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 java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.felix.scr.impl.helper.ConfigAdminTracker; import org.apache.felix.scr.impl.logger.BundleLogger; import org.apache.felix.scr.impl.logger.ComponentLogger; import org.apache.felix.scr.impl.logger.ScrLogger; import org.apache.felix.scr.impl.manager.AbstractComponentManager; import org.apache.felix.scr.impl.manager.ComponentActivator; import org.apache.felix.scr.impl.manager.ComponentHolder; import org.apache.felix.scr.impl.manager.DependencyManager; import org.apache.felix.scr.impl.manager.ExtendedServiceEvent; import org.apache.felix.scr.impl.manager.ExtendedServiceListener; import org.apache.felix.scr.impl.manager.RegionConfigurationSupport; import org.apache.felix.scr.impl.manager.ScrConfiguration; import org.apache.felix.scr.impl.metadata.ComponentMetadata; import org.apache.felix.scr.impl.xml.XmlHandler; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentException; import org.osgi.service.log.LogService; /** * The BundleComponentActivator is helper class to load and unload Components of * a single bundle. It will read information from the metadata.xml file * descriptors and create the corresponding managers. */ public class BundleComponentActivator implements ComponentActivator { // global component registration private final ComponentRegistry m_componentRegistry; // The bundle owning the registered component private final Bundle m_bundle; // The bundle context owning the registered component private final BundleContext m_context; // This is a list of component holders that belong to a particular bundle private final List> m_holders = new ArrayList<>(); // thread acting upon configurations private final ComponentActorThread m_componentActor; // true as long as the dispose method is not called private final AtomicBoolean m_active = new AtomicBoolean( true ); private final CountDownLatch m_closeLatch = new CountDownLatch( 1 ); // the configuration private final ScrConfiguration m_configuration; private final ConfigAdminTracker configAdminTracker; private final Map listenerMap = new HashMap<>(); private final BundleLogger logger; private static class ListenerInfo implements ServiceListener { private Map>> filterMap = new HashMap<>(); @Override public void serviceChanged(ServiceEvent event) { ServiceReference ref = event.getServiceReference(); ExtendedServiceEvent extEvent = null; ExtendedServiceEvent endMatchEvent = null; Map>> filterMap; synchronized ( this ) { filterMap = this.filterMap; } for ( Map.Entry>> entry : filterMap.entrySet() ) { Filter filter = entry.getKey(); if ( filter == null || filter.match( ref ) ) { if ( extEvent == null ) { extEvent = new ExtendedServiceEvent( event ); } for ( ExtendedServiceListener forwardTo : entry.getValue() ) { forwardTo.serviceChanged( extEvent ); } } else if ( event.getType() == ServiceEvent.MODIFIED ) { if ( endMatchEvent == null ) { endMatchEvent = new ExtendedServiceEvent( ServiceEvent.MODIFIED_ENDMATCH, ref ); } for ( ExtendedServiceListener forwardTo : entry.getValue() ) { forwardTo.serviceChanged( endMatchEvent ); } } } if ( extEvent != null ) { extEvent.activateManagers(); } if ( endMatchEvent != null ) { endMatchEvent.activateManagers(); } } public synchronized void add(Filter filter, ExtendedServiceListener listener) { filterMap = new HashMap<>( filterMap ); List> listeners = filterMap.get( filter ); if ( listeners == null ) { listeners = Collections.> singletonList( listener ); } else { listeners = new ArrayList<>( listeners ); listeners.add( listener ); } filterMap.put( filter, listeners ); } public synchronized boolean remove(Filter filter, ExtendedServiceListener listener) { List> listeners = filterMap.get( filter ); if ( listeners != null ) { filterMap = new HashMap<>( filterMap ); listeners = new ArrayList<>( listeners ); listeners.remove( listener ); if ( listeners.isEmpty() ) { filterMap.remove( filter ); } else { filterMap.put( filter, listeners ); } } return filterMap.isEmpty(); } } @Override public void addServiceListener(String classNameFilter, Filter eventFilter, ExtendedServiceListener listener) { ListenerInfo listenerInfo; synchronized ( listenerMap ) { logger.log( LogService.LOG_DEBUG, "classNameFilter: " + classNameFilter + " event filter: " + eventFilter, null); listenerInfo = listenerMap.get( classNameFilter ); if ( listenerInfo == null ) { listenerInfo = new ListenerInfo(); listenerMap.put( classNameFilter, listenerInfo ); try { m_context.addServiceListener( listenerInfo, classNameFilter ); } catch ( InvalidSyntaxException e ) { throw (IllegalArgumentException) new IllegalArgumentException( "invalid class name filter" ).initCause( e ); } } } listenerInfo.add( eventFilter, listener ); } @Override public void removeServiceListener(String className, Filter filter, ExtendedServiceListener listener) { synchronized ( listenerMap ) { ListenerInfo listenerInfo = listenerMap.get( className ); if ( listenerInfo != null ) { if ( listenerInfo.remove( filter, listener ) ) { listenerMap.remove( className ); m_context.removeServiceListener( listenerInfo ); } } } } /** * Called upon starting of the bundle. This method invokes initialize() which * parses the metadata and creates the holders * * @param componentRegistry The ComponentRegistry used to * register components with to ensure uniqueness of component names * and to ensure configuration updates. * @param context The bundle context owning the components * * @throws ComponentException if any error occurrs initializing this class */ public BundleComponentActivator(final ScrLogger scrLogger, final ComponentRegistry componentRegistry, final ComponentActorThread componentActor, final BundleContext context, final ScrConfiguration configuration, final List cachedComponentMetadata) throws ComponentException { // create a logger on behalf of the bundle this.logger = new BundleLogger(context, scrLogger); // keep the parameters for later m_componentRegistry = componentRegistry; m_componentActor = componentActor; m_context = context; m_bundle = context.getBundle(); m_configuration = configuration; logger.log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle active", null); initialize(cachedComponentMetadata); ConfigAdminTracker tracker = null; for ( ComponentHolder holder : m_holders ) { if ( !holder.getComponentMetadata().isConfigurationIgnored() ) { tracker = new ConfigAdminTracker( this ); break; } } configAdminTracker = tracker; } /** * Gets the MetaData location, parses the meta data and requests the processing * of binder instances * @param cachedComponentMetadata * * @throws IllegalStateException If the bundle has already been uninstalled. */ protected void initialize(List cachedComponentMetadata) { if (cachedComponentMetadata != null) { for (ComponentMetadata metadata : cachedComponentMetadata) { validateAndRegister(metadata); } } else { // Get the Metadata-Location value from the manifest String descriptorLocations = m_bundle.getHeaders("").get("Service-Component"); if (descriptorLocations == null) { throw new ComponentException( "Service-Component entry not found in the manifest"); } logger.log(LogService.LOG_DEBUG, "BundleComponentActivator : Descriptor locations {0}", null, descriptorLocations); // 112.4.1: The value of the the header is a comma separated list of XML entries within the Bundle StringTokenizer st = new StringTokenizer(descriptorLocations, ", "); while (st.hasMoreTokens()) { String descriptorLocation = st.nextToken(); URL[] descriptorURLs = findDescriptors(m_bundle, descriptorLocation); if (descriptorURLs.length == 0) { // 112.4.1 If an XML document specified by the header cannot be located in the bundle and its attached // fragments, SCR must log an error message with the Log Service, if present, and continue. logger.log(LogService.LOG_ERROR, "Component descriptor entry ''{0}'' not found", null, descriptorLocation); continue; } // load from the descriptors for (URL descriptorURL : descriptorURLs) { loadDescriptor(descriptorURL); } } } } /** * Called outside the constructor so that the m_managers field is completely initialized. * A component might possibly start a thread to enable other components, which could access m_managers */ void initialEnable() { //enable all the enabled components for ( ComponentHolder componentHolder : m_holders ) { logger.log( LogService.LOG_DEBUG, "BundleComponentActivator : May enable component holder {0}", null, componentHolder.getComponentMetadata().getName() ); if ( componentHolder.getComponentMetadata().isEnabled() ) { logger.log( LogService.LOG_DEBUG, "BundleComponentActivator :Enabling component holder {0}", null, componentHolder.getComponentMetadata().getName() ); try { componentHolder.enableComponents( false ); } catch ( Throwable t ) { // caught on unhandled RuntimeException or Error // (e.g. ClassDefNotFoundError) // make sure the component is properly disabled, just in case try { componentHolder.disableComponents( false ); } catch ( Throwable ignore ) { } logger.log( LogService.LOG_ERROR, "BundleComponentActivator : Unexpected failure enabling component holder {0}", t, componentHolder.getComponentMetadata().getName() ); } } else { logger.log( LogService.LOG_DEBUG, "BundleComponentActivator : Will not enable component holder {0}", null, componentHolder.getComponentMetadata().getName() ); } } } /** * Finds component descriptors based on descriptor location. * * @param bundle bundle to search for descriptor files * @param descriptorLocation descriptor location * @return array of descriptors or empty array if none found */ static URL[] findDescriptors(final Bundle bundle, final String descriptorLocation) { if ( bundle == null || descriptorLocation == null || descriptorLocation.trim().length() == 0 ) { return new URL[0]; } // split pattern and path final int lios = descriptorLocation.lastIndexOf( "/" ); final String path; final String filePattern; if ( lios > 0 ) { path = descriptorLocation.substring( 0, lios ); filePattern = descriptorLocation.substring( lios + 1 ); } else { path = "/"; filePattern = descriptorLocation; } // find the entries final Enumeration entries = bundle.findEntries( path, filePattern, false ); if ( entries == null || !entries.hasMoreElements() ) { return new URL[0]; } // create the result list List urls = new ArrayList<>(); while ( entries.hasMoreElements() ) { urls.add( entries.nextElement() ); } return urls.toArray( new URL[urls.size()] ); } private void loadDescriptor(final URL descriptorURL) { // simple path for log messages final String descriptorLocation = descriptorURL.getPath(); InputStream stream = null; try { stream = descriptorURL.openStream(); XmlHandler handler = new XmlHandler( m_bundle, this.logger, getConfiguration().isFactoryEnabled(), getConfiguration().keepInstances() ); final SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); final SAXParser parser = factory.newSAXParser(); parser.parse( stream, handler ); // 112.4.2 Component descriptors may contain a single, root component element // or one or more component elements embedded in a larger document for ( ComponentMetadata metadata : handler.getComponentMetadataList() ) { validateAndRegister(metadata); } } catch ( IOException ex ) { // 112.4.1 If an XML document specified by the header cannot be located in the bundle and its attached // fragments, SCR must log an error message with the Log Service, if present, and continue. logger.log( LogService.LOG_ERROR, "Problem reading descriptor entry ''{0}''", ex, descriptorLocation ); } catch ( Exception ex ) { logger.log( LogService.LOG_ERROR, "General problem with descriptor entry ''{0}''", ex, descriptorLocation ); } finally { if ( stream != null ) { try { stream.close(); } catch ( IOException ignore ) { } } } } void validateAndRegister(ComponentMetadata metadata) { final ComponentLogger componentLogger = new ComponentLogger(metadata, logger); ComponentRegistryKey key = null; try { // validate the component metadata metadata.validate(); // check and reserve the component name (validate ensures it's never null) key = m_componentRegistry.checkComponentName(m_bundle, metadata.getName()); // Request creation of the component manager ComponentHolder holder = m_componentRegistry.createComponentHolder(this, metadata, componentLogger); // register the component after validation m_componentRegistry.registerComponentHolder(key, holder); m_holders.add(holder); componentLogger.log(LogService.LOG_DEBUG, "BundleComponentActivator : ComponentHolder created.", null); } catch (Throwable t) { // There is a problem with this particular component, we'll log the error // and proceed to the next one componentLogger.log(LogService.LOG_ERROR, "Cannot register component", t); // make sure the name is not reserved any more if (key != null) { m_componentRegistry.unregisterComponentHolder(key); } } } /** * Dispose of this component activator instance and all the component * managers. */ void dispose(int reason) { if ( m_active.compareAndSet( true, false ) ) { logger.log( LogService.LOG_DEBUG, "BundleComponentActivator : Will destroy {0} instances", null, m_holders.size() ); for ( ComponentHolder holder : m_holders ) { try { holder.disposeComponents( reason ); } catch ( Exception e ) { logger.log( LogService.LOG_ERROR, "BundleComponentActivator : Exception invalidating", e, holder.getComponentMetadata() ); } finally { m_componentRegistry.unregisterComponentHolder( m_bundle, holder.getComponentMetadata().getName() ); } } if ( configAdminTracker != null ) { configAdminTracker.dispose(); } logger.log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle STOPPED", null ); logger.close(); m_closeLatch.countDown(); } else { try { m_closeLatch.await( m_configuration.lockTimeout(), TimeUnit.MILLISECONDS ); } catch ( InterruptedException e ) { //ignore interruption during concurrent shutdown. Thread.currentThread().interrupt(); } } } /** * Returns if this instance is active, that is if components * may be activated for this component. The active flag is set early * in the constructor indicating the activator is basically active * (not fully setup, though) and reset early in the process of * {@link #dispose(int) disposing} this instance. */ @Override public boolean isActive() { return m_active.get(); } /** * Returns the BundleContext * * @return the BundleContext */ @Override public BundleContext getBundleContext() { return m_context; } @Override public ScrConfiguration getConfiguration() { return m_configuration; } /** * Implements the ComponentContext.enableComponent(String) * method by first finding the component(s) for the name and * enabling them. The enable method will schedule activation. *

* * @param name The name of the component to enable or null to * enable all components. */ @Override public void enableComponent(final String name) { final List> holder = getSelectedComponents( name ); for ( ComponentHolder aHolder : holder ) { try { // TODO use component logger logger.log( LogService.LOG_DEBUG, "Enabling Component {0}", null, aHolder.getComponentMetadata().getName() ); aHolder.enableComponents( true ); } catch ( Throwable t ) { // TODO use component logger logger.log( LogService.LOG_ERROR, "Cannot enable component {0}", t, aHolder.getComponentMetadata().getName() ); } } } /** * Implements the ComponentContext.disableComponent(String) * method by first finding the component(s) for the name and * disabling them. The disable method will schedule deactivation *

* * @param name The name of the component to disable or null to * disable all components. */ @Override public void disableComponent(final String name) { final List> holder = getSelectedComponents( name ); for ( ComponentHolder aHolder : holder ) { try { // TODO use component logger logger.log( LogService.LOG_DEBUG, "Disabling Component {0}", null, aHolder.getComponentMetadata().getName() ); aHolder.disableComponents( true ); } catch ( Throwable t ) { // TODO use component logger logger.log( LogService.LOG_ERROR, "Cannot disable component {0}", t, aHolder.getComponentMetadata().getName() ); } } } /** * Returns an array of {@link ComponentHolder} instances which match the * name. If the name is null an * array of all currently known component managers is returned. Otherwise * an array containing a single component manager matching the name is * returned if one is registered. Finally, if no component manager with the * given name is registered, null is returned. * * @param name The name of the component manager to return or * null to return an array of all component managers. * * @return An array containing one or more component managers according * to the name parameter or null if no * component manager with the given name is currently registered. */ List> getSelectedComponents(String name) { // if all components are selected if ( name == null ) { return m_holders; } ComponentHolder componentHolder = m_componentRegistry.getComponentHolder( m_bundle, name ); if ( componentHolder != null ) { return Collections.> singletonList( componentHolder ); } // if the component is not known return Collections.emptyList(); } //---------- Component ID support @Override public long registerComponentId(AbstractComponentManager componentManager) { return m_componentRegistry.registerComponentId( componentManager ); } @Override public void unregisterComponentId(AbstractComponentManager componentManager) { m_componentRegistry.unregisterComponentId( componentManager.getId() ); } //---------- Asynchronous Component Handling ------------------------------ /** * Schedules the given task for asynchrounous execution or * synchronously runs the task if the thread is not running. If this instance * is {@link #isActive() not active}, the task is not executed. * * @param task The component task to execute */ @Override public void schedule(Runnable task) { if ( isActive() ) { ComponentActorThread cat = m_componentActor; if ( cat != null ) { cat.schedule( task ); } else { logger.log( LogService.LOG_DEBUG, "Component Actor Thread not running, calling synchronously", null ); try { synchronized ( this ) { task.run(); } } catch ( Throwable t ) { logger.log( LogService.LOG_WARNING, "Unexpected problem executing task", t ); } } } else { logger.log( LogService.LOG_WARNING, "BundleComponentActivator is not active; not scheduling {0}", null, task ); } } @Override public BundleLogger getLogger() { return logger; } @Override public boolean enterCreate(ServiceReference serviceReference) { return m_componentRegistry.enterCreate( serviceReference ); } @Override public void leaveCreate(ServiceReference serviceReference) { m_componentRegistry.leaveCreate( serviceReference ); } @Override public void missingServicePresent(ServiceReference serviceReference) { m_componentRegistry.missingServicePresent( serviceReference, m_componentActor ); } @Override public void registerMissingDependency(DependencyManager dependencyManager, ServiceReference serviceReference, int trackingCount) { m_componentRegistry.registerMissingDependency( dependencyManager, serviceReference, trackingCount ); } @Override public RegionConfigurationSupport setRegionConfigurationSupport(ServiceReference reference) { RegionConfigurationSupport rcs = m_componentRegistry.registerRegionConfigurationSupport( reference ); if (rcs != null) { for ( ComponentHolder holder : m_holders ) { rcs.configureComponentHolder( holder ); } } return rcs; } @Override public void unsetRegionConfigurationSupport(RegionConfigurationSupport rcs) { m_componentRegistry.unregisterRegionConfigurationSupport( rcs ); // TODO anything needed? } @Override public void updateChangeCount() { this.m_componentRegistry.updateChangeCount(); } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/config/0000755000175000017500000000000013675426212023302 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java0000644000175000017500000000344513675426212027500 0ustar sudipsudip/* * 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 ScrManagedService receives configuration for the Declarative * Services Runtime itself. *

* This class is instantiated in a ServiceFactory manner by the * {@link ScrManagedServiceServiceFactory} when the Configuration Admin service * implementation and API is available. *

* Requires OSGi Configuration Admin Service API available * * @see ScrManagedServiceServiceFactory */ public class ScrManagedService implements ManagedService { private final ScrConfigurationImpl scrConfiguration; public ScrManagedService(final ScrConfigurationImpl scrConfiguration) { this.scrConfiguration = scrConfiguration; } @Override public void updated(final Dictionary properties) throws ConfigurationException { this.scrConfiguration.configure(properties, true); } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java0000644000175000017500000000410413675426212032342 0ustar sudipsudip/* * 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.osgi.framework.Bundle; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; /** * The {@code ScrManagedServiceServiceFactory} is a {@code ServiceFactory} registered * on behalf of {@link ScrManagedService} to create a managed service instance * on demand once it is used by the Configuration Admin Service. *

* In contrast to the {@link ScrManagedService} class, this class only requires * core OSGi API and thus may be instantiated without the Configuration Admin * actually available at the time of instantiation. */ @SuppressWarnings("rawtypes") public class ScrManagedServiceServiceFactory implements ServiceFactory { private final ScrConfigurationImpl scrConfiguration; public ScrManagedServiceServiceFactory(final ScrConfigurationImpl scrConfiguration) { this.scrConfiguration = scrConfiguration; } @Override public Object getService(final Bundle bundle, final ServiceRegistration registration) { return new ScrManagedService( this.scrConfiguration ); } @Override public void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object service) { // nothing really to do; GC will do the rest } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/config/ScrMetaTypeProviderServiceFactory.javafelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/config/ScrMetaTypeProviderServiceFactory.ja0000644000175000017500000000417013675426212032404 0ustar sudipsudip/* * 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.manager.ScrConfiguration; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; /** * The {@code ScrMetaTypeProviderServiceFactory} is a {@code ServiceFactory} registered * on behalf of {@link ScrConfiguration} to create a metatype provider instance * on demand once it is used by the Metatype Service. *

* In contrast to the {@link ScrMetaTypeProvider} class, this class only requires * core OSGi API and thus may be instantiated without the MetaType Service API actually available * at the time of instantiation. */ @SuppressWarnings("rawtypes") public class ScrMetaTypeProviderServiceFactory implements ServiceFactory { private final ScrConfiguration scrConfiguration; public ScrMetaTypeProviderServiceFactory(final ScrConfiguration scrConfiguration) { this.scrConfiguration = scrConfiguration; } @Override public Object getService(final Bundle bundle, final ServiceRegistration registration) { return new ScrMetaTypeProvider( this.scrConfiguration ); } @Override public void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object service) { // nothing really to do; GC will do the rest } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/config/ScrMetaTypeProvider.java0000644000175000017500000002145713675426212030071 0ustar sudipsudip/* * 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.apache.felix.scr.impl.manager.ScrConfiguration; import org.osgi.service.metatype.AttributeDefinition; import org.osgi.service.metatype.MetaTypeProvider; import org.osgi.service.metatype.ObjectClassDefinition; /** * The ScrManagedServiceMetaTypeProvider receives the Declarative * Services Runtime configuration (by extending the {@link ScrManagedService} * class. *

* This class is instantiated in a ServiceFactory manner by the * {@link ScrManagedServiceServiceFactory} when the Configuration Admin service * implementation and API is available *

* Requires OSGi Metatype Service API available * * @see ScrManagedServiceServiceFactory */ class ScrMetaTypeProvider implements MetaTypeProvider { private final ScrConfiguration configuration; public ScrMetaTypeProvider(final ScrConfiguration scrConfiguration) { this.configuration = scrConfiguration; } /** * @see org.osgi.service.metatype.MetaTypeProvider#getLocales() */ @Override public String[] getLocales() { return null; } /** * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String, java.lang.String) */ @Override public ObjectClassDefinition getObjectClassDefinition( String id, String locale ) { if ( !ScrConfiguration.PID.equals( id ) ) { return null; } final ArrayList adList = new ArrayList<>(); 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. This property is not used" + " if a R7 LogService implementation is available as the log level can be configured" + " through that service. Default is ERROR.", AttributeDefinition.INTEGER, new String[] { String.valueOf(this.configuration.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 .configuration.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 .configuration.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.configuration.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.configuration.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()]); @Override public String getName() { return "Apache Felix Declarative Service Implementation"; } @Override public InputStream getIcon(int arg0) { return null; } @Override public String getID() { return ScrConfiguration.PID; } @Override public String getDescription() { return "Configuration for the Apache Felix Declarative Services Implementation." + " This configuration overwrites configuration defined in framework properties of the same names."; } @Override 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; } @Override public int getCardinality() { return cardinality; } @Override public String[] getDefaultValue() { return defaultValues; } @Override public String getDescription() { return description; } @Override public String getID() { return id; } @Override public String getName() { return name; } @Override public String[] getOptionLabels() { return optionLabels; } @Override public String[] getOptionValues() { return optionValues; } @Override public int getType() { return type; } @Override public String validate( String arg0 ) { return null; } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/config/ScrConfigurationImpl.java0000644000175000017500000003135513675426212030255 0ustar sudipsudip/* * 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.ComponentCommands; import org.apache.felix.scr.impl.manager.ScrConfiguration; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; import org.osgi.service.log.LogService; import org.osgi.service.metatype.MetaTypeProvider; /** * The ScrConfiguration class conveys configuration for the * Felix DS implementation bundle. *

* Configuration Source *

*

    *
  1. Framework properties: These are read when the Declarative Services * implementation is first started.
  2. *
  3. Configuration Admin Service: Properties are provided by means of a * ManagedService with Service PID * org.apache.felix.scr.ScrService. 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. *
  4. *
*

* See the Configuration section of the * Apache Felix Service Component Runtime * documentation page for detailed information. */ public class ScrConfigurationImpl implements ScrConfiguration { private static final String VALUE_TRUE = Boolean.TRUE.toString(); 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"; private final Activator activator; private int logLevel; private boolean factoryEnabled; private boolean keepInstances; private boolean infoAsService; private boolean cacheMetadata; private long lockTimeout = DEFAULT_LOCK_TIMEOUT_MILLISECONDS; private long stopTimeout = DEFAULT_STOP_TIMEOUT_MILLISECONDS; private long serviceChangecountTimeout = DEFAULT_SERVICE_CHANGECOUNT_TIMEOUT_MILLISECONDS; private Boolean globalExtender; private volatile BundleContext bundleContext; private volatile ServiceRegistration managedServiceRef; private volatile ServiceRegistration metatypeProviderRef; private ComponentCommands scrCommand; public ScrConfigurationImpl(Activator activator ) { this.activator = activator; } public void start(final BundleContext bundleContext) { this.bundleContext = bundleContext; // listen for Configuration Admin configuration final Dictionary msProps = new Hashtable<>(); msProps.put(Constants.SERVICE_PID, PID); msProps.put(Constants.SERVICE_DESCRIPTION, "SCR Configurator"); msProps.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 ); managedServiceRef = bundleContext.registerService("org.osgi.service.cm.ManagedService", new ScrManagedServiceServiceFactory(this), msProps); final Dictionary mtProps = new Hashtable<>(); mtProps.put(MetaTypeProvider.METATYPE_PID, PID); mtProps.put(Constants.SERVICE_DESCRIPTION, "SCR Configurator MetaTypeProvider"); mtProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); metatypeProviderRef = bundleContext.registerService("org.osgi.service.metatype.MetaTypeProvider", new ScrMetaTypeProviderServiceFactory(this), mtProps); } public void stop() { if (this.managedServiceRef != null) { this.managedServiceRef.unregister(); this.managedServiceRef = null; } if (this.metatypeProviderRef != null) { this.metatypeProviderRef.unregister(); this.metatypeProviderRef = null; } this.bundleContext = null; } public void setScrCommand(ComponentCommands scrCommand) { this.scrCommand = scrCommand; scrCommand.updateProvideScrInfoService(infoAsService()); } // Called from the ScrManagedService.updated method to reconfigure void configure( Dictionary 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; serviceChangecountTimeout = DEFAULT_SERVICE_CHANGECOUNT_TIMEOUT_MILLISECONDS; newGlobalExtender = false; cacheMetadata = false; } else { logLevel = getDefaultLogLevel(); factoryEnabled = getDefaultFactoryEnabled(); keepInstances = getDefaultKeepInstances(); infoAsService = getDefaultInfoAsService(); lockTimeout = getDefaultLockTimeout(); stopTimeout = getDefaultStopTimeout(); serviceChangecountTimeout = getServiceChangecountTimeout(); newGlobalExtender = getDefaultGlobalExtender(); cacheMetadata = getDefaultCacheMetadata(); } } 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) ) ); cacheMetadata = VALUE_TRUE.equalsIgnoreCase( String.valueOf(config.get(PROP_CACHE_METADATA))); } if ( scrCommand != null ) { scrCommand.updateProvideScrInfoService( infoAsService() ); } oldGlobalExtender = this.globalExtender; this.globalExtender = newGlobalExtender; } if ( newGlobalExtender != oldGlobalExtender ) { activator.restart( newGlobalExtender ); } } /** * Returns the current log level. * Note that this log level is not used with an R7 LogService implementation. * @return */ @Override public int getLogLevel() { return logLevel; } @Override public boolean isFactoryEnabled() { return factoryEnabled; } @Override public boolean keepInstances() { return keepInstances; } @Override public boolean infoAsService() { return infoAsService; } @Override public long lockTimeout() { return lockTimeout; } @Override public long stopTimeout() { return stopTimeout; } @Override public boolean globalExtender() { return globalExtender; } @Override public boolean cacheMetadata() { return cacheMetadata; } @Override public long serviceChangecountTimeout() { return serviceChangecountTimeout; } 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 long getServiceChangecountTimeout() { String val = bundleContext.getProperty( PROP_SERVICE_CHANGECOUNT_TIMEOUT ); if ( val == null) { return DEFAULT_SERVICE_CHANGECOUNT_TIMEOUT_MILLISECONDS; } return Long.parseLong( val ); } private boolean getDefaultGlobalExtender() { return VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty( PROP_GLOBAL_EXTENDER) ); } private boolean getDefaultCacheMetadata() { return VALUE_TRUE.equalsIgnoreCase( bundleContext.getProperty(PROP_CACHE_METADATA)); } 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; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java0000644000175000017500000002204413675426212026144 0ustar sudipsudip/* * Licensed 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 java.util.ArrayList; import java.util.Collection; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.Constants; import org.osgi.framework.SynchronousBundleListener; import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.util.tracker.BundleTracker; import org.osgi.util.tracker.BundleTrackerCustomizer; /** * Base class to write bundle extenders. * This extender tracks started bundles (or starting if they have a lazy activation * policy) and will create an extension for each of them to manage it. * * The extender will handle all concurrency and synchronization issues. * * The extender guarantee that all extensions will be stopped synchronously with * the STOPPING event of a given bundle and that all extensions will be stopped * before the extender bundle is stopped. * */ public abstract class AbstractExtender implements BundleActivator, BundleTrackerCustomizer, SynchronousBundleListener { private final ConcurrentMap extensions = new ConcurrentHashMap<>(); private final ConcurrentMap> destroying = new ConcurrentHashMap<>(); private volatile boolean stopping; private volatile boolean stopped; private BundleContext context; private BundleTracker tracker; public BundleContext getBundleContext() { return context; } public boolean isStopping() { return stopping; } @Override public void start(BundleContext context) throws Exception { this.context = context; this.context.addBundleListener(this); this.tracker = new BundleTracker<>(this.context, Bundle.ACTIVE | Bundle.STARTING, this); doStart(); } @Override public void stop(BundleContext context) throws Exception { stopping = true; while (!extensions.isEmpty()) { Collection toDestroy = chooseBundlesToDestroy(extensions.keySet()); if (toDestroy == null || toDestroy.isEmpty()) { toDestroy = new ArrayList<>(extensions.keySet()); } for (Bundle bundle : toDestroy) { destroyExtension(bundle); } } doStop(); stopped = true; } protected void doStart() throws Exception { startTracking(); } protected void doStop() throws Exception { stopTracking(); } protected void startTracking() { this.tracker.open(); } protected void stopTracking() { this.tracker.close(); } /** * Create the executor used to start extensions asynchronously. * * @return an */ protected ExecutorService createExecutor() { return Executors.newScheduledThreadPool(3); } protected Collection chooseBundlesToDestroy(Set bundles) { return null; } @Override public void bundleChanged(BundleEvent event) { if (stopped) { return; } Bundle bundle = event.getBundle(); if (bundle.getState() != Bundle.ACTIVE && bundle.getState() != Bundle.STARTING) { // The bundle is not in STARTING or ACTIVE state anymore // so destroy the context. Ignore our own bundle since it // needs to kick the orderly shutdown. if (bundle != this.context.getBundle()) { destroyExtension(bundle); } } } @Override public Bundle addingBundle(Bundle bundle, BundleEvent event) { modifiedBundle(bundle, event, bundle); return bundle; } @Override public void modifiedBundle(Bundle bundle, BundleEvent event, Bundle object) { if (bundle.getState() != Bundle.ACTIVE && bundle.getState() != Bundle.STARTING) { // The bundle is not in STARTING or ACTIVE state anymore // so destroy the context. Ignore our own bundle since it // needs to kick the orderly shutdown and not unregister the namespaces. if (bundle != this.context.getBundle()) { destroyExtension(bundle); } return; } // Do not track bundles given we are stopping if (stopping) { return; } // For starting bundles, ensure, it's a lazy activation, // else we'll wait for the bundle to become ACTIVE if (bundle.getState() == Bundle.STARTING) { String activationPolicyHeader = bundle.getHeaders("").get(Constants.BUNDLE_ACTIVATIONPOLICY); if (activationPolicyHeader == null || !activationPolicyHeader.startsWith(Constants.ACTIVATION_LAZY) || !bundle.adapt(BundleStartLevel.class).isActivationPolicyUsed()) { // Do not track this bundle yet return; } } createExtension(bundle); } @Override public void removedBundle(Bundle bundle, BundleEvent event, Bundle object) { // Nothing to do destroyExtension(bundle); } private void createExtension(final Bundle bundle) { try { BundleContext bundleContext = bundle.getBundleContext(); if (bundleContext == null) { // The bundle has been stopped in the mean time return; } final Activator.ScrExtension extension = doCreateExtension(bundle); if (extension == null) { // This bundle is not to be extended return; } synchronized (extensions) { if (extensions.putIfAbsent(bundle, extension) != null) { return; } } debug(bundle, "Starting extension synchronously"); extension.start(); } catch (Throwable t) { warn(bundle, "Error while creating extension", t); } } private void destroyExtension(final Bundle bundle) { FutureTask future; synchronized (extensions) { debug(bundle, "Starting destruction process"); future = destroying.get(bundle); if (future == null) { final Activator.ScrExtension extension = extensions.remove(bundle); if (extension != null) { debug(bundle, "Scheduling extension destruction"); future = new FutureTask<>(new Runnable() { @Override public void run() { debug(bundle, "Destroying extension"); try { extension.destroy(); } catch (Exception e) { warn(bundle, "Error while destroying extension", e); } finally { debug(bundle, "Finished destroying extension"); synchronized (extensions) { destroying.remove(bundle); } } } }, null); destroying.put(bundle, future); } else { debug(bundle, "Not an extended bundle or destruction of extension already finished"); } } else { debug(bundle, "Destruction already scheduled"); } } if (future != null) { try { debug(bundle, "Waiting for extension destruction"); future.run(); future.get(); } catch (Throwable t) { warn(bundle, "Error while destroying extension", t); } } } /** * Create the extension for the given bundle, or null if the bundle is not to be extended. * * @param bundle the bundle to extend * @return The extension * @throws Exception If something goes wrong */ protected abstract Activator.ScrExtension doCreateExtension(Bundle bundle) throws Exception; protected abstract void debug(Bundle bundle, String msg); protected abstract void warn(Bundle bundle, String msg, Throwable t); } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/ComponentActorThread.java0000644000175000017500000001212213675426212026761 0ustar sudipsudip/* * 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 java.util.LinkedList; import org.apache.felix.scr.impl.logger.ScrLogger; import org.osgi.service.log.LogService; /** * The ComponentActorThread is the thread used to act upon registered * components of the service component runtime. */ class ComponentActorThread implements Runnable { // sentinel task to terminate this thread private static final Runnable TERMINATION_TASK = new Runnable() { @Override public void run() { } @Override public String toString() { return "Component Actor Terminator"; } }; // the queue of Runnable instances to be run private final LinkedList tasks = new LinkedList<>(); private final ScrLogger logger; ComponentActorThread( final ScrLogger log ) { logger = log; } // waits on Runnable instances coming into the queue. As instances come // in, this method calls the Runnable.run method, logs any exception // happening and keeps on waiting for the next Runnable. If the Runnable // taken from the queue is this thread instance itself, the thread // terminates. @Override public void run() { logger.log( LogService.LOG_DEBUG, "Starting ComponentActorThread", null ); for ( ;; ) { final Runnable task; synchronized ( tasks ) { while ( tasks.isEmpty() ) { boolean interrupted = Thread.interrupted(); try { tasks.wait(); } catch ( InterruptedException ie ) { interrupted = true; // don't care } finally { if (interrupted) { // restore interrupt status Thread.currentThread().interrupt(); } } } task = tasks.removeFirst(); } try { // return if the task is this thread itself if ( task == TERMINATION_TASK ) { logger.log( LogService.LOG_DEBUG, "Shutting down ComponentActorThread", null ); return; } // otherwise execute the task, log any issues logger.log( LogService.LOG_DEBUG, "Running task: " + task, null ); task.run(); } catch ( Throwable t ) { logger.log( LogService.LOG_ERROR, "Unexpected problem executing task " + task, t ); } finally { synchronized ( tasks ) { tasks.notifyAll(); } } } } // cause this thread to terminate by adding this thread to the end // of the queue void terminate() { schedule( TERMINATION_TASK ); synchronized ( tasks ) { while ( !tasks.isEmpty() ) { boolean interrupted = Thread.interrupted(); try { tasks.wait(); } catch ( InterruptedException e ) { interrupted = true; logger.log(LogService.LOG_ERROR, "Interrupted exception waiting for queue to empty", e); } finally { if (interrupted) { // restore interrupt status Thread.currentThread().interrupt(); } } } } } // queue the given runnable to be run as soon as possible void schedule( Runnable task ) { synchronized ( tasks ) { // append to the task queue tasks.add( task ); logger.log( LogService.LOG_DEBUG, "Adding task [{0}] as #{1} in the queue", null, task, tasks.size()); // notify the waiting thread tasks.notifyAll(); } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/logger/0000755000175000017500000000000013675426212023314 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/logger/ScrLogger.java0000644000175000017500000000256513675426212026056 0ustar sudipsudip/* * 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.logger; import org.apache.felix.scr.impl.manager.ScrConfiguration; import org.osgi.framework.BundleContext; /** * This is the "global" logger used by the implementation for all logging * not directly related to an extended bundle (and its components) */ public class ScrLogger extends LogServiceEnabledLogger { public ScrLogger(final ScrConfiguration config, final BundleContext bundleContext) { super(config, bundleContext); } @Override InternalLogger getDefaultLogger() { return new StdOutLogger(); } }felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/logger/ComponentLogger.java0000644000175000017500000000675713675426212027300 0ustar sudipsudip/* * 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.logger; import org.apache.felix.scr.impl.metadata.ComponentMetadata; /** * The {@code ComponentLogger} is the logger to be used to log on behalf of a component. * This avoids avoids that all clients doing logging on behalf of a component need to * pass in things like {@code ComponentMetadata} or the component Id. */ public class ComponentLogger extends AbstractLogger { private final String name; private final String className; private final BundleLogger parent; private volatile int trackingCount = -3; private volatile InternalLogger currentLogger; public ComponentLogger(final ComponentMetadata metadata, final BundleLogger parent) { super(parent.getConfiguration(), ""); // we set the prefix later this.parent = parent; if ( metadata.getName() != null ) { this.name = metadata.getName(); } else if ( metadata.getImplementationClassName() != null ) { this.name = "implementation class " + metadata.getImplementationClassName(); } else { this.name = "UNKNOWN"; } if ( metadata.getImplementationClassName() != null ) { this.className = metadata.getImplementationClassName(); } else { this.className = null; } this.setComponentId(-1); } /** * Update the logger with the correct component id. * @param id The component id */ public void setComponentId(final long id) { if ( id > -1 ) { this.setPrefix(this.parent.getPrefix() + "[" + name + "(" + id + ")] : "); } else { this.setPrefix(this.parent.getPrefix() + "[" + name + "] : "); } } @Override InternalLogger getLogger() { if ( this.trackingCount < this.parent.getTrackingCount() ) { this.currentLogger = this.parent.getLogger(this.className); this.trackingCount = this.parent.getTrackingCount(); } return currentLogger; } @Override public boolean log(final int level, final String pattern, final Throwable ex, final Object... arguments) { // delegate to parent if not logging if ( !super.log(level, pattern, ex, arguments) ) { return this.parent.log(level, pattern, ex, arguments); } return false; } @Override public boolean log(final int level, final String message, final Throwable ex) { // delegate to parent if not logging if ( !super.log(level, message, ex) ) { return this.parent.log(level, message, ex); } return false; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/logger/LogServiceSupport.java0000644000175000017500000000464113675426212027623 0ustar sudipsudip/* * 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.logger; import org.osgi.framework.Bundle; import org.osgi.service.log.LogService; /** * This is a logger based on the LogService. * It supports both R6 and R7 logging * */ class LogServiceSupport { private final boolean r7Enabled; private final LogService logService; private final Bundle bundle; private static boolean checkForLoggerFactory(Class clazz) { while ( clazz != null ) { final Class[] is = clazz.getInterfaces(); for(final Class c : is) { if ( "org.osgi.service.log.LoggerFactory".equals(c.getName()) ) { return true; } if ( checkForLoggerFactory(c) ) { return true; } } clazz = clazz.getSuperclass(); } return false; } public LogServiceSupport(final Bundle bundle, final Object logService) { this.logService = (LogService) logService; this.bundle = bundle; this.r7Enabled = checkForLoggerFactory(this.logService.getClass()); } InternalLogger getLogger() { if ( r7Enabled ) { return new R7LogServiceLogger(this.bundle, this.logService, null); } return new R6LogServiceLogger(this.logService); } InternalLogger getLogger(final String className) { if ( r7Enabled ) { return new R7LogServiceLogger(this.bundle, this.logService, className); } return new R6LogServiceLogger(this.logService); } }felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/logger/StdOutLogger.java0000644000175000017500000000513713675426212026547 0ustar sudipsudip/* * 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.logger; import java.io.PrintStream; import org.osgi.service.log.LogService; /** * This logger logs to std out / err */ class StdOutLogger implements InternalLogger { @Override public boolean checkScrConfig() { return true; } @Override public void log(final int level, final String message, final Throwable ex) { if ( isLogEnabled(level) ) { // output depending on level final PrintStream out = ( level == LogService.LOG_ERROR )? System.err: System.out; // level as a string final StringBuilder buf = new StringBuilder(); switch (level) { case ( LogService.LOG_DEBUG ): buf.append( "DEBUG: " ); break; case ( LogService.LOG_INFO ): buf.append( "INFO : " ); break; case ( LogService.LOG_WARNING ): buf.append( "WARN : " ); break; case ( LogService.LOG_ERROR ): buf.append( "ERROR: " ); break; default: buf.append( "UNK : " ); break; } buf.append(message); final String msg = buf.toString(); if ( ex == null ) { out.println(msg); } else { // keep the message and the stacktrace together synchronized ( out ) { out.println( msg ); ex.printStackTrace( out ); } } } } @Override public boolean isLogEnabled(final int level) { return true; } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/logger/R7LogServiceLogger.java0000644000175000017500000000477113675426212027603 0ustar sudipsudip/* * 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.logger; import org.osgi.framework.Bundle; import org.osgi.service.log.LogService; import org.osgi.service.log.Logger; import org.osgi.service.log.LoggerFactory; /** * This is a logger based on the R7 LogService/LoggerFactory */ class R7LogServiceLogger implements InternalLogger { private final Logger logger; public R7LogServiceLogger(final Bundle bundle, final LogService loggerFactory, final String name) { this.logger = ((LoggerFactory)loggerFactory).getLogger(name == null ? Logger.ROOT_LOGGER_NAME : name, Logger.class); } @Override public boolean checkScrConfig() { return false; } @Override public boolean isLogEnabled(final int level) { switch ( level ) { case 1 : return logger.isErrorEnabled(); case 2 : return logger.isWarnEnabled(); case 3 : return logger.isInfoEnabled(); default : return logger.isDebugEnabled(); } } @Override public void log(final int level, final String message, final Throwable ex) { if ( ex == null ) { switch ( level ) { case 1 : logger.error(message); break; case 2 : logger.warn(message); break; case 3 : logger.info(message); break; default : logger.debug(message); } } else { switch ( level ) { case 1 : logger.error(message, ex); break; case 2 : logger.warn(message, ex); break; case 3 : logger.info(message, ex); break; default : logger.debug(message, ex); } } } }felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/logger/AbstractLogger.java0000644000175000017500000001143713675426212027070 0ustar sudipsudip/* * 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.logger; import java.text.MessageFormat; import org.apache.felix.scr.impl.manager.ScrConfiguration; import org.osgi.framework.Bundle; /** * This is a common base for all loggers * */ public abstract class AbstractLogger { private final ScrConfiguration config; /** * The prefix put for each log message */ private volatile String prefix; AbstractLogger(final ScrConfiguration config, final String prefix) { this.config = config; this.prefix = prefix; } ScrConfiguration getConfiguration() { return this.config; } void setPrefix(final String value) { this.prefix = value; } String getPrefix() { return this.prefix; } /** * Get the internal logger * @return The internal logger */ abstract InternalLogger getLogger(); /** * Returns {@code true} if logging for the given level is enabled. */ public boolean isLogEnabled(final int level) { final InternalLogger l = getLogger(); return (!l.checkScrConfig() || config.getLogLevel() >= level) && l.isLogEnabled(level); } /** * Method to actually emit the log message. If the LogService is available, * the message will be logged through the LogService. Otherwise the message * is logged to stdout (or stderr in case of LOG_ERROR level messages), * * @param level The log level to log the message at * @param pattern The {@code java.text.MessageFormat} message format * string for preparing the message * @param ex An optional Throwable whose stack trace is written, * @param arguments The format arguments for the pattern * string. */ public boolean log(final int level, final String pattern, final Throwable ex, final Object... arguments ) { if ( isLogEnabled( level ) ) { getLogger().log(level, format(pattern, arguments), ex); return true; } return false; } /** * Method to actually emit the log message. If the LogService is available, * the message will be logged through the LogService. Otherwise the message * is logged to stdout (or stderr in case of LOG_ERROR level messages), * * @param level The log level of the messages. This corresponds to the log * levels defined by the OSGi LogService. * @param message The message to print * @param ex The Throwable causing the message to be logged. */ public boolean log(final int level, final String message, final Throwable ex) { if ( isLogEnabled( level ) ) { getLogger().log(level, prefix.concat(" ").concat(message), ex); return true; } return false; } static String getBundleIdentifier(final Bundle bundle) { final StringBuilder sb = new StringBuilder("bundle "); // symbolic name might be null if ( bundle.getSymbolicName() != null ) { sb.append(bundle.getSymbolicName()); sb.append(':'); sb.append(bundle.getVersion()); sb.append( " (" ); sb.append( bundle.getBundleId() ); sb.append( ")" ); } else { sb.append( bundle.getBundleId() ); } return sb.toString(); } private String format( final String pattern, final Object... arguments ) { final String message; if ( arguments == null || arguments.length == 0 ) { message = pattern; } else { for(int i=0;i logServiceTracker; private volatile InternalLogger currentLogger; protected volatile int trackingCount = -2; public LogServiceEnabledLogger(final ScrConfiguration config, final BundleContext bundleContext) { super(config, getBundleIdentifier(bundleContext.getBundle())); // Start a tracker for the log service // we only track a single log service which in reality should be enough logServiceTracker = new ServiceTracker<>( bundleContext, LOGSERVICE_CLASS, new ServiceTrackerCustomizer() { private volatile boolean hasService = false; @Override public Object addingService(final ServiceReference reference) { if ( !hasService ) { final Object logService = bundleContext.getService(reference); if ( logService != null ) { hasService = true; final LogServiceSupport lsl = new LogServiceSupport(bundleContext.getBundle(), logService); return lsl; } } return null; } @Override public void modifiedService(final ServiceReference reference, final Object service) { // nothing to do } @Override public void removedService(final ServiceReference reference, final Object service) { hasService = false; bundleContext.ungetService(reference); } } ); logServiceTracker.open(); } /** * Close the logger */ public void close() { // stop the tracker logServiceTracker.close(); } @Override InternalLogger getLogger() { if ( this.trackingCount < this.logServiceTracker.getTrackingCount() ) { final Object logServiceSupport = this.logServiceTracker.getService(); if ( logServiceSupport == null ) { this.currentLogger = this.getDefaultLogger(); } else { this.currentLogger = ((LogServiceSupport)logServiceSupport).getLogger(); } this.trackingCount = this.logServiceTracker.getTrackingCount(); } return currentLogger; } abstract InternalLogger getDefaultLogger(); }felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/helper/0000755000175000017500000000000013675426212023314 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/helper/Coercions.java0000644000175000017500000003212313675426212026104 0ustar sudipsudip/* * 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.util.Collection; import org.osgi.framework.Bundle; import org.osgi.service.component.ComponentException; /** * This implements the coercion table in RFC 190 5.6.3 * */ public class Coercions { // Numbers are AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short //annotation fields can be primitives, String, Class, enums, annotations, and arrays of the preceding types // input scalars // String | Integer | Long | Float // | Double | Byte | Short //| Character | Boolean private static final byte byte0 = 0; private static final char char0 = 0; private static final double double0 = 0; private static final float float0 = 0; private static final int int0 = 0; private static final long long0 = 0; private static final short short0 = 0; public static Object coerce(Class type, Object raw, Bundle bundle) { if ( type == Byte.class || type == byte.class ) { return coerceToByte( raw ); } if ( type == Boolean.class || type == boolean.class ) { return coerceToBoolean( raw ); } if ( type == Character.class || type == char.class ) { return coerceToChar( raw ); } if ( type == Class.class ) { return coerceToClass( raw, bundle ); } if ( type == Double.class || type == double.class ) { return coerceToDouble( raw ); } if ( type.isEnum() ) { final Class clazz = type; return coerceToEnum( raw, clazz ); } if ( type == Float.class || type == float.class ) { return coerceToFloat( raw ); } if ( type == Integer.class || type == int.class ) { return coerceToInteger( raw ); } if ( type == Long.class || type == long.class ) { return coerceToLong( raw ); } if ( type == Short.class || type == short.class ) { return coerceToShort( raw ); } if ( type == String.class ) { return coerceToString( raw ); } if ( raw != null ) { raw = multipleToSingle( raw, null ); if ( raw != null ) { if ( type.isAssignableFrom( raw.getClass() ) ) { return raw; } throw new ComponentException( "unexpected output type " + type ); } } return null; } public static byte coerceToByte(Object o) { o = multipleToSingle( o, byte0 ); if ( o instanceof Byte ) { return (Byte) o; } if ( o instanceof String ) { try { return Byte.parseByte( (String) o ); } catch ( NumberFormatException e ) { throw new ComponentException( e ); } } if ( o instanceof Boolean ) { return (Boolean) o? 1: byte0; } if ( o instanceof Character ) { return (byte) ( (Character) o ).charValue(); } if ( o instanceof Number ) { return ( (Number) o ).byteValue(); } if ( o == null ) { return 0; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static char coerceToChar(Object o) { o = multipleToSingle( o, byte0 ); if ( o instanceof Character ) { return (Character) o; } if ( o instanceof String ) { if ( ( (String) o ).length() > 0 ) { return ( (String) o ).charAt( 0 ); } return char0; } if ( o instanceof Boolean ) { return (Boolean) o? 1: char0; } if ( o instanceof Number ) { return (char) ( (Number) o ).intValue(); } if ( o == null ) { return char0; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static double coerceToDouble(Object o) { o = multipleToSingle( o, double0 ); if ( o instanceof Double ) { return (Double) o; } if ( o instanceof String ) { try { return Double.parseDouble( (String) o ); } catch ( NumberFormatException e ) { throw new ComponentException( e ); } } if ( o instanceof Boolean ) { return (Boolean) o? 1: 0; } if ( o instanceof Character ) { return ( (Character) o ).charValue(); } if ( o instanceof Number ) { return ( (Number) o ).doubleValue(); } if ( o == null ) { return 0; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static float coerceToFloat(Object o) { o = multipleToSingle( o, float0 ); if ( o instanceof Float ) { return (Float) o; } if ( o instanceof String ) { try { return Float.parseFloat( (String) o ); } catch ( NumberFormatException e ) { throw new ComponentException( e ); } } if ( o instanceof Boolean ) { return (Boolean) o? 1: 0; } if ( o instanceof Character ) { return ( (Character) o ).charValue(); } if ( o instanceof Number ) { return ( (Number) o ).floatValue(); } if ( o == null ) { return 0; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static int coerceToInteger(Object o) { o = multipleToSingle( o, int0 ); if ( o instanceof Integer ) { return (Integer) o; } if ( o instanceof String ) { try { return Integer.parseInt( (String) o ); } catch ( NumberFormatException e ) { throw new ComponentException( e ); } } if ( o instanceof Boolean ) { return (Boolean) o? 1: 0; } if ( o instanceof Character ) { return ( (Character) o ).charValue(); } if ( o instanceof Number ) { return ( (Number) o ).intValue(); } if ( o == null ) { return 0; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static long coerceToLong(Object o) { o = multipleToSingle( o, long0 ); if ( o instanceof Long ) { return (Long) o; } if ( o instanceof String ) { try { return Long.parseLong( (String) o ); } catch ( NumberFormatException e ) { throw new ComponentException( e ); } } if ( o instanceof Boolean ) { return (Boolean) o? 1: 0; } if ( o instanceof Character ) { return ( (Character) o ).charValue(); } if ( o instanceof Number ) { return ( (Number) o ).longValue(); } if ( o == null ) { return 0; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static short coerceToShort(Object o) { o = multipleToSingle( o, short0 ); if ( o instanceof Short ) { return (Short) o; } if ( o instanceof String ) { try { return Short.parseShort( (String) o ); } catch ( NumberFormatException e ) { throw new ComponentException( e ); } } if ( o instanceof Boolean ) { return (Boolean) o? 1: short0; } if ( o instanceof Character ) { return (short) ( (Character) o ).charValue(); } if ( o instanceof Number ) { return ( (Number) o ).shortValue(); } if ( o == null ) { return 0; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static String coerceToString(Object o) { o = multipleToSingle( o, null ); if ( o instanceof String ) { return (String) o; } if ( o == null ) { return null; } return o.toString(); } public static boolean coerceToBoolean(Object o) { o = multipleToSingle( o, false ); if ( o instanceof Boolean ) { return (Boolean) o; } if ( o instanceof String ) { try { return Boolean.parseBoolean( (String) o ); } catch ( NumberFormatException e ) { throw new ComponentException( e ); } } if ( o instanceof Character ) { return ( (Character) o ).charValue() != 0; } if ( o instanceof Number ) { return ( (Number) o ).doubleValue() != 0D; } if ( o == null ) { return false; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static Class coerceToClass(Object o, Bundle b) { o = multipleToSingle( o, null ); if ( o == null ) { return null; } if ( o instanceof String ) { try { return b.loadClass( (String) o ); } catch ( ClassNotFoundException e ) { throw new ComponentException( e ); } } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } public static > T coerceToEnum(Object o, Class clazz) { o = multipleToSingle( o, null ); if ( o instanceof String ) { try { return Enum.valueOf( clazz, (String) o ); } catch ( IllegalArgumentException e ) { throw new ComponentException( e ); } } if ( o == null ) { return null; } throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() ); } private static Object multipleToSingle(Object o, Object defaultValue) { if ( o instanceof Collection ) { return firstCollectionElement( o, defaultValue ); } if ( o != null && o.getClass().isArray() ) { return firstArrayElement( o, defaultValue ); } return o; } private static Object firstCollectionElement(Object raw, Object defaultValue) { if ( !( raw instanceof Collection ) ) { throw new ComponentException( "Not a collection: " + raw ); } Collection c = (Collection) raw; if ( c.isEmpty() ) { return defaultValue; } return c.iterator().next(); } private static Object firstArrayElement(Object o, Object defaultValue) { if ( o == null || !o.getClass().isArray() ) { throw new ComponentException( "Not an array: " + o ); } if ( Array.getLength( o ) == 0 ) { return defaultValue; } return Array.get( o, 0 ); } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/helper/ConfigAdminTracker.java0000644000175000017500000000733513675426212027661 0ustar sudipsudip/* * 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.apache.felix.scr.impl.manager.ComponentActivator; import org.apache.felix.scr.impl.manager.RegionConfigurationSupport; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.log.LogService; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; public class ConfigAdminTracker { public static final String CONFIGURATION_ADMIN = "org.osgi.service.cm.ConfigurationAdmin"; private final ServiceTracker configAdminTracker; public ConfigAdminTracker(final ComponentActivator componentActivator) { configAdminTracker = new ServiceTracker<>( componentActivator.getBundleContext(), CONFIGURATION_ADMIN, new ServiceTrackerCustomizer() { @Override public RegionConfigurationSupport addingService(ServiceReference reference) { // let's do a quick check if the returned CA service is using the same // CA API as is visible to this (SCR) bundle boolean visible = false; try { ConfigurationAdmin ca = componentActivator.getBundleContext().getService(reference); if ( ca != null ) { visible = true; componentActivator.getBundleContext().ungetService(reference); } } catch ( final Exception ex) { componentActivator.getLogger().log(LogService.LOG_ERROR, "Configuration admin API visible to bundle " + componentActivator.getBundleContext().getBundle() + " is not the same as the Configuration Admin API visible to the SCR implementation.", ex); } if ( !visible ) { return null; } return componentActivator.setRegionConfigurationSupport( reference ); } @Override public void modifiedService(ServiceReference reference, RegionConfigurationSupport service) { } @Override public void removedService(ServiceReference reference, RegionConfigurationSupport rcs) { componentActivator.unsetRegionConfigurationSupport( rcs ); } } ); configAdminTracker.open(); } public void dispose() { configAdminTracker.close(); } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/helper/ReadOnlyDictionary.java0000644000175000017500000001241213675426212027722 0ustar sudipsudip/* * 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.util.Collection; import java.util.Collections; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; import java.util.Map; import java.util.Set; import org.osgi.framework.ServiceReference; /** * The ReadOnlyDictionary is both a Dictionary and * a Map whose modification methods (like {@link #put(Object, Object)}, * {@link #remove(Object)}, etc.) throw an {@link UnsupportedOperationException}. */ public class ReadOnlyDictionary extends Dictionary implements Map, Comparable { private final Hashtable m_delegate; private final ServiceReference m_serviceReference; /** * Creates a wrapper for the given delegate dictionary providing read * only access to the data. */ public ReadOnlyDictionary( final Map delegate ) { if ( delegate instanceof Hashtable ) { this.m_delegate = ( Hashtable ) delegate; } else { this.m_delegate = new Hashtable(); for ( Map.Entry entry: delegate.entrySet() ) { this.m_delegate.put( entry.getKey(), entry.getValue() ); } } m_serviceReference = null; } /** * Creates a wrapper for the given service reference providing read only * access to the reference properties. */ public ReadOnlyDictionary( final ServiceReference serviceReference ) { Hashtable properties = new Hashtable(); final String[] keys = serviceReference.getPropertyKeys(); if ( keys != null ) { for ( int j = 0; j < keys.length; j++ ) { final String key = keys[j]; properties.put( key, serviceReference.getProperty( key ) ); } } m_delegate = properties; m_serviceReference = serviceReference; } //---------- Dictionary API @Override public Enumeration elements() { return m_delegate.elements(); } @Override public Object get( final Object key ) { return m_delegate.get( key ); } @Override public boolean isEmpty() { return m_delegate.isEmpty(); } @Override public Enumeration keys() { return m_delegate.keys(); } /** * This method has no effect and always returns null as this * instance is read-only and cannot modify and properties. */ @Override public Object put( final String key, final Object value ) { throw new UnsupportedOperationException(); } /** * This method has no effect and always returns null as this * instance is read-only and cannot modify and properties. */ @Override public Object remove( final Object key ) { throw new UnsupportedOperationException(); } @Override public int size() { return m_delegate.size(); } @Override public String toString() { return m_delegate.toString(); } //---------- Map API public void clear() { throw new UnsupportedOperationException(); } public boolean containsKey( Object key ) { return m_delegate.containsKey( key ); } public boolean containsValue( Object value ) { return m_delegate.containsValue( value ); } public Set> entrySet() { return Collections.unmodifiableSet( m_delegate.entrySet() ); } public Set keySet() { return Collections.unmodifiableSet( m_delegate.keySet() ); } public void putAll( Map m ) { throw new UnsupportedOperationException(); } public Collection values() { return Collections.unmodifiableCollection( m_delegate.values() ); } public int compareTo(final ReadOnlyDictionary o) { if ( m_serviceReference == null ) { if ( o.m_serviceReference == null ) { return 0; } return 1; } else if ( o.m_serviceReference == null ) { return -1; } return m_serviceReference.compareTo(o.m_serviceReference); } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java0000644000175000017500000001626513675426212032126 0ustar sudipsudip/* * 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.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceObjects; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentServiceObjects; /** * Utility class for handling references using a ComponentServiceObjects * to get services. */ public class ComponentServiceObjectsHelper { private final BundleContext bundleContext; private final ConcurrentMap, ComponentServiceObjectsImpl> services = new ConcurrentHashMap, ComponentServiceObjectsImpl>(); private final List closedServices = new ArrayList(); private final ConcurrentMap, Object> prototypeInstances = new ConcurrentHashMap, Object>(); public ComponentServiceObjectsHelper(final BundleContext bundleContext) { this.bundleContext = bundleContext; } public void cleanup() { Collection csos = services.values(); services.clear(); for(final ComponentServiceObjectsImpl cso : csos) { cso.deactivate(); } synchronized ( this.closedServices ) { csos = new ArrayList(this.closedServices); this.closedServices.clear(); } for(final ComponentServiceObjectsImpl cso : csos) { cso.deactivate(); } prototypeInstances.clear(); } public ComponentServiceObjects getServiceObjects(final ServiceReference ref) { ComponentServiceObjectsImpl cso = this.services.get(ref); if ( cso == null ) { final ServiceObjects serviceObjects = this.bundleContext.getServiceObjects(ref); if ( serviceObjects != null ) { cso = new ComponentServiceObjectsImpl(serviceObjects); final ComponentServiceObjectsImpl oldCSO = this.services.putIfAbsent(ref, cso); if ( oldCSO != null ) { cso = oldCSO; } } } return cso; } public void closeServiceObjects(final ServiceReference ref) { ComponentServiceObjectsImpl cso = this.services.remove(ref); if ( cso != null ) { synchronized ( closedServices ) { closedServices.add(cso); } cso.close(); } } public T getPrototypeRefInstance(final ServiceReference ref) { T service = (T) prototypeInstances.get(ref); if ( service == null ) { service = (T) getServiceObjects(ref).getService(); T oldService = (T)prototypeInstances.putIfAbsent(ref, service); if ( oldService != null ) { // another thread created the instance already getServiceObjects(ref).ungetService(service); service = oldService; } } return service; } private static final class ComponentServiceObjectsImpl implements ComponentServiceObjects { private final List instances = new ArrayList(); private volatile ServiceObjects serviceObjects; private volatile boolean deactivated = false; public ComponentServiceObjectsImpl(final ServiceObjects so) { this.serviceObjects = so; } public void deactivate() { this.deactivated = true; close(); } /** * Close this instance and unget all services. */ public void close() { final ServiceObjects so = this.serviceObjects; this.serviceObjects = null; if ( so != null ) { final List localInstances = new ArrayList(); synchronized ( this.instances ) { localInstances.addAll(this.instances); this.instances.clear(); } for(final Object obj : localInstances) { try { so.ungetService(obj); } catch ( final IllegalStateException ise ) { // ignore (this happens if the bundle is not valid anymore) } catch ( final IllegalArgumentException iae ) { // ignore (this happens if the service has not been returned by the service objects) } } } } public Object getService() { if ( this.deactivated ) { throw new IllegalStateException(); } final ServiceObjects so = this.serviceObjects; Object service = null; if ( so != null ) { service = so.getService(); if ( service != null ) { synchronized ( this.instances ) { this.instances.add(service); } } } return service; } public void ungetService(final Object service) { if ( this.deactivated ) { throw new IllegalStateException(); } final ServiceObjects so = this.serviceObjects; if ( so != null ) { boolean remove; synchronized ( instances ) { remove = instances.remove(service); } if ( remove ) { so.ungetService(service); } } } public ServiceReference getServiceReference() { final ServiceObjects so = this.serviceObjects; if ( so != null ) { return so.getServiceReference(); } return null; } @Override public String toString() { return "ComponentServiceObjectsImpl [instances=" + instances + ", serviceObjects=" + serviceObjects + ", deactivated=" + deactivated + ", hashCode=" + this.hashCode() + "]"; } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/Activator.java0000644000175000017500000005466313675426212024652 0ustar sudipsudip/* * 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 java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.felix.scr.impl.config.ScrConfigurationImpl; import org.apache.felix.scr.impl.inject.internal.ClassUtils; import org.apache.felix.scr.impl.logger.ScrLogger; import org.apache.felix.scr.impl.manager.ComponentHolder; import org.apache.felix.scr.impl.metadata.ComponentMetadata; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataReader; import org.apache.felix.scr.impl.metadata.MetadataStoreHelper.MetaDataWriter; import org.apache.felix.scr.impl.runtime.ServiceComponentRuntimeImpl; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; import org.osgi.namespace.extender.ExtenderNamespace; import org.osgi.service.component.ComponentConstants; import org.osgi.service.component.runtime.ServiceComponentRuntime; import org.osgi.service.log.LogService; /** * This activator is used to cover requirement described in section 112.8.1 @@ -27,14 * 37,202 @@ in active bundles. * */ public class Activator extends AbstractExtender { // Our configuration from bundle context properties and Config Admin private final ScrConfigurationImpl m_configuration; private BundleContext m_context; //Either this bundle's context or the framework bundle context, depending on the globalExtender setting. private BundleContext m_globalContext; // this bundle private Bundle m_bundle; // the log service to log messages to private volatile ScrLogger logger; // map of BundleComponentActivator instances per Bundle indexed by Bundle id private Map m_componentBundles; // registry of managed component private ComponentRegistry m_componentRegistry; // thread acting upon configurations private ComponentActorThread m_componentActor; private ServiceRegistration m_runtime_reg; private ComponentCommands m_componentCommands; private ConcurrentMap> m_componentMetadataStore; public Activator() { m_configuration = new ScrConfigurationImpl( this ); } /** * Registers this instance as a (synchronous) bundle listener and loads the * components of already registered bundles. * * @param context The BundleContext of the SCR implementation * bundle. */ @Override public void start(final BundleContext context) throws Exception { m_context = context; m_bundle = context.getBundle(); // require the log service logger = new ScrLogger(m_configuration, m_context); // set bundle context for PackageAdmin tracker ClassUtils.setBundleContext( context ); // get the configuration m_configuration.start( m_context ); //this will call restart, which calls super.start. } public void restart(boolean globalExtender) { m_componentMetadataStore = load(m_context, logger, m_configuration.cacheMetadata()); BundleContext context = m_globalContext; if ( globalExtender ) { m_globalContext = m_context.getBundle( Constants.SYSTEM_BUNDLE_LOCATION ).getBundleContext(); } else { m_globalContext = m_context; } if ( ClassUtils.m_packageAdmin != null ) { logger.log(LogService.LOG_INFO, "Stopping to restart with new globalExtender setting: {0}", null, globalExtender); //this really is a restart, not the initial start // the initial start where m_globalContext is null should skip this as m_packageAdmin should not yet be set. try { super.stop( context ); } catch ( final Exception e ) { // logger might be null if ( logger != null ) { logger.log(LogService.LOG_ERROR, "Exception stopping during restart", e); } } // reinstantiate logger logger = new ScrLogger(m_configuration, m_context); } try { logger.log(LogService.LOG_INFO, "Starting with globalExtender setting: {0}", null, globalExtender); super.start( m_globalContext ); } catch ( final Exception e ) { logger.log(LogService.LOG_ERROR, "Exception starting during restart", e); } } @Override protected void doStart() throws Exception { // prepare component registry m_componentBundles = new HashMap<>(); m_componentRegistry = new ComponentRegistry( this.m_configuration, this.logger ); final ServiceComponentRuntimeImpl runtime = new ServiceComponentRuntimeImpl( m_globalContext, m_componentRegistry ); m_runtime_reg = m_context.registerService( ServiceComponentRuntime.class, runtime, m_componentRegistry.getServiceRegistrationProperties() ); m_componentRegistry.setRegistration(m_runtime_reg); // log SCR startup logger.log( LogService.LOG_INFO, " Version = {0}", null, m_bundle.getVersion().toString() ); // create and start the component actor m_componentActor = new ComponentActorThread( this.logger ); Thread t = new Thread( m_componentActor, "SCR Component Actor" ); t.setDaemon( true ); t.start(); super.doStart(); m_componentCommands = new ComponentCommands(m_context, runtime, m_configuration); m_componentCommands.register(); m_componentCommands.updateProvideScrInfoService(m_configuration.infoAsService()); m_configuration.setScrCommand(m_componentCommands); } @Override public void stop(BundleContext context) throws Exception { super.stop( context ); m_configuration.stop(); store(m_componentMetadataStore, context, logger, m_configuration.cacheMetadata()); } @Override public void bundleChanged(BundleEvent event) { super.bundleChanged(event); if (event.getType() == BundleEvent.UPDATED || event.getType() == BundleEvent.UNINSTALLED) { m_componentMetadataStore.remove(event.getBundle().getBundleId()); } } private static ConcurrentMap> load( BundleContext context, ScrLogger logger, boolean loadFromCache) { try { ConcurrentMap> result = new ConcurrentHashMap<>(); if (!loadFromCache) { return result; } BundleContext systemContext = context.getBundle( Constants.SYSTEM_BUNDLE_LOCATION).getBundleContext(); File store = context.getDataFile("componentMetadataStore"); if (store.isFile()) { try (DataInputStream in = new DataInputStream( new BufferedInputStream(new FileInputStream(store)))) { MetaDataReader metaDataReader = new MetaDataReader(); if (!metaDataReader.isVersionSupported(in)) { // the stored version is not compatible return result; } int numStrings = in.readInt(); for (int i = 0; i < numStrings; i++) { metaDataReader.readIndexedString(in); } int numBundles = in.readInt(); for (int i = 0; i < numBundles; i++) { // Read all the components for the ID even if the bundle does not exist; long bundleId = in.readLong(); int numComponents = in.readInt(); long lastModified = in.readLong(); List components = new ArrayList<>( numComponents); for (int j = 0; j < numComponents; j++) { components.add(ComponentMetadata.load(in, metaDataReader)); } // Check with system context by ID to avoid hooks hiding; Bundle b = systemContext.getBundle(bundleId); if (b != null) { if (lastModified == b.getLastModified()) { result.put(bundleId, components); } } } } catch (IOException e) { logger.log(LogService.LOG_WARNING, "Error loading component metadata cache.", e); } } return result; } catch (RuntimeException re) { // avoid failing all of SCR start on cache load bug logger.log(LogService.LOG_ERROR, "Error loading component metadata cache.", re); return new ConcurrentHashMap<>(); } } private static void store(Map> componentsMap, BundleContext context, ScrLogger logger, boolean storeCache) { if (!storeCache) { return; } BundleContext systemContext = context.getBundle( Constants.SYSTEM_BUNDLE_LOCATION).getBundleContext(); File store = context.getDataFile("componentMetadataStore"); try (DataOutputStream out = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(store)))) { MetaDataWriter metaDataWriter = new MetaDataWriter(); metaDataWriter.writeVersion(out); Set allStrings = new HashSet<>(); for (List components : componentsMap.values()) { for (ComponentMetadata component : components) { component.collectStrings(allStrings); } } // remove possible null allStrings.remove(null); out.writeInt(allStrings.size()); for (String s : allStrings) { metaDataWriter.writeIndexedString(s, out); } out.writeInt(componentsMap.size()); for (Entry> entry : componentsMap.entrySet()) { out.writeLong(entry.getKey()); out.writeInt(entry.getValue().size()); Bundle b = systemContext.getBundle(entry.getKey()); out.writeLong(b == null ? -1 : b.getLastModified()); for (ComponentMetadata component : entry.getValue()) { component.store(out, metaDataWriter); } } } catch (IOException e) { logger.log(LogService.LOG_WARNING, "Error storing component metadata cache.", e); } } /** * Unregisters this instance as a bundle listener and unloads all components * which have been registered during the active life time of the SCR * implementation bundle. */ @Override public void doStop() throws Exception { // stop tracking super.doStop(); if ( m_componentCommands != null ) { m_componentCommands.unregister(); } if ( m_runtime_reg != null ) { m_runtime_reg.unregister(); m_runtime_reg = null; } // dispose component registry if ( m_componentRegistry != null ) { m_componentRegistry = null; } // terminate the actor thread if ( m_componentActor != null ) { m_componentActor.terminate(); m_componentActor = null; } // close the LogService tracker now if ( logger != null ) { logger.close(); logger = null; } ClassUtils.close(); } //---------- Component Management ----------------------------------------- @Override protected ScrExtension doCreateExtension(final Bundle bundle) throws Exception { return new ScrExtension( bundle ); } protected class ScrExtension { private final Bundle bundle; private final Lock stateLock = new ReentrantLock(); public ScrExtension(Bundle bundle) { this.bundle = bundle; } public void start() { boolean acquired = false; try { try { acquired = stateLock.tryLock( m_configuration.stopTimeout(), TimeUnit.MILLISECONDS ); } catch ( final InterruptedException e ) { Thread.currentThread().interrupt(); logger.log(LogService.LOG_WARNING, "The wait for {0} being destroyed before destruction has been interrupted.", e, bundle ); } loadComponents( ScrExtension.this.bundle ); } finally { if ( acquired ) { stateLock.unlock(); } } } public void destroy() { boolean acquired = false; try { try { acquired = stateLock.tryLock( m_configuration.stopTimeout(), TimeUnit.MILLISECONDS ); } catch ( final InterruptedException e ) { Thread.currentThread().interrupt(); logger.log(LogService.LOG_WARNING, "The wait for {0} being started before destruction has been interrupted.", e, bundle ); } disposeComponents( bundle ); } finally { if ( acquired ) { stateLock.unlock(); } } } } /** * Loads the components of the given bundle. If the bundle has no * Service-Component header, this method has no effect. The * fragments of a bundle are not checked for the header (112.4.1). *

* This method calls the {@link Bundle#getBundleContext()} method to find * the BundleContext of the bundle. If the context cannot be * found, this method does not load components for the bundle. */ private void loadComponents(Bundle bundle) { final Long bundleId = bundle.getBundleId(); List cached = m_componentMetadataStore.get(bundleId); if (cached != null && cached.isEmpty()) { // Cached that there are no components for this bundle. return; } if (cached == null && bundle.getHeaders("").get(ComponentConstants.SERVICE_COMPONENT) == null) { // Cache that there are no components m_componentMetadataStore.put(bundleId, Collections. emptyList()); // no components in the bundle, abandon return; } // there should be components, load them with a bundle context BundleContext context = bundle.getBundleContext(); if ( context == null ) { logger.log(LogService.LOG_DEBUG, "Cannot get BundleContext of {0}.", null, bundle); return; } //Examine bundle for extender requirement; if present check if bundle is wired to us. BundleWiring wiring = bundle.adapt( BundleWiring.class ); List extenderWires = wiring.getRequiredWires( ExtenderNamespace.EXTENDER_NAMESPACE ); for ( BundleWire wire : extenderWires ) { if ( ComponentConstants.COMPONENT_CAPABILITY_NAME.equals( wire.getCapability().getAttributes().get( ExtenderNamespace.EXTENDER_NAMESPACE ) ) ) { if ( !m_bundle.adapt( BundleRevision.class ).equals( wire.getProvider() ) ) { logger.log(LogService.LOG_DEBUG, "{0} wired to a different extender: {1}.", null, bundle, wire.getProvider().getBundle()); return; } break; } } // FELIX-1666 method is called for the LAZY_ACTIVATION event and // the started event. Both events cause this method to be called; // so we have to make sure to not load components twice // FELIX-2231 Mark bundle loaded early to prevent concurrent loading // if LAZY_ACTIVATION and STARTED event are fired at the same time final boolean loaded; synchronized ( m_componentBundles ) { if ( m_componentBundles.containsKey( bundleId ) ) { loaded = true; } else { m_componentBundles.put( bundleId, null ); loaded = false; } } // terminate if already loaded (or currently being loaded) if ( loaded ) { logger.log(LogService.LOG_DEBUG, "Components for {0} already loaded. Nothing to do.", null, bundle ); return; } try { BundleComponentActivator ga = new BundleComponentActivator( this.logger, m_componentRegistry, m_componentActor, context, m_configuration, cached); ga.initialEnable(); if (cached == null) { List> components = ga.getSelectedComponents(null); List metadatas = new ArrayList<>(components.size()); for (ComponentHolder holder : ga.getSelectedComponents(null)) { metadatas.add(holder.getComponentMetadata()); } m_componentMetadataStore.put(bundleId, metadatas); } // replace bundle activator in the map synchronized ( m_componentBundles ) { m_componentBundles.put( bundleId, ga ); } } catch ( Exception e ) { // remove the bundle id from the bundles map to ensure it is // not marked as being loaded synchronized ( m_componentBundles ) { m_componentBundles.remove( bundleId ); } if ( e instanceof IllegalStateException && bundle.getState() != Bundle.ACTIVE ) { logger.log(LogService.LOG_DEBUG, "{0} has been stopped while trying to activate its components. Trying again when the bundles gets started again.", e, bundle ); } else { logger.log(LogService.LOG_ERROR, "Error while loading components of {0}", e, bundle); } } } /** * Unloads components of the given bundle. If no components have been loaded * for the bundle, this method has no effect. */ private void disposeComponents(Bundle bundle) { final BundleComponentActivator ga; synchronized ( m_componentBundles ) { ga = m_componentBundles.remove( bundle.getBundleId() ); } if ( ga != null ) { try { int reason = isStopping()? ComponentConstants.DEACTIVATION_REASON_DISPOSED : ComponentConstants.DEACTIVATION_REASON_BUNDLE_STOPPED; ga.dispose( reason ); } catch ( Exception e ) { logger.log(LogService.LOG_ERROR, "Error while disposing components of {0}", e, bundle); } } } @Override protected void debug(final Bundle bundle, final String msg) { if ( logger.isLogEnabled(LogService.LOG_DEBUG) ) { if ( bundle != null ) { logger.log( LogService.LOG_DEBUG, "{0} : " + msg, null, bundle ); } else { logger.log( LogService.LOG_DEBUG, msg, null ); } } } @Override protected void warn(final Bundle bundle, final String msg, final Throwable t) { if ( logger.isLogEnabled(LogService.LOG_WARNING) ) { if ( bundle != null ) { logger.log( LogService.LOG_WARNING, "{0} : " + msg, t, bundle ); } else { logger.log( LogService.LOG_WARNING, msg, t ); } } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java0000644000175000017500000006742513675426212026411 0ustar sudipsudip/* * 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 java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; import org.apache.felix.scr.impl.inject.ComponentMethods; import org.apache.felix.scr.impl.inject.internal.ComponentMethodsImpl; import org.apache.felix.scr.impl.logger.ComponentLogger; import org.apache.felix.scr.impl.logger.ScrLogger; import org.apache.felix.scr.impl.manager.AbstractComponentManager; import org.apache.felix.scr.impl.manager.ComponentActivator; import org.apache.felix.scr.impl.manager.ComponentHolder; import org.apache.felix.scr.impl.manager.ConfigurableComponentHolder; import org.apache.felix.scr.impl.manager.DependencyManager; import org.apache.felix.scr.impl.manager.RegionConfigurationSupport; import org.apache.felix.scr.impl.manager.ScrConfiguration; import org.apache.felix.scr.impl.metadata.ComponentMetadata; import org.apache.felix.scr.impl.metadata.TargetedPID; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentConstants; import org.osgi.service.component.ComponentException; import org.osgi.service.component.runtime.ServiceComponentRuntime; import org.osgi.service.log.LogService; /** * The ComponentRegistry class acts as the global registry for * components by name and by component ID. */ public class ComponentRegistry { /** * Service property for change count. This constant is defined here to avoid * a dependency on R7 of the framework. * The value of the property is of type {@code Long}. */ private static String PROP_CHANGECOUNT = "service.changecount"; /** * The map of known components indexed by component name. The values are * either null (for name reservations) or implementations * of the {@link ComponentHolder} interface. *

* The {@link #checkComponentName(String)} will first add an entry to this * map with null value to reserve the name. After setting up * the component, the {@link #registerComponentHolder(String, ComponentHolder)} * method replaces the value of the named entry with the actual * {@link ComponentHolder}. * * @see #checkComponentName(String) * @see #registerComponentHolder(String, ComponentHolder) * @see #unregisterComponentHolder(String) */ private final Map> m_componentHoldersByName; /** * The map of known components indexed by component configuration pid. The values are * Sets of the {@link ComponentHolder} interface. Normally, the configuration pid * is the component name, but since DS 1.2 (OSGi 4.3), a component may specify a specific * pid, and it is possible that different components refer to the same pid. That's why * the values of this map are Sets of ComponentHolders, allowing to lookup all components * which are using a given configuration pid. * This map is used when the ConfigurationSupport detects that a CM pid is updated. When * a PID is updated, the ConfigurationSupport listener class invokes the * {@link #getComponentHoldersByPid(String)} method which returns an iterator over all * components that are using the given pid for configuration. *

* * @see #registerComponentHolder(String, ComponentHolder) * @see #unregisterComponentHolder(String) * @see RegionConfigurationSupport#configurationEvent(org.osgi.service.cm.ConfigurationEvent) */ private final Map>> m_componentHoldersByPid; /** * Map of components by component ID. This map indexed by the component * ID number (java.lang.Long) contains the actual * {@link AbstractComponentManager} instances existing in the system. * * @see #registerComponentId(AbstractComponentManager) * @see #unregisterComponentId(long) */ private final Map> m_componentsById; /** * Counter to setup the component IDs as issued by the * {@link #registerComponentId(AbstractComponentManager)} method. This * counter is only incremented. */ private long m_componentCounter = -1; private final Map, List>> m_missingDependencies = new HashMap<>( ); private final ScrLogger m_logger; private final ScrConfiguration m_configuration; public ComponentRegistry( final ScrConfiguration scrConfiguration, final ScrLogger logger ) { m_configuration = scrConfiguration; m_logger = logger; m_componentHoldersByName = new HashMap<>(); m_componentHoldersByPid = new HashMap<>(); m_componentsById = new HashMap<>(); } //---------- ComponentManager registration by component Id /** * Assigns a unique ID to the component, internally registers the * component under that ID and returns the assigned component ID. * * @param componentManager The {@link AbstractComponentManager} for which * to assign a component ID and which is to be internally registered * * @return the assigned component ID */ final long registerComponentId( final AbstractComponentManager componentManager ) { long componentId; synchronized ( m_componentsById ) { componentId = ++m_componentCounter; m_componentsById.put( componentId, componentManager ); } return componentId; } /** * Unregisters the component with the given component ID from the internal * registry. After unregistration, the component ID should be considered * invalid. * * @param componentId The ID of the component to be removed from the * internal component registry. */ final void unregisterComponentId( final long componentId ) { synchronized ( m_componentsById ) { m_componentsById.remove( componentId ); } } //---------- ComponentHolder registration by component name /** * Checks whether the component name is "globally" unique or not. If it is * unique, it is reserved until the actual component is registered with * {@link #registerComponentHolder(String, ComponentHolder)} or until * it is unreserved by calling {@link #unregisterComponentHolder(String)}. * If a component with the same name has already been reserved or registered * a ComponentException is thrown with a descriptive message. * * @param bundle the bundle registering the component * @param name the component name to check and reserve * @throws ComponentException if the name is already in use by another * component. */ final ComponentRegistryKey checkComponentName( final Bundle bundle, final String name ) { // register the name if no registration for that name exists already final ComponentRegistryKey key = new ComponentRegistryKey( bundle, name ); ComponentHolder existingRegistration = null; boolean present; synchronized ( m_componentHoldersByName ) { present = m_componentHoldersByName.containsKey( key ); if ( !present ) { m_componentHoldersByName.put( key, null ); } else { existingRegistration = m_componentHoldersByName.get( key ); } } // there was a registration already, throw an exception and use the // existing registration to provide more information if possible if ( present ) { String message = "The component name '" + name + "' has already been registered"; if ( existingRegistration != null ) { Bundle cBundle = existingRegistration.getActivator().getBundleContext().getBundle(); ComponentMetadata cMeta = existingRegistration.getComponentMetadata(); StringBuilder buf = new StringBuilder( message ); buf.append( " by Bundle " ).append( cBundle.getBundleId() ); if ( cBundle.getSymbolicName() != null ) { buf.append( " (" ).append( cBundle.getSymbolicName() ).append( ")" ); } buf.append( " as Component of Class " ).append( cMeta.getImplementationClassName() ); message = buf.toString(); } throw new ComponentException( message ); } return key; } /** * Registers the given component under the given name. If the name has not * already been reserved calling {@link #checkComponentName(String)} this * method throws a {@link ComponentException}. * * @param name The name to register the component under * @param componentHolder The component to register * * @throws ComponentException if the name has not been reserved through * {@link #checkComponentName(String)} yet. */ final void registerComponentHolder( final ComponentRegistryKey key, ComponentHolder componentHolder ) { m_logger.log(LogService.LOG_DEBUG, "Registering component with pid {0} for bundle {1}", null, componentHolder.getComponentMetadata().getConfigurationPid(), key.getBundleId()); synchronized ( m_componentHoldersByName ) { // only register the component if there is a m_registration for it ! if ( m_componentHoldersByName.get( key ) != null ) { // this is not expected if all works ok throw new ComponentException( "The component name '{0}" + componentHolder.getComponentMetadata().getName() + "' has already been registered." ); } m_componentHoldersByName.put( key, componentHolder ); } synchronized (m_componentHoldersByPid) { // See if the component declares a specific configuration pid (112.4.4 configuration-pid) List configurationPids = componentHolder.getComponentMetadata().getConfigurationPid(); for ( String configurationPid: configurationPids ) { // Since several components may refer to the same configuration pid, we have to // store the component holder in a Set, in order to be able to lookup every // components from a given pid. Set> set = m_componentHoldersByPid.get( configurationPid ); if ( set == null ) { set = new HashSet<>(); m_componentHoldersByPid.put( configurationPid, set ); } set.add( componentHolder ); } } this.updateChangeCount(); } /** * Returns the component registered under the given name or null * if no component is registered yet. */ public final ComponentHolder getComponentHolder( final Bundle bundle, final String name ) { synchronized ( m_componentHoldersByName ) { return m_componentHoldersByName.get( new ComponentRegistryKey( bundle, name ) ); } } /** * Returns the set of ComponentHolder instances whose configuration pids are matching * the given pid. * @param pid the pid candidate * @return the set of ComponentHolders matching the singleton pid supplied */ public final Collection> getComponentHoldersByPid(TargetedPID targetedPid) { String pid = targetedPid.getServicePid(); Set> componentHoldersUsingPid = new HashSet<>(); synchronized (m_componentHoldersByPid) { Set> set = m_componentHoldersByPid.get(pid); // only return the entry if non-null and not a reservation if (set != null) { for (ComponentHolder holder: set) { Bundle bundle = holder.getActivator().getBundleContext().getBundle(); if (targetedPid.matchesTarget(bundle)) { componentHoldersUsingPid.add( holder ); } } } } return componentHoldersUsingPid; } /** * Returns an array of all values currently stored in the component holders * map. The entries in the array are either String types for component * name reservations or {@link ComponentHolder} instances for actual * holders of components. */ public final List> getComponentHolders() { List> all = new ArrayList<>(); synchronized ( m_componentHoldersByName ) { for (ComponentHolder holder: m_componentHoldersByName.values()) { // Ignore name reservations if (holder != null) { all.add(holder); } } } return all; } public final List> getComponentHolders(Bundle...bundles) { List> all =getComponentHolders(); List> holders = new ArrayList<>(); for ( ComponentHolder holder: all) { ComponentActivator activator = holder.getActivator(); if (activator != null) { try { Bundle holderBundle = activator.getBundleContext().getBundle(); for (Bundle b: bundles) { if (b == holderBundle) { holders.add(holder); } } } catch ( IllegalStateException ise) { // ignore inactive bundles } } } return holders; } /** * Removes the component registered under that name. If no component is * yet registered but the name is reserved, it is unreserved. *

* After calling this method, the name can be reused by other components. */ final void unregisterComponentHolder( final Bundle bundle, final String name ) { unregisterComponentHolder( new ComponentRegistryKey( bundle, name ) ); } /** * Removes the component registered under that name. If no component is * yet registered but the name is reserved, it is unreserved. *

* After calling this method, the name can be reused by other components. */ final void unregisterComponentHolder( final ComponentRegistryKey key ) { ComponentHolder component; synchronized ( m_componentHoldersByName ) { component = m_componentHoldersByName.remove( key ); } if (component != null) { m_logger.log(LogService.LOG_DEBUG, "Unregistering component with pid {0} for bundle {1}", null, component.getComponentMetadata().getConfigurationPid(), key.getBundleId()); synchronized (m_componentHoldersByPid) { List configurationPids = component.getComponentMetadata().getConfigurationPid(); for ( String configurationPid: configurationPids ) { Set> componentsForPid = m_componentHoldersByPid.get( configurationPid ); if ( componentsForPid != null ) { componentsForPid.remove( component ); if ( componentsForPid.size() == 0 ) { m_componentHoldersByPid.remove( configurationPid ); } } } } this.updateChangeCount(); } } //---------- base configuration support /** * Factory method to issue {@link ComponentHolder} instances to manage * components described by the given component metadata. */ public ComponentHolder createComponentHolder( ComponentActivator activator, ComponentMetadata metadata, ComponentLogger logger ) { return new DefaultConfigurableComponentHolder<>(activator, metadata, logger); } static class DefaultConfigurableComponentHolder extends ConfigurableComponentHolder { public DefaultConfigurableComponentHolder(ComponentActivator activator, ComponentMetadata metadata, ComponentLogger logger) { super(activator, metadata, logger); } @Override protected ComponentMethods createComponentMethods() { return new ComponentMethodsImpl<>(); } } //---------- ServiceListener //---------- Helper method private final ThreadLocal>> circularInfos = new ThreadLocal>> () { @Override protected List> initialValue() { return new ArrayList<>(); } }; /** * Track getService calls by service reference. * @param serviceReference * @return true is we have encountered a circular dependency, false otherwise. */ public boolean enterCreate(final ServiceReference serviceReference) { List> info = circularInfos.get(); if (info.contains(serviceReference)) { m_logger.log(LogService.LOG_ERROR, "Circular reference detected trying to get service {0}\n stack of references: {1}", new Exception("stack trace"), serviceReference, new Info(info)); return true; } m_logger.log(LogService.LOG_DEBUG, "getService {0}: stack of references: {1}", null, serviceReference, info); info.add(serviceReference); return false; } private class Info { private final List> info; public Info(List> info) { this.info = info; } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (ServiceReference sr: info) { sb.append("ServiceReference: ").append(sr).append("\n"); List> entries = m_missingDependencies.get(sr); if (entries != null) { for (Entry entry: entries) { sb.append(" Dependency: ").append(entry.getDm()).append("\n"); } } } return sb.toString(); } } public void leaveCreate(final ServiceReference serviceReference) { List> info = circularInfos.get(); if (info != null) { if (!info.isEmpty() && info.iterator().next().equals(serviceReference)) { circularInfos.remove(); } else { info.remove(serviceReference); } } } /** * Schedule late binding of now-available reference on a different thread. The late binding cannot occur on this thread * due to service registry circular reference detection. We cannot wait for the late binding before returning from the initial * getService call because of synchronization in the service registry. * @param serviceReference * @param actor */ public synchronized void missingServicePresent( final ServiceReference serviceReference, ComponentActorThread actor ) { final List> dependencyManagers = m_missingDependencies.remove( serviceReference ); if ( dependencyManagers != null ) { Runnable runnable = new Runnable() { @Override @SuppressWarnings("unchecked") public void run() { for ( Entry entry : dependencyManagers ) { ((DependencyManager)entry.getDm()).invokeBindMethodLate( serviceReference, entry.getTrackingCount() ); } m_logger.log(LogService.LOG_DEBUG, "Ran {0} asynchronously", null, this); } @Override public String toString() { return "Late binding task of reference " + serviceReference + " for dependencyManagers " + dependencyManagers; } } ; m_logger.log(LogService.LOG_DEBUG, "Scheduling runnable {0} asynchronously", null, runnable); actor.schedule( runnable ); } } public synchronized void registerMissingDependency( DependencyManager dependencyManager, ServiceReference serviceReference, int trackingCount ) { //check that the service reference is from scr if ( serviceReference.getProperty( ComponentConstants.COMPONENT_NAME ) == null || serviceReference.getProperty( ComponentConstants.COMPONENT_ID ) == null ) { m_logger.log(LogService.LOG_DEBUG, "Missing service {0} for dependency manager {1} is not a DS service, cannot resolve circular dependency", null, serviceReference, dependencyManager); return; } List> dependencyManagers = m_missingDependencies.get( serviceReference ); if ( dependencyManagers == null ) { dependencyManagers = new ArrayList<>(); m_missingDependencies.put( serviceReference, dependencyManagers ); } dependencyManagers.add( new Entry<>( dependencyManager, trackingCount ) ); m_logger.log(LogService.LOG_DEBUG, "Dependency managers {0} waiting for missing service {1}", null, dependencyManagers, serviceReference); } private static class Entry { private final DependencyManager dm; private final int trackingCount; private Entry( DependencyManager dm, int trackingCount ) { this.dm = dm; this.trackingCount = trackingCount; } public DependencyManager getDm() { return dm; } public int getTrackingCount() { return trackingCount; } @Override public String toString() { return dm.toString() + "@" + trackingCount; } } private final ConcurrentMap bundleToRcsMap = new ConcurrentHashMap<>(); public RegionConfigurationSupport registerRegionConfigurationSupport( ServiceReference reference) { Bundle bundle = reference.getBundle(); if (bundle == null) { return null; } RegionConfigurationSupport trialRcs = new RegionConfigurationSupport(m_logger, reference, bundle) { @Override protected Collection> getComponentHolders(TargetedPID pid) { return ComponentRegistry.this.getComponentHoldersByPid(pid); } }; return registerRegionConfigurationSupport(trialRcs); } public RegionConfigurationSupport registerRegionConfigurationSupport( RegionConfigurationSupport trialRcs) { Long bundleId = trialRcs.getBundleId(); RegionConfigurationSupport existing = null; RegionConfigurationSupport previous = null; while (true) { existing = bundleToRcsMap.putIfAbsent(bundleId, trialRcs); if (existing == null) { trialRcs.start(); return trialRcs; } if (existing == previous) { //the rcs we referenced is still current return existing; } if (existing.reference()) { //existing can still be used previous = existing; } else { //existing was discarded in another thread, start over previous = null; } } } public void unregisterRegionConfigurationSupport( RegionConfigurationSupport rcs) { if (rcs.dereference()) { bundleToRcsMap.remove(rcs.getBundleId()); } } private final AtomicLong changeCount = new AtomicLong(); private volatile Timer changeCountTimer; private final Object changeCountTimerLock = new Object(); private volatile ServiceRegistration registration; public Dictionary getServiceRegistrationProperties() { final Dictionary props = new Hashtable<>(); props.put(PROP_CHANGECOUNT, this.changeCount.get()); return props; } public void setRegistration(final ServiceRegistration reg) { this.registration = reg; } public void updateChangeCount() { if ( registration != null ) { final long count = this.changeCount.incrementAndGet(); final Timer timer; synchronized ( this.changeCountTimerLock ) { if ( this.changeCountTimer == null ) { this.changeCountTimer = new Timer(); } timer = this.changeCountTimer; } try { timer.schedule(new TimerTask() { @Override public void run() { if ( changeCount.get() == count ) { try { registration.setProperties(getServiceRegistrationProperties()); } catch ( final IllegalStateException ise) { // we ignore this as this might happen on shutdown } synchronized ( changeCountTimerLock ) { if ( changeCount.get() == count ) { changeCountTimer.cancel(); changeCountTimer = null; } } } } }, m_configuration.serviceChangecountTimeout()); } catch (Exception e) { m_logger.log(LogService.LOG_WARNING, "Service changecount Timer for {0} had a problem", e, registration.getReference()); } } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/ComponentCommands.java0000644000175000017500000007044713675426212026340 0ustar sudipsudip/* * 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 java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.felix.scr.impl.manager.ScrConfiguration; import org.apache.felix.scr.info.ScrInfo; import org.apache.felix.service.command.Converter; import org.apache.felix.service.command.Descriptor; 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.framework.dto.ServiceReferenceDTO; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWiring; import org.osgi.service.component.ComponentConstants; import org.osgi.service.component.ComponentFactory; 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; import org.osgi.service.component.runtime.dto.UnsatisfiedReferenceDTO; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; public class ComponentCommands implements ServiceTrackerCustomizer> { private static final String INDENT_1 = " "; private static final String INDENT_2 = INDENT_1 + INDENT_1; private final BundleContext context; private final ServiceComponentRuntime scr; private final ScrConfiguration scrConfig; private final ServiceTracker> gogoRuntimeTracker; private final Comparator configDtoComparator = new Comparator() { @Override public int compare(ComponentConfigurationDTO o1, ComponentConfigurationDTO o2) { long diff = o1.id - o2.id; return diff == 0L ? 0 : (int) (diff / Math.abs(diff)); } }; private final Comparator serviceRefDtoComparator = new Comparator() { @Override public int compare(ServiceReferenceDTO o1, ServiceReferenceDTO o2) { long diff = o1.id - o2.id; return diff == 0L ? 0 : (int) (diff / Math.abs(diff)); } }; private ServiceRegistration commandsReg = null; private ServiceRegistration scrInfoReg = null; synchronized void register() { if (commandsReg != null) { throw new IllegalStateException("Component Commands already registered"); } Dictionary svcProps; svcProps = new Hashtable<>(); svcProps.put("osgi.command.scope", "scr"); svcProps.put("osgi.command.function", new String[] { "config", "disable", "enable", "info", "list" }); svcProps.put(Constants.SERVICE_DESCRIPTION, "SCR Gogo Shell Support"); svcProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); commandsReg = context.registerService(ComponentCommands.class, this, svcProps); gogoRuntimeTracker.open(true); } synchronized void unregister() { gogoRuntimeTracker.close(); safeUnregister(commandsReg); safeUnregister(scrInfoReg); } public synchronized void updateProvideScrInfoService(boolean register) { if (register) { if (scrInfoReg == null) { Dictionary svcProps = new Hashtable<>(); svcProps.put(Constants.SERVICE_DESCRIPTION, "SCR Info Service"); svcProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); scrInfoReg = context.registerService(ScrInfo.class, new ComponentCommandsScrInfo(this, context), svcProps); } } else { safeUnregister(scrInfoReg); scrInfoReg = null; } } protected ComponentCommands(BundleContext context, ServiceComponentRuntime scr, ScrConfiguration scrConfig) { this.context = context; this.scr = scr; this.scrConfig = scrConfig; this.gogoRuntimeTracker = new ServiceTracker<>(context, "org.apache.felix.service.command.CommandProcessor", this); } @Descriptor("List all components") public ComponentDescriptionDTO[] list() { ComponentDescriptionDTO[] result = scr.getComponentDescriptionDTOs().toArray(new ComponentDescriptionDTO[0]); Arrays.sort(result, new Comparator() { @Override public int compare(ComponentDescriptionDTO c1, ComponentDescriptionDTO c2) { return Long.compare(c1.bundle.id, c2.bundle.id); } }); return result; } @Descriptor("List components of a specific bundle") public ComponentDescriptionDTO[] list(@Descriptor("ID of the bundle") long bundleId) { Bundle bundle = context.getBundle(bundleId); return bundle != null ? scr.getComponentDescriptionDTOs(bundle).toArray(new ComponentDescriptionDTO[0]) : null; } private List findComponents(String name) { String lowerName = name.toLowerCase(); List matches = new LinkedList<>(); for (ComponentDescriptionDTO dto : scr.getComponentDescriptionDTOs()) { if (dto.name.equalsIgnoreCase(name)) { // Exact match, return only this component. return Collections.singletonList(dto); } if (dto.name.toLowerCase().contains(lowerName)) matches.add(dto); } return matches; } @Descriptor("Dump information of a component") public ComponentDescriptionDTO info(@Descriptor("Name of the component") String name) { List matches = findComponents(name); if (matches.isEmpty()) { throw new IllegalArgumentException(MessageFormat.format("No component description matching \"{0}\".", name)); } else if (matches.size() > 1) { StringBuilder partialMatchesStr = new StringBuilder(); for (Iterator iter = matches.iterator(); iter.hasNext(); ) { partialMatchesStr.append(iter.next().name); if (iter.hasNext()) partialMatchesStr.append(", "); } throw new IllegalArgumentException(MessageFormat.format("Multiple components matching \"{0}\": [{1}]", name, partialMatchesStr)); } return matches.get(0); } @Descriptor("Dump information of a component configuration") public ComponentConfigurationDTO info(@Descriptor("ID of the component configuration") long id) { for (ComponentDescriptionDTO descDto : scr.getComponentDescriptionDTOs()) { for (ComponentConfigurationDTO configDto : scr.getComponentConfigurationDTOs(descDto)) { if (configDto.id == id) return configDto; } } return null; } @Descriptor("Enable a disabled component") public boolean enable(@Descriptor("Name of the component") final String name) { boolean changed = false; for (ComponentDescriptionDTO comp : findComponents(name)) { if (!scr.isComponentEnabled(comp)) { scr.enableComponent(comp); changed = true; } } return changed; } @Descriptor("Disable an enabled component") public boolean disable(@Descriptor("Name of the component") final String name) { boolean changed = false; for (ComponentDescriptionDTO comp : findComponents(name)) { if (scr.isComponentEnabled(comp)) { scr.disableComponent(comp); changed = true; } } return changed; } @SuppressWarnings("deprecation") @Descriptor("Show the current SCR configuration") public String config() { Map out = new LinkedHashMap<>(); out.put("Log Level", Integer.toString(scrConfig.getLogLevel())); out.put("Obsolete Component Factory with Factory Configuration", Boolean.toString(scrConfig.isFactoryEnabled())); out.put("Keep instances with no references", scrConfig.keepInstances() ? "Supported" : "Unsupported"); out.put("Lock timeout ms", Long.toString(scrConfig.lockTimeout())); out.put("Stop timeout ms", Long.toString(scrConfig.stopTimeout())); out.put("Global extender", Boolean.toString(scrConfig.globalExtender())); out.put("Info Service registered", scrConfig.infoAsService() ? "Supported" : "Unsupported"); StringBuilder builder = new StringBuilder(); printColumnsAligned("SCR Configuration", out, '=', builder); return builder.toString(); } public Object convert(Class desiredType, Object in) throws Exception { return null; } public CharSequence format(Object target, int level) throws Exception { final CharSequence result; if (target instanceof ComponentDescriptionDTO[]) { result = format((ComponentDescriptionDTO[]) target, level); } else if (target instanceof ComponentDescriptionDTO) { result = format((ComponentDescriptionDTO) target, level); } else if (target instanceof ComponentConfigurationDTO) { result = format((ComponentConfigurationDTO) target, level); } else { result = null; } return result; } CharSequence format(ComponentDescriptionDTO[] dtoArray, int level) throws Exception { StringBuilder sb = new StringBuilder(); if (dtoArray == null || dtoArray.length == 0) { sb.append("No component descriptions found"); } else { for (int i = 0; i < dtoArray.length; i++) { if (i > 0) sb.append('\n'); sb.append(format(dtoArray[i], Converter.LINE)); } } return sb; } CharSequence format(ComponentDescriptionDTO dto, int level) throws Exception { final StringBuilder builder = new StringBuilder(); // Get the child ComponentConfigurationDTOs and sort by id field. final List children; Collection childrenTmp = scr.getComponentConfigurationDTOs(dto); if (childrenTmp == null) { children = Collections.emptyList(); } else { children = new ArrayList<>(childrenTmp); Collections.sort(children, configDtoComparator); } switch (level) { case Converter.LINE: builder.append(MessageFormat.format("{0} in bundle {1} ({2}:{3}) {4}, {5,choice,0#0 instances|1#1 instance|1<{5} instances}.", dto.name, dto.bundle.id, dto.bundle.symbolicName, dto.bundle.version, dto.defaultEnabled ? "enabled" : "disabled", children.size() )); for (ComponentConfigurationDTO child : children) builder.append("\n").append(INDENT_2).append(format(child, Converter.LINE)); break; case Converter.INSPECT: printComponentDescriptionAndConfigs(dto, children.toArray(new ComponentConfigurationDTO[0]), builder); break; case Converter.PART: break; } return builder; } CharSequence format(ComponentConfigurationDTO dto, int level) throws Exception { final StringBuilder builder = new StringBuilder(); switch (level) { case Converter.INSPECT: printComponentDescriptionAndConfigs(dto.description, new ComponentConfigurationDTO[]{dto}, builder); break; case Converter.LINE: builder.append("Id: ").append(dto.id); builder.append(", ").append("State:").append(stateToString(dto.state)); String[] pids = getStringArray(dto.properties, Constants.SERVICE_PID, null); if (pids != null && pids.length > 0) { builder.append(", ").append("PID(s): ").append(Arrays.toString(pids)); } break; case Converter.PART: break; } return builder; } void printComponentDescriptionAndConfigs(ComponentDescriptionDTO descDto, ComponentConfigurationDTO[] configs, StringBuilder builder) { final Map out = new LinkedHashMap<>(); // Component Description out.put("Class", descDto.implementationClass); out.put("Bundle", String.format("%d (%s:%s)", descDto.bundle.id, descDto.bundle.symbolicName, descDto.bundle.version)); out.put("Enabled", Boolean.toString(descDto.defaultEnabled)); out.put("Immediate", Boolean.toString(descDto.immediate)); out.put("Services", arrayToString(descDto.serviceInterfaces)); if (descDto.scope != null) { out.put("Scope", descDto.scope); } out.put("Config PID(s)", String.format("%s, Policy: %s", arrayToString(descDto.configurationPid), descDto.configurationPolicy)); out.put("Base Props", printProperties(descDto.properties, INDENT_1)); if (descDto.factory != null) { out.put("Factory", descDto.factory); try { ServiceReference[] serviceRefs = context.getAllServiceReferences(ComponentFactory.class.getName(), String.format("(&(%s=%s)(%s=%d))", ComponentConstants.COMPONENT_NAME, descDto.name, Constants.SERVICE_BUNDLEID, descDto.bundle.id)); if (serviceRefs != null && serviceRefs.length > 0) { out.put("Factory Service", printPublishedServices(serviceRefs)); } } catch (InvalidSyntaxException e) { // shouldn't happen } } printColumnsAligned(String.format("Component Description: %s", descDto.name), out, '=', builder); if (configs != null) for (ComponentConfigurationDTO configDto : configs) { out.clear(); // Blank line separator builder.append("\n\n"); // Inspect configuration DTO String title = String.format("Component Configuration Id: %d", configDto.id); out.put("State", stateToString(configDto.state)); // Print service registration try { ServiceReference[] serviceRefs = context.getAllServiceReferences(null, String.format("(%s=%d)", ComponentConstants.COMPONENT_ID, configDto.id)); if (serviceRefs != null && serviceRefs.length > 0) { out.put("Service", printPublishedServices(serviceRefs)); } } catch (InvalidSyntaxException e) { // Shouldn't happen... } // Print Configuration Properties out.put("Config Props", printProperties(configDto.properties, INDENT_1)); // Print References out.put("References", printServiceReferences(configDto.satisfiedReferences, configDto.unsatisfiedReferences, descDto.references)); // Print Failure if (configDto.failure != null) { out.put("Failure", configDto.failure); } printColumnsAligned(title, out, '-', builder); } } String printPublishedServices(ServiceReference[] serviceRefs) { StringBuilder sb = new StringBuilder(); if (serviceRefs.length > 1) { sb.append("(total ").append(serviceRefs.length).append(')'); sb.append('\n').append(INDENT_1); } for (ServiceReference serviceRef : serviceRefs) { sb.append(serviceRef.getProperty(Constants.SERVICE_ID)); sb.append(' ').append(Arrays.toString((String[]) serviceRef.getProperty(Constants.OBJECTCLASS))); Bundle[] consumers = serviceRef.getUsingBundles(); if (consumers != null) for (Bundle consumer : consumers) { sb.append("\n").append(INDENT_2); sb.append(String.format("Used by bundle %d (%s:%s)", consumer.getBundleId(), consumer.getSymbolicName(), consumer.getVersion())); } } return sb.toString(); } private String arrayToString(String[] array) { return array == null || array.length == 0 ? "<>" : Arrays.toString(array); } static final String stateToString(int state) { final String string; switch (state) { case ComponentConfigurationDTO.ACTIVE: string = "ACTIVE"; break; case ComponentConfigurationDTO.SATISFIED: string = "SATISFIED"; break; case ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION: string = "UNSATISFIED CONFIGURATION"; break; case ComponentConfigurationDTO.UNSATISFIED_REFERENCE: string = "UNSATISFIED REFERENCE"; break; case ComponentConfigurationDTO.FAILED_ACTIVATION: string = "FAILED ACTIVATION"; break; default: string = String.format("<>", state); } return string; } static String printProperties(Map props, String indent) { StringBuilder builder = new StringBuilder(); int size = props.size(); builder.append('(').append(Integer.toString(size)).append(' ').append(size == 1 ? "entry" : "entries").append(')'); if (size > 0) { final SortedMap sortedMap = new TreeMap<>(props); for (Map.Entry e : sortedMap.entrySet()) { builder.append('\n').append(indent); final Object value = e.getValue(); final String typeName; final String valueStr; if (value == null) { typeName = valueStr = "null"; } else { typeName = value.getClass().getSimpleName(); if (value instanceof int[]) valueStr = Arrays.toString((int[]) value); else if (value instanceof long[]) valueStr = Arrays.toString((long[]) value); else if (value instanceof byte[]) valueStr = Arrays.toString((byte[]) value); else if (value instanceof short[]) valueStr = Arrays.toString((short[]) value); else if (value instanceof byte[]) valueStr = Arrays.toString((byte[]) value); else if (value instanceof char[]) valueStr = Arrays.toString((char[]) value); else if (value instanceof boolean[]) valueStr = Arrays.toString((boolean[]) value); else if (value instanceof float[]) valueStr = Arrays.toString((boolean[]) value); else if (value instanceof double[]) valueStr = Arrays.toString((boolean[]) value); else if (value instanceof Object[]) valueStr = Arrays.deepToString((Object[]) value); else valueStr = value.toString(); } builder.append(String.format("%s<%s> = %s", e.getKey(), typeName, valueStr)); } } return builder.toString(); } String printServiceReferences(SatisfiedReferenceDTO[] satisfiedReferences, UnsatisfiedReferenceDTO[] unsatisfiedReferences, ReferenceDTO[] references) { StringBuilder builder = new StringBuilder(); final Map refDtoMap = new HashMap<>(); if (references != null) { for (ReferenceDTO refDto : references) refDtoMap.put(refDto.name, refDto); } int refCount = (satisfiedReferences != null ? satisfiedReferences.length : 0) + (unsatisfiedReferences != null ? unsatisfiedReferences.length : 0); builder.append("(total ").append(Integer.toString(refCount)).append(")"); if (unsatisfiedReferences != null) { for (UnsatisfiedReferenceDTO refDto : unsatisfiedReferences) printServiceReference(refDtoMap.get(refDto.name), "UNSATISFIED", null, builder); } if (satisfiedReferences != null) { for (SatisfiedReferenceDTO refDto : satisfiedReferences) printServiceReference(refDtoMap.get(refDto.name), "SATISFIED", refDto.boundServices != null ? refDto.boundServices : new ServiceReferenceDTO[0], builder); } return builder.toString(); } void printServiceReference(ReferenceDTO reference, String state, ServiceReferenceDTO[] bindings, StringBuilder builder) { StringBuilder policyWithOption = new StringBuilder().append(reference.policy); if (!"reluctant".equals(reference.policyOption)) policyWithOption.append('+').append(reference.policyOption); builder.append(String.format("%n" + INDENT_1 + "- %s: %s %s %s %s", reference.name, reference.interfaceName, state, reference.cardinality, policyWithOption)); builder.append(String.format("%n" + INDENT_1 + " target=%s scope=%s", reference.target == null ? "(*)" : reference.target, reference.scope == null ? "bundle" : reference.scope)); if (reference.collectionType != null) { builder.append(" collectionType=").append(reference.collectionType); } if (bindings != null) { Arrays.sort(bindings, serviceRefDtoComparator); builder.append(MessageFormat.format(" {0,choice,0#(no active bindings)|1#(1 binding):|1<({0} bindings):}", bindings.length)); for (ServiceReferenceDTO svcDto : bindings) { Bundle provider = context.getBundle(svcDto.bundle); builder.append(String.format("%n" + INDENT_1 + " * Bound to [%d] from bundle %d (%s:%s)", svcDto.id, svcDto.bundle, provider.getSymbolicName(), provider.getVersion())); } } } static void printColumnsAligned(String title, Map properties, char underlineChar, StringBuilder builder) { builder.append(title); // Generate the title underline char[] carray = new char[title.length()]; Arrays.fill(carray, underlineChar); builder.append('\n'); builder.append(carray); int widestKey = 0; for (String key : properties.keySet()) { widestKey = Math.max(widestKey, key.length()); } for (Map.Entry e : properties.entrySet()) { String key = e.getKey(); int padLength = widestKey - key.length(); char[] padding = new char[padLength]; Arrays.fill(padding, ' '); builder.append('\n'); builder.append(key).append(": "); builder.append(padding); builder.append(e.getValue()); } } private static String[] getStringArray(Map map, String name, String[] defaultValue) throws IllegalArgumentException { Object o = map.get(name); if (o instanceof String) { return new String[]{(String) o}; } else if (o instanceof String[]) { return (String[]) o; } else if (o instanceof Collection) { Collection c = (Collection) o; if (c.isEmpty()) { return new String[0]; } else { String[] a = new String[c.size()]; Iterator iter = c.iterator(); for (int i = 0; i < a.length; i++) { Object elem = iter.next(); if (!(elem instanceof String)) throw new IllegalArgumentException(String.format("Collection value for field '%s' contains non-String element at index %d.", name, i)); a[i] = (String) elem; } return a; } } else if (o == null) { return defaultValue; } else { throw new IllegalArgumentException(String.format("Value for field '%s' is not a String, String-array or Collection of String. Actual type was %s.", name, o.getClass().getName())); } } private void safeUnregister(ServiceRegistration registration) { try { if (registration != null) registration.unregister(); } catch (Exception e) { // ignore } } @Override public ServiceRegistration addingService(ServiceReference reference) { Bundle b = reference.getBundle(); BundleRevision rev = b == null ? null : b.adapt(BundleRevision.class); if (rev != null) { Object converter = createConverter(b); if (converter != null) { Dictionary svcProps = new Hashtable<>(); svcProps.put("osgi.converter.classes", new String[] { ComponentDescriptionDTO.class.getName(), ComponentConfigurationDTO.class.getName() }); svcProps.put(Constants.SERVICE_DESCRIPTION, "SCR Runtime DTO Converter"); svcProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); return b.getBundleContext().registerService("org.apache.felix.service.command.Converter", converter, svcProps); } } return null; } private Object createConverter(Bundle bundle) { BundleWiring wiring = bundle.adapt(BundleWiring.class); if (wiring != null) { ClassLoader cl = wiring.getClassLoader(); if (cl != null) { try { Class[] types = new Class[] {cl.loadClass("org.apache.felix.service.command.Converter")}; return Proxy.newProxyInstance(cl, types, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("convert".equals(method.getName())) { return convert((Class) args[0], args[1]); } if ("format".equals(method.getName())) { return format(args[0], (int) args[1]); } return method.invoke(this, args); } }); } catch (ClassNotFoundException e) { } } } return null; } @Override public void modifiedService(ServiceReference reference, ServiceRegistration reg) { // nothing } @Override public void removedService(ServiceReference reference, ServiceRegistration reg) { safeUnregister(reg); } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/runtime/0000755000175000017500000000000013675426212023520 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java0000644000175000017500000004512513675426212032043 0ustar sudipsudip/* * 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.runtime; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.felix.scr.impl.ComponentRegistry; import org.apache.felix.scr.impl.manager.ComponentHolder; import org.apache.felix.scr.impl.manager.ComponentManager; import org.apache.felix.scr.impl.manager.ReferenceManager; import org.apache.felix.scr.impl.metadata.ComponentMetadata; import org.apache.felix.scr.impl.metadata.ReferenceMetadata; import org.osgi.dto.DTO; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.Constants; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.dto.BundleDTO; import org.osgi.framework.dto.ServiceReferenceDTO; 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; import org.osgi.service.component.runtime.dto.UnsatisfiedReferenceDTO; import org.osgi.util.promise.Promise; import org.osgi.util.promise.Promises; public class ServiceComponentRuntimeImpl implements ServiceComponentRuntime, ServiceListener, BundleListener { private static final String[] EMPTY = {}; private final BundleContext context; private final ComponentRegistry componentRegistry; private volatile SoftReference> dtoCache = new SoftReference<>(new ConcurrentHashMap()); public ServiceComponentRuntimeImpl(final BundleContext context, final ComponentRegistry componentRegistry) { this.context = context; this.componentRegistry = componentRegistry; this.context.addBundleListener(this); this.context.addServiceListener(this); } /** * @see org.osgi.service.component.runtime.ServiceComponentRuntime#getComponentDescriptionDTOs(org.osgi.framework.Bundle[]) */ @Override public Collection getComponentDescriptionDTOs(Bundle... bundles) { List> holders; if (bundles == null || bundles.length == 0) { holders = componentRegistry.getComponentHolders(); } else { holders = componentRegistry.getComponentHolders(bundles); } List result = new ArrayList<>(holders.size()); for (ComponentHolder holder: holders) { ComponentDescriptionDTO dto = holderToDescription(holder); if ( dto != null ) { result.add(dto); } } return result; } /** * @see org.osgi.service.component.runtime.ServiceComponentRuntime#getComponentDescriptionDTO(org.osgi.framework.Bundle, java.lang.String) */ @Override public ComponentDescriptionDTO getComponentDescriptionDTO(Bundle bundle, String name) { ComponentHolder holder = componentRegistry.getComponentHolder(bundle, name); if ( holder != null ) { return holderToDescription(holder); } else { return null; } } /** * @see org.osgi.service.component.runtime.ServiceComponentRuntime#getComponentConfigurationDTOs(org.osgi.service.component.runtime.dto.ComponentDescriptionDTO) */ @Override public Collection getComponentConfigurationDTOs(ComponentDescriptionDTO description) { if ( description == null) { return Collections.emptyList(); } try { ComponentHolder holder = getHolderFromDescription( description); // Get a fully filled out valid description DTO description = holderToDescription(holder); if ( description == null) { return Collections.emptyList(); } List> managers = holder.getComponents(); List result = new ArrayList<>(managers.size()); for (ComponentManager manager: managers) { result.add(managerToConfiguration(manager, description)); } return result; } catch ( IllegalStateException ise) { return Collections.emptyList(); } } /** * @see org.osgi.service.component.runtime.ServiceComponentRuntime#isComponentEnabled(org.osgi.service.component.runtime.dto.ComponentDescriptionDTO) */ @Override public boolean isComponentEnabled(ComponentDescriptionDTO description) { try { ComponentHolder holder = getHolderFromDescription( description); return holder.isEnabled(); } catch ( IllegalStateException ise) { return false; } } /** * @see org.osgi.service.component.runtime.ServiceComponentRuntime#enableComponent(org.osgi.service.component.runtime.dto.ComponentDescriptionDTO) */ @Override public Promise enableComponent(ComponentDescriptionDTO description) { try { final ComponentHolder holder = getHolderFromDescription( description); final boolean doUpdate = !holder.isEnabled(); final Promise result = holder.enableComponents(true); if ( doUpdate ) { this.componentRegistry.updateChangeCount(); } return result; } catch ( IllegalStateException ise) { return Promises.failed(ise); } } /** * @see org.osgi.service.component.runtime.ServiceComponentRuntime#disableComponent(org.osgi.service.component.runtime.dto.ComponentDescriptionDTO) */ @Override public Promise disableComponent(ComponentDescriptionDTO description) { try { final ComponentHolder holder = getHolderFromDescription( description); final boolean doUpdate = holder.isEnabled(); final Promise result = holder.disableComponents(true); //synchronous if ( doUpdate ) { this.componentRegistry.updateChangeCount(); } return result; } catch ( IllegalStateException ise) { return Promises.failed(ise); } } private ComponentConfigurationDTO managerToConfiguration(final ComponentManager manager, final ComponentDescriptionDTO description) { final ComponentConfigurationDTO dto = new ComponentConfigurationDTO(); dto.satisfiedReferences = satisfiedRefManagersToDTO(manager.getReferenceManagers()); dto.unsatisfiedReferences = unsatisfiedRefManagersToDTO(manager.getReferenceManagers()); dto.description = description; dto.id = manager.getId(); dto.properties = new HashMap<>(manager.getProperties());//TODO deep copy? dto.state = manager.getSpecState(); // DS 1.4 if ( dto.state == ComponentConfigurationDTO.ACTIVE || dto.state == ComponentConfigurationDTO.SATISFIED ) { dto.service = serviceReferenceToDTO(manager.getRegisteredServiceReference()); } if ( manager.getFailureReason() != null ) { dto.state = ComponentConfigurationDTO.FAILED_ACTIVATION; dto.failure = manager.getFailureReason(); } return dto; } private SatisfiedReferenceDTO[] satisfiedRefManagersToDTO(List> referenceManagers) { List dtos = new ArrayList<>(); for (ReferenceManager ref: referenceManagers) { if (ref.isSatisfied()) { SatisfiedReferenceDTO dto = new SatisfiedReferenceDTO(); dto.name = ref.getName(); dto.target = ref.getTarget(); List> serviceRefs = ref.getServiceReferences(); ServiceReferenceDTO[] srDTOs = new ServiceReferenceDTO[serviceRefs.size()]; int j = 0; for (ServiceReference serviceRef : serviceRefs) { ServiceReferenceDTO srefDTO = serviceReferenceToDTO(serviceRef); if (srefDTO != null) srDTOs[j++] = srefDTO; } dto.boundServices = srDTOs; dtos.add(dto); } } return dtos.toArray( new SatisfiedReferenceDTO[dtos.size()] ); } private UnsatisfiedReferenceDTO[] unsatisfiedRefManagersToDTO(List> referenceManagers) { List dtos = new ArrayList<>(); for (ReferenceManager ref: referenceManagers) { if (!ref.isSatisfied()) { UnsatisfiedReferenceDTO dto = new UnsatisfiedReferenceDTO(); dto.name = ref.getName(); dto.target = ref.getTarget(); List> serviceRefs = ref.getServiceReferences(); ServiceReferenceDTO[] srDTOs = new ServiceReferenceDTO[serviceRefs.size()]; int j = 0; for (ServiceReference serviceRef : serviceRefs) { ServiceReferenceDTO srefDTO = serviceReferenceToDTO(serviceRef); if (srefDTO != null) srDTOs[j++] = srefDTO; } dto.targetServices = srDTOs; dtos.add(dto); } } return dtos.toArray( new UnsatisfiedReferenceDTO[dtos.size()] ); } private ServiceReferenceDTO serviceReferenceToDTO( ServiceReference serviceRef) { if (serviceRef == null) return null; final Bundle bundle = serviceRef.getBundle(); if (bundle == null) { return null; } final long bundleId = bundle.getBundleId(); ConcurrentHashMap cache = dtoCache.get(); if (cache == null) { cache = new ConcurrentHashMap<>(); dtoCache = new SoftReference<>(cache); } ServiceReferenceDTO[] dtos = cache.get(bundleId); if (dtos == null) { dtos = bundle.adapt(ServiceReferenceDTO[].class); if (dtos == null) { dtos = new ServiceReferenceDTO[0]; } cache.put(bundleId, dtos); } final long id = (Long) serviceRef.getProperty(Constants.SERVICE_ID); for (final ServiceReferenceDTO dto : dtos) { if (dto.id == id) { // we need to return a copy! final ServiceReferenceDTO result = new ServiceReferenceDTO(); result.bundle = dto.bundle; result.id = dto.id; result.properties = new HashMap<>(dto.properties); if (dto.usingBundles != null) { result.usingBundles = new long[dto.usingBundles.length]; if (dto.usingBundles.length > 0) { System.arraycopy(dto.usingBundles, 0, result.usingBundles, 0, result.usingBundles.length); } } return result; } } return null; } /** * Return the component holder * @param description Component description DTO * @return The component holder * @throws IllegalStateException If the bundle is not active anymore */ private ComponentHolder getHolderFromDescription(ComponentDescriptionDTO description) { if (description.bundle == null) { throw new IllegalArgumentException("No bundle supplied in ComponentDescriptionDTO named " + description.name); } long bundleId = description.bundle.id; Bundle b = context.getBundle(bundleId); String name = description.name; return componentRegistry.getComponentHolder(b, name); } private ComponentDescriptionDTO holderToDescription( ComponentHolder holder ) { ComponentDescriptionDTO dto = new ComponentDescriptionDTO(); ComponentMetadata m = holder.getComponentMetadata(); dto.activate = m.getActivate(); dto.bundle = bundleToDTO(holder.getActivator().getBundleContext()); // immediately return if bundle is not active anymore if ( dto.bundle == null ) { return null; } dto.configurationPid = m.getConfigurationPid().toArray(new String[m.getConfigurationPid().size()]); dto.configurationPolicy = m.getConfigurationPolicy(); dto.deactivate = m.getDeactivate(); dto.defaultEnabled = m.isEnabled(); dto.factory = m.getFactoryIdentifier(); dto.immediate = m.isImmediate(); dto.implementationClass = m.getImplementationClassName(); dto.modified = m.getModified(); dto.name = m.getName(); dto.properties = deepCopy(m.getProperties()); dto.references = refsToDTO(m.getDependencies()); dto.scope = m.getServiceMetadata() == null? null: m.getServiceMetadata().getScope().name(); dto.serviceInterfaces = m.getServiceMetadata() == null? EMPTY: m.getServiceMetadata().getProvides(); // DS 1.4 dto.factoryProperties = m.isFactory() ? m.getFactoryProperties() : null; dto.activationFields = (m.getActivationFields() == null ? EMPTY : m.getActivationFields().toArray(new String[m.getActivationFields().size()])); dto.init = m.getNumberOfConstructorParameters(); return dto; } private Map deepCopy(Map source) { HashMap result = new HashMap<>(source.size()); for (Map.Entry entry: source.entrySet()) { result.put(entry.getKey(), convert(entry.getValue())); } return result; } Object convert(Object source) { if (source.getClass().isArray()) { Class type = source.getClass().getComponentType(); if (checkType(type)) { return source; } return String.valueOf(source); /* array copy code in case it turns out to be needed int length = Array.getLength(source); Object copy = Array.newInstance(type, length); for (int i = 0; i type) { if (type == String.class) return true; if (type == Boolean.class) return true; if (Number.class.isAssignableFrom(type)) return true; if (DTO.class.isAssignableFrom(type)) return true; return false; } private ReferenceDTO[] refsToDTO(List dependencies) { ReferenceDTO[] dtos = new ReferenceDTO[dependencies.size()]; int i = 0; for (ReferenceMetadata r: dependencies) { ReferenceDTO dto = new ReferenceDTO(); dto.bind = r.getBind(); dto.cardinality = r.getCardinality(); dto.field = r.getField(); dto.fieldOption = r.getFieldOption(); dto.interfaceName = r.getInterface(); dto.name = r.getName(); dto.policy = r.getPolicy(); dto.policyOption = r.getPolicyOption(); dto.scope = r.getScope().name(); dto.target = r.getTarget(); dto.unbind = r.getUnbind(); dto.updated = r.getUpdated(); // DS 1.4 dto.parameter = r.getParameterIndex(); dto.collectionType = r.getFieldCollectionType(); dtos[i++] = dto; } return dtos; } private BundleDTO bundleToDTO(BundleContext bundleContext) { if (bundleContext == null) { return null; } try { Bundle bundle = bundleContext.getBundle(); if (bundle == null) { return null; } BundleDTO b = new BundleDTO(); b.id = bundle.getBundleId(); b.lastModified = bundle.getLastModified(); b.state = bundle.getState(); b.symbolicName = bundle.getSymbolicName(); b.version = bundle.getVersion().toString(); return b; } catch (IllegalStateException e) { return null; } } @Override public void bundleChanged(final BundleEvent event) { ConcurrentHashMap cache = dtoCache.get(); if (cache != null) { cache.remove(event.getBundle().getBundleId()); } } @Override public void serviceChanged(final ServiceEvent event) { if (event.getServiceReference() != null) { ConcurrentHashMap cache = dtoCache.get(); if (cache != null) { // using bundle id property incase the service has gotten unregistered // before we could get the bundle object cache.remove(event.getServiceReference().getProperty(Constants.SERVICE_BUNDLEID)); } } } } felix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/manager/0000755000175000017500000000000013675426212023447 5ustar sudipsudipfelix-scr-2.1.20/src/main/java/org/apache/felix/scr/impl/manager/ConfigurableComponentHolder.java0000644000175000017500000007615713675426212031753 0ustar sudipsudip/* * 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.manager; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.felix.scr.impl.inject.ComponentMethods; import org.apache.felix.scr.impl.logger.ComponentLogger; import org.apache.felix.scr.impl.metadata.ComponentMetadata; import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope; import org.apache.felix.scr.impl.metadata.TargetedPID; import org.osgi.framework.Constants; import org.osgi.service.component.ComponentConstants; import org.osgi.service.log.LogService; import org.osgi.util.promise.Deferred; import org.osgi.util.promise.Promise; import org.osgi.util.promise.Promises; /** * The ConfigurableComponentHolder class is a * {@link ComponentHolder} for automatically configured components instances * that may or may not be configured through Config Admin. *

* The holder copes with three situations: *

    *
  • No configuration is available for the held component. That is there is * no configuration whose service.pid or * service.factoryPid equals the component name.
  • *
  • A singleton configuration is available whose service.pid * equals the component name.
  • *
  • One or more factory configurations exist whose * service.factoryPid equals the component name.
  • *
*/ public abstract class ConfigurableComponentHolder implements ComponentHolder, ComponentContainer { /** * The activator owning the per-bundle components */ private final ComponentActivator m_activator; /** * The {@link ComponentMetadata} describing the held component(s) */ private final ComponentMetadata m_componentMetadata; /** the targeted pids corresponding to the pids specified in the config metadata, except possibly for the single * factory pid */ private final TargetedPID[] m_targetedPids; private final Long[] m_changeCount; private final Map m_factoryChangeCount = new HashMap<>(); /** * the index in metadata.getConfigurationPid() of the base factory pid, if any. Each component created from a factory configuration * might have a different targeted pid. */ private volatile Integer m_factoryPidIndex; /** * the non-factory configurations shared between all instances. */ private final Dictionary[] m_configurations; /** * the factory configurations indexed by pid (which cannot be a TargetedPID since it's generated by CA). We have to track these since * other required configs may not yet be present so we can't create the component manager yet. */ private final Map> m_factoryConfigurations = new HashMap<>(); /** * Each factory config may be from a different TargetedPID (sharing the same base service pid, but with different level of detail) */ private final Map m_factoryTargetedPids = new HashMap<>(); /** * A map of components configured with factory configuration. The indices * are the PIDs (service.pid) of the configuration objects. * The values are the {@link SingleComponentManager component instances} * created on behalf of the configurations. */ private final Map> m_components; /** * The special component used if there is no configuration or a singleton * configuration. This field is only null once all components * held by this holder have been disposed of by * {@link #disposeComponents(int)} and is first created in the constructor. * As factory configurations are provided this instance may be configured * or "deconfigured". *

* Expected invariants: *