You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2017/11/09 10:20:58 UTC
svn commit: r1814712 - in /felix/trunk/osgi-r7/scr: ./
src/main/java/org/apache/felix/scr/impl/
Author: cziegeler
Date: Thu Nov 9 10:20:57 2017
New Revision: 1814712
URL: http://svn.apache.org/viewvc?rev=1814712&view=rev
Log:
FELIX-5739 : Strange behaviour with Lazy-ActivationPolicy and autostart
Added:
felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java (with props)
Modified:
felix/trunk/osgi-r7/scr/bnd.bnd
felix/trunk/osgi-r7/scr/pom.xml
felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java
Modified: felix/trunk/osgi-r7/scr/bnd.bnd
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/scr/bnd.bnd?rev=1814712&r1=1814711&r2=1814712&view=diff
==============================================================================
--- felix/trunk/osgi-r7/scr/bnd.bnd (original)
+++ felix/trunk/osgi-r7/scr/bnd.bnd Thu Nov 9 10:20:57 2017
@@ -21,8 +21,7 @@ Export-Package: org.apache.felix.scr.com
org.osgi.util.function;version=1.0, \
org.osgi.util.promise;version=1.0
-Private-Package: org.apache.felix.scr.impl.*, \
- org.apache.felix.utils.extender
+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.
Modified: felix/trunk/osgi-r7/scr/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/scr/pom.xml?rev=1814712&r1=1814711&r2=1814712&view=diff
==============================================================================
--- felix/trunk/osgi-r7/scr/pom.xml (original)
+++ felix/trunk/osgi-r7/scr/pom.xml Thu Nov 9 10:20:57 2017
@@ -106,6 +106,12 @@
-->
<dependency>
<groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.log</artifactId>
+ <version>1.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
<artifactId>org.osgi.service.metatype</artifactId>
<version>1.3.0</version>
<scope>provided</scope>
@@ -123,12 +129,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.utils</artifactId>
- <version>1.8.6</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>${project.groupId}</groupId>
<artifactId>org.apache.felix.shell</artifactId>
<version>1.0.0</version>
Added: felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java?rev=1814712&view=auto
==============================================================================
--- felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java (added)
+++ felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java Thu Nov 9 10:20:57 2017
@@ -0,0 +1,258 @@
+/*
+ * 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<Bundle>, SynchronousBundleListener {
+
+ private final ConcurrentMap<Bundle, Activator.ScrExtension> extensions = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Bundle, FutureTask<Void>> destroying = new ConcurrentHashMap<>();
+ private volatile boolean stopping;
+ private volatile boolean stopped;
+
+ private BundleContext context;
+ private BundleTracker<Bundle> 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<Bundle> 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<Bundle> chooseBundlesToDestroy(Set<Bundle> 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<Void> 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);
+
+}
Propchange: felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/AbstractExtender.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Modified: felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/Activator.java?rev=1814712&r1=1814711&r2=1814712&view=diff
==============================================================================
--- felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/Activator.java (original)
+++ felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/Activator.java Thu Nov 9 10:20:57 2017
@@ -29,8 +29,6 @@ import org.apache.felix.scr.impl.config.
import org.apache.felix.scr.impl.inject.ClassUtils;
import org.apache.felix.scr.impl.logger.ScrLogger;
import org.apache.felix.scr.impl.runtime.ServiceComponentRuntimeImpl;
-import org.apache.felix.utils.extender.AbstractExtender;
-import org.apache.felix.utils.extender.Extension;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
@@ -80,7 +78,6 @@ public class Activator extends AbstractE
public Activator()
{
m_configuration = new ScrConfigurationImpl( this );
- setSynchronous( true );
}
/**
@@ -225,12 +222,12 @@ public class Activator extends AbstractE
//---------- Component Management -----------------------------------------
@Override
- protected Extension doCreateExtension(final Bundle bundle) throws Exception
+ protected ScrExtension doCreateExtension(final Bundle bundle) throws Exception
{
return new ScrExtension( bundle );
}
- protected class ScrExtension implements Extension
+ protected class ScrExtension
{
private final Bundle bundle;
@@ -241,7 +238,6 @@ public class Activator extends AbstractE
this.bundle = bundle;
}
- @Override
public void start()
{
boolean acquired = false;
@@ -269,7 +265,6 @@ public class Activator extends AbstractE
}
}
- @Override
public void destroy()
{
boolean acquired = false;
@@ -464,13 +459,4 @@ public class Activator extends AbstractE
}
}
}
-
- @Override
- protected void error(final String msg, final Throwable t)
- {
- if ( logger.isLogEnabled(LogService.LOG_ERROR) )
- {
- logger.log( LogService.LOG_ERROR, msg, t );
- }
- }
}
\ No newline at end of file
Modified: felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java?rev=1814712&r1=1814711&r2=1814712&view=diff
==============================================================================
--- felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java (original)
+++ felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java Thu Nov 9 10:20:57 2017
@@ -46,7 +46,6 @@ import org.apache.felix.scr.impl.manager
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.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationAdmin;
@@ -458,48 +457,6 @@ public class ComponentRegistry
//---------- Helper method
- /**
- * Returns <code>true</code> if the <code>bundle</code> is to be considered
- * active from the perspective of declarative services.
- * <p>
- * As of R4.1 a bundle may have lazy activation policy which means a bundle
- * remains in the STARTING state until a class is loaded from that bundle
- * (unless that class is declared to not cause the bundle to start). And
- * thus for DS 1.1 this means components are to be loaded for lazily started
- * bundles being in the STARTING state (after the LAZY_ACTIVATION event) has
- * been sent. Hence DS must consider a bundle active when it is really
- * active and when it is a lazily activated bundle in the STARTING state.
- *
- * @param bundle The bundle check
- * @return <code>true</code> if <code>bundle</code> is not <code>null</code>
- * and the bundle is either active or has lazy activation policy
- * and is in the starting state.
- *
- * @see <a href="https://issues.apache.org/jira/browse/FELIX-1666">FELIX-1666</a>
- */
- static boolean isBundleActive( final Bundle bundle )
- {
- if ( bundle != null )
- {
- if ( bundle.getState() == Bundle.ACTIVE )
- {
- return true;
- }
-
- if ( bundle.getState() == Bundle.STARTING )
- {
- // according to the spec the activationPolicy header is only
- // set to request a bundle to be lazily activated. So in this
- // simple check we just verify the header is set to assume
- // the bundle is considered a lazily activated bundle
- return bundle.getHeaders("").get(Constants.BUNDLE_ACTIVATIONPOLICY) != null;
- }
- }
-
- // fall back: bundle is not considered active
- return false;
- }
-
private final ThreadLocal<List<ServiceReference<?>>> circularInfos = new ThreadLocal<List<ServiceReference<?>>> ()
{
Modified: felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java?rev=1814712&r1=1814711&r2=1814712&view=diff
==============================================================================
--- felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java (original)
+++ felix/trunk/osgi-r7/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java Thu Nov 9 10:20:57 2017
@@ -58,6 +58,7 @@ public class ScrCommand implements ScrIn
private static final Comparator<ComponentDescriptionDTO> DESCRIPTION_COMP = new Comparator<ComponentDescriptionDTO>()
{
+ @Override
public int compare(final ComponentDescriptionDTO c1, final ComponentDescriptionDTO c2)
{
final long bundleId1 = c1.bundle.id;
@@ -85,6 +86,7 @@ public class ScrCommand implements ScrIn
private static final Comparator<ComponentConfigurationDTO> CONFIGURATION_COMP = new Comparator<ComponentConfigurationDTO>()
{
+ @Override
public int compare(final ComponentConfigurationDTO c1, final ComponentConfigurationDTO c2)
{
return Long.signum(c1.id - c2.id);
@@ -124,7 +126,7 @@ public class ScrCommand implements ScrIn
try
{
final ScrGogoCommand gogoCmd = new ScrGogoCommand(this);
- final Hashtable<String, Object> props = new Hashtable<String, Object>();
+ final Hashtable<String, Object> props = new Hashtable<>();
props.put("osgi.command.scope", "scr");
props.put("osgi.command.function", new String[]
{ "config", "disable", "enable", "info", "list" });
@@ -144,7 +146,7 @@ public class ScrCommand implements ScrIn
{
// Register "scr" impl command service as a
// wrapper for the bundle repository service.
- final Hashtable<String, Object> props = new Hashtable<String, Object>();
+ final Hashtable<String, Object> props = new Hashtable<>();
props.put(Constants.SERVICE_DESCRIPTION, "SCR Legacy Shell Support");
props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
shellReg = bundleContext.registerService(org.apache.felix.shell.Command.class, new ScrShellCommand(this),
@@ -179,7 +181,7 @@ public class ScrCommand implements ScrIn
{
if ( reg == null )
{
- final Hashtable<String, Object> props = new Hashtable<String, Object>();
+ final Hashtable<String, Object> props = new Hashtable<>();
props.put(Constants.SERVICE_DESCRIPTION, "SCR Info service");
props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
reg = bundleContext.registerService( ScrInfo.class, this, props );
@@ -195,12 +197,55 @@ public class ScrCommand implements ScrIn
}
}
+ /**
+ * Returns <code>true</code> if the <code>bundle</code> is to be considered
+ * active from the perspective of declarative services.
+ * <p>
+ * As of R4.1 a bundle may have lazy activation policy which means a bundle
+ * remains in the STARTING state until a class is loaded from that bundle
+ * (unless that class is declared to not cause the bundle to start). And
+ * thus for DS 1.1 this means components are to be loaded for lazily started
+ * bundles being in the STARTING state (after the LAZY_ACTIVATION event) has
+ * been sent. Hence DS must consider a bundle active when it is really
+ * active and when it is a lazily activated bundle in the STARTING state.
+ *
+ * @param bundle The bundle check
+ * @return <code>true</code> if <code>bundle</code> is not <code>null</code>
+ * and the bundle is either active or has lazy activation policy
+ * and is in the starting state.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/FELIX-1666">FELIX-1666</a>
+ */
+ private static boolean isBundleActive( final Bundle bundle )
+ {
+ if ( bundle != null )
+ {
+ if ( bundle.getState() == Bundle.ACTIVE )
+ {
+ return true;
+ }
+
+ if ( bundle.getState() == Bundle.STARTING )
+ {
+ // according to the spec the activationPolicy header is only
+ // set to request a bundle to be lazily activated. So in this
+ // simple check we just verify the header is set to assume
+ // the bundle is considered a lazily activated bundle
+ return bundle.getHeaders("").get(Constants.BUNDLE_ACTIVATIONPOLICY) != null;
+ }
+ }
+
+ // fall back: bundle is not considered active
+ return false;
+ }
+
/* (non-Javadoc)
* @see org.apache.felix.scr.impl.ScrInfo#list(java.lang.String, java.io.PrintStream, java.io.PrintStream)
*/
+ @Override
public void list(final String bundleIdentifier, final PrintWriter out)
{
- final List<ComponentDescriptionDTO> descriptions = new ArrayList<ComponentDescriptionDTO>();
+ final List<ComponentDescriptionDTO> descriptions = new ArrayList<>();
if (bundleIdentifier != null)
{
@@ -228,7 +273,7 @@ public class ScrCommand implements ScrIn
{
throw new IllegalArgumentException("Missing bundle with ID " + bundleIdentifier);
}
- if (ComponentRegistry.isBundleActive(bundle))
+ if (isBundleActive(bundle))
{
descriptions.addAll(scrService.getComponentDescriptionDTOs(bundle));
if (descriptions.isEmpty())
@@ -260,7 +305,7 @@ public class ScrCommand implements ScrIn
for(final ComponentDescriptionDTO desc : descriptions)
{
out.println( String.format( " [%1$4d] %2$s %3$s", desc.bundle.id, desc.name, desc.defaultEnabled ? "enabled" : "disabled" ) );
- final List<ComponentConfigurationDTO> configs = new ArrayList<ComponentConfigurationDTO>(this.scrService.getComponentConfigurationDTOs(desc));
+ final List<ComponentConfigurationDTO> configs = new ArrayList<>(this.scrService.getComponentConfigurationDTOs(desc));
Collections.sort( configs, CONFIGURATION_COMP);
for ( final ComponentConfigurationDTO component : configs )
{
@@ -287,6 +332,7 @@ public class ScrCommand implements ScrIn
/**
* @see org.apache.felix.scr.impl.ScrInfo#info(java.lang.String, java.io.PrintStream, java.io.PrintStream)
*/
+ @Override
public void info(final String componentId, final PrintWriter out)
{
final Result result = getComponentsFromArg(componentId, false);
@@ -402,7 +448,7 @@ public class ScrCommand implements ScrIn
{
out.println(" (No Component Configurations)");
}
- else
+ else
{
for (final ComponentConfigurationDTO cc: componentConfigurationDTOs)
{
@@ -423,7 +469,7 @@ public class ScrCommand implements ScrIn
out.print( prefix );
out.print( label );
out.println( " Properties:" );
- TreeMap<String, Object> keys = new TreeMap<String, Object>( props );
+ TreeMap<String, Object> keys = new TreeMap<>( props );
for ( Entry<String, Object> entry: keys.entrySet() )
{
out.print( prefix );
@@ -546,6 +592,7 @@ public class ScrCommand implements ScrIn
/**
* @see org.apache.felix.scr.impl.ScrInfo#config(java.io.PrintStream)
*/
+ @Override
public void config(final PrintWriter out)
{
out.print("Log Level: ");
@@ -584,7 +631,7 @@ public class ScrCommand implements ScrIn
}
private static final class Result {
- public List<ComponentDescriptionDTO> components = new ArrayList<ComponentDescriptionDTO>();
+ public List<ComponentDescriptionDTO> components = new ArrayList<>();
public ComponentConfigurationDTO configuration;
}