You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/10 16:15:53 UTC
[31/59] [abbrv] [KARAF-2852] Merge diagnostic/core and
diagnostic/command
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/core/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/diagnostic/core/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java b/diagnostic/core/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java
deleted file mode 100644
index 7a01daf..0000000
--- a/diagnostic/core/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.diagnostic.core.internal.osgi;
-
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-
-import org.apache.karaf.diagnostic.core.DumpProvider;
-import org.apache.karaf.diagnostic.core.internal.BundleDumpProvider;
-import org.apache.karaf.diagnostic.core.internal.DiagnosticDumpMBeanImpl;
-import org.apache.karaf.diagnostic.core.internal.EnvironmentDumpProvider;
-import org.apache.karaf.diagnostic.core.internal.FeaturesDumpProvider;
-import org.apache.karaf.diagnostic.core.internal.HeapDumpProvider;
-import org.apache.karaf.diagnostic.core.internal.LogDumpProvider;
-import org.apache.karaf.diagnostic.core.internal.MemoryDumpProvider;
-import org.apache.karaf.diagnostic.core.internal.ThreadDumpProvider;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.util.tracker.SingleServiceTracker;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-
-public class Activator implements BundleActivator {
-
- private List<ServiceRegistration<DumpProvider>> registrations;
- private ServiceRegistration<DumpProvider> featuresProviderRegistration;
- private ServiceRegistration mbeanRegistration;
- private SingleServiceTracker<FeaturesService> featuresServiceTracker;
- private ServiceTracker<DumpProvider, DumpProvider> providersTracker;
-
- @Override
- public void start(final BundleContext context) throws Exception {
- registrations = new ArrayList<ServiceRegistration<DumpProvider>>();
- registrations.add(context.registerService(DumpProvider.class, new BundleDumpProvider(context), null));
- registrations.add(context.registerService(DumpProvider.class, new EnvironmentDumpProvider(context), null));
- registrations.add(context.registerService(DumpProvider.class, new HeapDumpProvider(), null));
- registrations.add(context.registerService(DumpProvider.class, new LogDumpProvider(context), null));
- registrations.add(context.registerService(DumpProvider.class, new MemoryDumpProvider(), null));
- registrations.add(context.registerService(DumpProvider.class, new ThreadDumpProvider(), null));
-
- featuresServiceTracker = new SingleServiceTracker<FeaturesService>(context, FeaturesService.class, new SingleServiceTracker.SingleServiceListener() {
- @Override
- public void serviceFound() {
- featuresProviderRegistration =
- context.registerService(
- DumpProvider.class,
- new FeaturesDumpProvider(featuresServiceTracker.getService()),
- null);
- }
- @Override
- public void serviceLost() {
- }
- @Override
- public void serviceReplaced() {
- featuresProviderRegistration.unregister();
- }
- });
-
- final DiagnosticDumpMBeanImpl diagnostic = new DiagnosticDumpMBeanImpl();
- providersTracker = new ServiceTracker<DumpProvider, DumpProvider>(
- context, DumpProvider.class, new ServiceTrackerCustomizer<DumpProvider, DumpProvider>() {
- @Override
- public DumpProvider addingService(ServiceReference<DumpProvider> reference) {
- DumpProvider service = context.getService(reference);
- diagnostic.registerProvider(service);
- return service;
- }
- @Override
- public void modifiedService(ServiceReference<DumpProvider> reference, DumpProvider service) {
- }
- @Override
- public void removedService(ServiceReference<DumpProvider> reference, DumpProvider service) {
- diagnostic.unregisterProvider(service);
- context.ungetService(reference);
- }
- });
- providersTracker.open();
-
- Hashtable<String, Object> props = new Hashtable<String, Object>();
- props.put("jmx.objectname", "org.apache.karaf:type=diagnostic,name=" + System.getProperty("karaf.name"));
- mbeanRegistration = context.registerService(
- getInterfaceNames(diagnostic),
- diagnostic,
- props
- );
- }
-
- @Override
- public void stop(BundleContext context) throws Exception {
- mbeanRegistration.unregister();
- featuresServiceTracker.close();
- providersTracker.close();
- for (ServiceRegistration<DumpProvider> reg : registrations) {
- reg.unregister();
- }
- }
-
- private String[] getInterfaceNames(Object object) {
- List<String> names = new ArrayList<String>();
- for (Class cl = object.getClass(); cl != Object.class; cl = cl.getSuperclass()) {
- addSuperInterfaces(names, cl);
- }
- return names.toArray(new String[names.size()]);
- }
-
- private void addSuperInterfaces(List<String> names, Class clazz) {
- for (Class cl : clazz.getInterfaces()) {
- names.add(cl.getName());
- addSuperInterfaces(names, cl);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/diagnostic/core/src/main/resources/OSGI-INF/bundle.info b/diagnostic/core/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index 15bc3cb..0000000
--- a/diagnostic/core/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,18 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-[mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-The diagnostic core bundle is the diagnostic core implementation.
-
-It's used by the diagnostic commands bundle and is responsible of the dump generation (environment, features, logs, bundles, threads).
-
-h1. See also
-
-Diagnostic - section of the Karaf User Guide.
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/pom.xml
----------------------------------------------------------------------
diff --git a/diagnostic/pom.xml b/diagnostic/pom.xml
index c40d93c..db61e04 100644
--- a/diagnostic/pom.xml
+++ b/diagnostic/pom.xml
@@ -29,13 +29,90 @@
</parent>
<groupId>org.apache.karaf.diagnostic</groupId>
- <artifactId>diagnostic</artifactId>
- <packaging>pom</packaging>
- <name>Apache Karaf :: Diagnostic</name>
-
- <modules>
- <module>core</module>
- <module>command</module>
- </modules>
+ <artifactId>org.apache.karaf.diagnostic.core</artifactId>
+ <packaging>bundle</packaging>
+ <name>Apache Karaf :: Diagnostic :: Core</name>
+ <description>Core implementation using Karaf diagnostic using the diagnostic common services</description>
+
+ <properties>
+ <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf</groupId>
+ <artifactId>org.apache.karaf.util</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>org.apache.karaf.features.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
+ <optional>true</optional>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <filtering>true</filtering>
+ <includes>
+ <include>**/*.info</include>
+ </includes>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.apache.karaf.diagnostic.command,
+ org.apache.karaf.diagnostic.core,
+ org.apache.karaf.diagnostic.core.common
+ </Export-Package>
+ <Import-Package>
+ com.sun.management*;resolution:=optional,
+ *
+ </Import-Package>
+ <Private-Package>
+ org.apache.karaf.diagnostic.core.internal,
+ org.apache.karaf.diagnostic.core.internal.osgi,
+ org.apache.karaf.util.tracker
+ </Private-Package>
+ <Bundle-Activator>
+ org.apache.karaf.diagnostic.core.internal.osgi.Activator
+ </Bundle-Activator>
+ <Karaf-Commands>*</Karaf-Commands>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/command/DumpCommand.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/command/DumpCommand.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/command/DumpCommand.java
new file mode 100644
index 0000000..3f6c607
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/command/DumpCommand.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.command;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.karaf.diagnostic.core.DumpDestination;
+import org.apache.karaf.diagnostic.core.DumpProvider;
+import org.apache.karaf.diagnostic.core.common.DirectoryDumpDestination;
+import org.apache.karaf.diagnostic.core.common.ZipDumpDestination;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * Command to create dump from shell.
+ */
+@Command(scope = "dev", name = "dump-create", description = "Creates zip archive with diagnostic info.")
+@Service
+public class DumpCommand implements Action {
+
+ /**
+ * Output format of the filename if not defined otherwise
+ */
+ private SimpleDateFormat dumpFormat = new SimpleDateFormat("yyyy-MM-dd_HHmmss");
+
+ /**
+ * Directory switch.
+ */
+ @Option(name = "-d", aliases = "--directory", description = "Creates dump in a directory in place of a ZIP archive")
+ boolean directory;
+
+ /**
+ * Name of created directory or archive.
+ */
+ @Argument(name = "name", description = "Name of created zip or directory", required = false)
+ String fileName;
+
+ @Reference
+ List<DumpProvider> providers;
+
+ @Override
+ public Object execute() throws Exception {
+ DumpDestination destination;
+
+ if (providers.isEmpty()) {
+ System.out.println("Unable to create dump. No providers were found");
+ return null;
+ }
+
+ // create default file name if none provided
+ if (fileName == null || fileName.trim().length() == 0) {
+ fileName = dumpFormat.format(new Date());
+ if (!directory) {
+ fileName += ".zip";
+ }
+ }
+ File target = new File(fileName);
+
+ // if directory switch is on, create dump in directory
+ if (directory) {
+ destination = new DirectoryDumpDestination(target);
+ } else {
+ destination = new ZipDumpDestination(target);
+ }
+
+ for (DumpProvider provider : providers) {
+ provider.createDump(destination);
+ }
+ destination.save();
+ System.out.println("Diagnostic dump created at " + target.getAbsolutePath() + ".");
+
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DiagnosticDumpMBean.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DiagnosticDumpMBean.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DiagnosticDumpMBean.java
new file mode 100644
index 0000000..f59982a
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DiagnosticDumpMBean.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core;
+
+import javax.management.MBeanException;
+
+/**
+ * Diagnostic MBean which allows to create dumps over JMX.
+ */
+public interface DiagnosticDumpMBean {
+
+ /**
+ * Creates dump over JMX.
+ *
+ * @param name Name of the dump.
+ * @throws Exception In case of any problems.
+ */
+ void createDump(String name) throws MBeanException;
+
+ /**
+ * Create dump with directory switch and name.
+ *
+ * @param directory Should dump be created in directory.
+ * @param name Name of the dump.
+ * @throws Exception In case of any problems.
+ */
+ void createDump(boolean directory, String name) throws MBeanException;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpDestination.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpDestination.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpDestination.java
new file mode 100644
index 0000000..39c4edc
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpDestination.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core;
+
+import java.io.OutputStream;
+
+/**
+ * Destination for created dumps.
+ */
+public interface DumpDestination {
+
+ /**
+ * Creates new entry in dump destination.
+ *
+ * Destination does not close returned output stream by default, dump
+ * provider should do this after completing write operation.
+ *
+ * @param name Name of file in destination.
+ * @return Output stream ready to write.
+ * @throws Exception When entry cannot be added.
+ */
+ OutputStream add(String name) throws Exception;
+
+ /**
+ * Complete creation of the dump.
+ */
+ void save() throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpProvider.java
new file mode 100644
index 0000000..ec7724c
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/DumpProvider.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core;
+
+/**
+ * Interface which represents instance of tool which can provide dump
+ * information.
+ */
+public interface DumpProvider {
+
+ /**
+ * Creates dump in given entry.
+ */
+ void createDump(DumpDestination destination) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ClosingEntryOutputStreamWrapper.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ClosingEntryOutputStreamWrapper.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ClosingEntryOutputStreamWrapper.java
new file mode 100644
index 0000000..0c4f9db
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ClosingEntryOutputStreamWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.common;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Output stream which closes entry instead closing whole stream.
+ */
+public class ClosingEntryOutputStreamWrapper extends OutputStream {
+
+ /**
+ * Wrapped ZIP output stream.
+ */
+ private ZipOutputStream outputStream;
+
+ /**
+ * Creates new OutputStream.
+ *
+ * @param outputStream Wrapped output stream.
+ */
+ public ClosingEntryOutputStreamWrapper(ZipOutputStream outputStream) {
+ this.outputStream = outputStream;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(int b) throws IOException {
+ outputStream.write(b);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(byte[] b) throws IOException {
+ outputStream.write(b);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(byte[] b, int off, int len)
+ throws IOException {
+ outputStream.write(b, off, len);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() throws IOException {
+ // close entry instead of closing zip stream.
+ outputStream.closeEntry();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/DirectoryDumpDestination.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/DirectoryDumpDestination.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/DirectoryDumpDestination.java
new file mode 100644
index 0000000..37ae72e
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/DirectoryDumpDestination.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.common;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import org.apache.karaf.diagnostic.core.DumpDestination;
+
+/**
+ * Class which packages dumps to given directory.
+ */
+public class DirectoryDumpDestination implements DumpDestination {
+
+ /**
+ * Directory where dump files will be created.
+ */
+ private File directory;
+
+ public DirectoryDumpDestination(File file) {
+ this.directory = file;
+
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+ }
+
+ public OutputStream add(String name) throws Exception {
+ File destination = new File(directory, name);
+ if (name.contains("/") || name.contains("\\")) {
+ // if name contains slashes we need to create sub directory
+ destination.getParentFile().mkdirs();
+ }
+ return new FileOutputStream(destination);
+ }
+
+ public void save() throws Exception {
+ // do nothing, all should be written to output streams
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/TextDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/TextDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/TextDumpProvider.java
new file mode 100644
index 0000000..0b97d6f
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/TextDumpProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.common;
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import org.apache.karaf.diagnostic.core.DumpDestination;
+import org.apache.karaf.diagnostic.core.DumpProvider;
+
+/**
+ * Base class for dump providers which writes text to destination.
+ */
+public abstract class TextDumpProvider implements DumpProvider {
+
+ /**
+ * Name of the file.
+ */
+ private final String name;
+
+ /**
+ * Creates new dump provider.
+ *
+ * @param name Name of the file.
+ */
+ protected TextDumpProvider(String name) {
+ this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void createDump(DumpDestination destination) throws Exception {
+ OutputStream outputStream = destination.add(name);
+ OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
+ try {
+ writeDump(outputStreamWriter);
+ } finally {
+ outputStreamWriter.close();
+ outputStream.close();
+ }
+ }
+
+ /**
+ * This method should create output.
+ *
+ * @param outputStreamWriter Stream which points to file specified in constructor.
+ * @throws Exception If any problem occur.
+ */
+ protected abstract void writeDump(OutputStreamWriter outputStreamWriter) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ZipDumpDestination.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ZipDumpDestination.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ZipDumpDestination.java
new file mode 100644
index 0000000..bafd38d
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/common/ZipDumpDestination.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.common;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.karaf.diagnostic.core.DumpDestination;
+
+/**
+ * Class which packages dumps to ZIP archive.
+ */
+public class ZipDumpDestination implements DumpDestination {
+
+ /**
+ * Destination streem.
+ */
+ private ZipOutputStream outputStream;
+
+ /**
+ * Creates new dump in given directory.
+ *
+ * @param directory Target directory.
+ * @param name Name of the archive.
+ */
+ public ZipDumpDestination(File directory, String name) {
+ this(new File(directory, name));
+ }
+
+ /**
+ * Creates new dump in given file (zip archive).
+ *
+ * @param file Destination file.
+ */
+ public ZipDumpDestination(File file) {
+ try {
+ outputStream = new ZipOutputStream(new FileOutputStream(
+ file));
+ } catch (FileNotFoundException e) {
+ // sometimes this can occur, but we simply re throw and let
+ // caller handle exception
+ throw new RuntimeException("Unable to create dump destination", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public OutputStream add(String name) throws Exception {
+ ZipEntry zipEntry = new ZipEntry(name);
+ outputStream.putNextEntry(zipEntry);
+ return new ClosingEntryOutputStreamWrapper(outputStream);
+ }
+
+ /**
+ * Closes archive handle.
+ */
+ public void save() throws Exception {
+ outputStream.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/BundleDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/BundleDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/BundleDumpProvider.java
new file mode 100644
index 0000000..774dc1f
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/BundleDumpProvider.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.karaf.diagnostic.core.common.TextDumpProvider;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Dump provider which produces file named bundles.txt with list of
+ * installed bundles and it's state.
+ */
+public class BundleDumpProvider extends TextDumpProvider {
+
+ /**
+ * Static map with state mask to string representation.
+ */
+ private static Map<Integer, String> stateMap = new HashMap<Integer, String>();
+
+ /**
+ * Map bundle states to string representation.
+ */
+ static {
+ stateMap.put(0x00000001, "UNINSTALLED");
+ stateMap.put(0x00000002, "INSTALLED");
+ stateMap.put(0x00000004, "RESOLVED");
+ stateMap.put(0x00000008, "STARTING");
+ stateMap.put(0x00000010, "STOPPING");
+ stateMap.put(0x00000020, "ACTIVE");
+ }
+
+ /**
+ * Bundle context.
+ */
+ private BundleContext bundleContext;
+
+ /**
+ * Creates new bundle information file.
+ *
+ * @param context Bundle context to access framework state.
+ */
+ public BundleDumpProvider(BundleContext context) {
+ super("bundles.txt");
+ this.bundleContext = context;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void writeDump(OutputStreamWriter writer) throws IOException {
+ // get bundle states
+ Bundle[] bundles = bundleContext.getBundles();
+
+ writer.write("Number of installed bundles " + bundles.length + "\n");
+
+ // create file header
+ writer.write("Id\tSymbolic name\tVersion\tState\n");
+ for (Bundle bundle : bundles) {
+ // write row :)
+ writer.write(bundle.getBundleId() + "\t" + bundle.getSymbolicName() + '\t' + bundle.getVersion()
+ + "\t" + stateMap.get(bundle.getState()) + "\n");
+ }
+
+ writer.flush();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/DiagnosticDumpMBeanImpl.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/DiagnosticDumpMBeanImpl.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/DiagnosticDumpMBeanImpl.java
new file mode 100644
index 0000000..22e09c9
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/DiagnosticDumpMBeanImpl.java
@@ -0,0 +1,89 @@
+/*
+ * 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.karaf.diagnostic.core.internal;
+
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.management.MBeanException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.StandardMBean;
+
+import org.apache.karaf.diagnostic.core.DiagnosticDumpMBean;
+import org.apache.karaf.diagnostic.core.DumpDestination;
+import org.apache.karaf.diagnostic.core.DumpProvider;
+import org.apache.karaf.diagnostic.core.common.DirectoryDumpDestination;
+import org.apache.karaf.diagnostic.core.common.ZipDumpDestination;
+
+/**
+ * Implementation of diagnostic MBean.
+ */
+public class DiagnosticDumpMBeanImpl extends StandardMBean implements DiagnosticDumpMBean {
+
+ /**
+ * Dump providers.
+ */
+ private final List<DumpProvider> providers = new CopyOnWriteArrayList<DumpProvider>();
+
+ /**
+ * Creates new diagnostic mbean.
+ *
+ * @throws NotCompliantMBeanException
+ */
+ public DiagnosticDumpMBeanImpl() throws NotCompliantMBeanException {
+ super(DiagnosticDumpMBean.class);
+ }
+
+ /**
+ * Creates dump witch given name
+ *
+ * @param name Name of the dump.
+ */
+ public void createDump(String name) throws MBeanException {
+ createDump(false, name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createDump(boolean directory, String name) throws MBeanException {
+ try {
+ File target = new File(name);
+
+ DumpDestination destination;
+ if (directory) {
+ destination = new DirectoryDumpDestination(target);
+ } else {
+ destination = new ZipDumpDestination(target);
+ }
+
+ for (DumpProvider provider : providers) {
+ provider.createDump(destination);
+ }
+
+ destination.save();
+ } catch (Exception e) {
+ throw new MBeanException(null, e.getMessage());
+ }
+ }
+
+ public void registerProvider(DumpProvider provider) {
+ providers.add(provider);
+ }
+
+ public void unregisterProvider(DumpProvider provider) {
+ providers.add(provider);
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/EnvironmentDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/EnvironmentDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/EnvironmentDumpProvider.java
new file mode 100644
index 0000000..3328067
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/EnvironmentDumpProvider.java
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal;
+
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.lang.management.ClassLoadingMXBean;
+import java.lang.management.CompilationMXBean;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.karaf.diagnostic.core.common.TextDumpProvider;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+
+/**
+ * Provider which dumps runtime environment information to file named environment.txt.
+ */
+public class EnvironmentDumpProvider extends TextDumpProvider {
+
+ private static final String KEY_VALUE_FORMAT = "%1$s\t: %2$s";
+ private static final String INDENT_KEY_VALUE_FORMAT = " "+KEY_VALUE_FORMAT;
+ private final BundleContext bundleContext;
+
+ /**
+ * Creates new dump entry which contains information about the runtime environment.
+ */
+ public EnvironmentDumpProvider(final BundleContext context) {
+ super("environment.txt");
+ this.bundleContext = context;
+ }
+
+ @Override
+ protected void writeDump(final OutputStreamWriter outputStream) throws Exception {
+ if( null == outputStream) {
+ return;
+ }
+ final PrintWriter outPW = new PrintWriter(outputStream);
+ // current date/time
+ final DateFormat dateTimeFormatInstance = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.ENGLISH);
+ outPW.printf(KEY_VALUE_FORMAT,"Dump timestamp", dateTimeFormatInstance.format(new Date(System.currentTimeMillis()))).println();
+ outPW.println();
+ // karaf information
+ dumpKarafInformation(outPW);
+ outPW.println();
+ // OSGi information
+ dumpOSGiInformation(outPW);
+ outPW.println();
+ // OS information
+ dumpOSInformation(outPW);
+ outPW.println();
+ // general information about JVM
+ dumpVMInformation(outPW, dateTimeFormatInstance);
+ outPW.println();
+ // threads
+ dumpThreadsInformation(outPW);
+ outPW.println();
+ // classes
+ dumpClassesInformation(outPW);
+ outPW.println();
+ // memory
+ dumpMemoryInformation(outPW);
+ outPW.println();
+ // garbage collector
+ dumpGCInformation(outPW);
+ }
+
+ private void dumpKarafInformation(final PrintWriter outPW) {
+ outPW.printf(KEY_VALUE_FORMAT, "Karaf", System.getProperty("karaf.name", "root") + ' ' + System.getProperty("karaf.version", "")).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "home", System.getProperty("karaf.home", "")).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "base", System.getProperty("karaf.base", "")).println();
+ }
+
+ private void dumpOSGiInformation(final PrintWriter outPW) {
+ if( null == bundleContext ) {
+ return;
+ }
+ outPW.println("OSGi:");
+ final Bundle[] bundles = bundleContext.getBundles();
+ for (final Bundle bundle : bundles) {
+ if( null == bundle || !!!"osgi.core".equals(bundle.getSymbolicName())) {
+ continue;
+ }
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "version", bundle.getVersion()).println();
+ break;
+ }
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "framework", bundleContext.getBundle(0).getSymbolicName() + " - " +
+ bundleContext.getBundle(0).getVersion()).println();
+ }
+
+ private void dumpOSInformation(final PrintWriter outPW) {
+ final OperatingSystemMXBean mxBean = ManagementFactory.getOperatingSystemMXBean();
+ if( null == mxBean) {
+ return;
+ }
+ outPW.printf(KEY_VALUE_FORMAT, "Operating System", mxBean.getName() + ' ' + mxBean.getVersion()).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "architecture", mxBean.getArch()).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "processors", mxBean.getAvailableProcessors()).println();
+// outPW.printf(INDENT_KEY_VALUE_FORMAT, "current system load average", mxBean.getSystemLoadAverage()).println();
+ }
+
+ private void dumpVMInformation(final PrintWriter outPW,
+ final DateFormat dateTimeFormatInstance) {
+ final RuntimeMXBean mxBean = ManagementFactory.getRuntimeMXBean();
+ if( mxBean == null ) {
+ return;
+ }
+ outPW.printf(KEY_VALUE_FORMAT,"Instance name", mxBean.getName()).println();
+ outPW.printf(KEY_VALUE_FORMAT,"Start time", dateTimeFormatInstance.format(new Date(mxBean.getStartTime()))).println();
+ outPW.printf(KEY_VALUE_FORMAT,"Uptime", printDuration(mxBean.getUptime())).println();
+ outPW.println();
+ outPW.printf(KEY_VALUE_FORMAT, "Java VM", mxBean.getVmName() + " " + mxBean.getVmVersion()).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "vendor", mxBean.getVmVendor()).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "version", System.getProperty("java.version")).println();
+ outPW.println();
+ outPW.println("Input arguments:");
+ final List<String> inputArguments = mxBean.getInputArguments();
+ for (final String argument : inputArguments) {
+ if( argument != null && argument.contains("=")) {
+ final String[] split = argument.split("=");
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, split[0], split[1]).println();
+ } else {
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, argument,"").println();
+ }
+ }
+ outPW.println("Classpath:");
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "boot classpath", mxBean.getBootClassPath()).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "library path", mxBean.getLibraryPath()).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "classpath", mxBean.getClassPath()).println();
+ outPW.println("System properties:");
+ final Map<String, String> systemProperties = mxBean.getSystemProperties();
+ for (final Entry<String, String> property : systemProperties.entrySet()) {
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, property.getKey(), property.getValue()).println();
+ }
+ outPW.println();
+ // JIT information
+ final CompilationMXBean compilationMXBean = ManagementFactory.getCompilationMXBean();
+ if( compilationMXBean != null ) {
+ outPW.printf(KEY_VALUE_FORMAT, "JIT compiler", compilationMXBean.getName()).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "total compile time", printDuration(compilationMXBean.getTotalCompilationTime())).println();
+ }
+ }
+
+ private void dumpThreadsInformation(final PrintWriter outPW) {
+ final ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
+ if( null == mxBean) {
+ return;
+ }
+ outPW.println("Threads:");
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "live", formatLong(mxBean.getThreadCount())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "daemon", formatLong(mxBean.getDaemonThreadCount())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "peak", formatLong(mxBean.getPeakThreadCount())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "total", formatLong(mxBean.getTotalStartedThreadCount())).println();
+ }
+
+ private void dumpClassesInformation(final PrintWriter outPW) {
+ final ClassLoadingMXBean mxBean = ManagementFactory.getClassLoadingMXBean();
+ if( null == mxBean) {
+ return;
+ }
+ outPW.println("Classes:");
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "loaded", formatLong(mxBean.getLoadedClassCount())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "total", formatLong(mxBean.getTotalLoadedClassCount())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "unloaded", formatLong(mxBean.getUnloadedClassCount())).println();
+ }
+
+ private void dumpMemoryInformation(final PrintWriter outPW) {
+ final MemoryMXBean mxBean = ManagementFactory.getMemoryMXBean();
+ if( null == mxBean) {
+ return;
+ }
+ final MemoryUsage heapMemoryUsage = mxBean.getHeapMemoryUsage();
+ final MemoryUsage nonHeapMemoryUsage = mxBean.getNonHeapMemoryUsage();
+ if( heapMemoryUsage != null ) {
+ outPW.println("HEAP Memory:");
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "commited", printMemory(heapMemoryUsage.getCommitted())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "init", printMemory(heapMemoryUsage.getInit())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "used", printMemory(heapMemoryUsage.getUsed())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "maximal", printMemory(heapMemoryUsage.getMax())).println();
+ }
+ if( nonHeapMemoryUsage != null ) {
+ outPW.println("NON-HEAP Memory:");
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "commited", printMemory(nonHeapMemoryUsage.getCommitted())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "init", printMemory(nonHeapMemoryUsage.getInit())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "used", printMemory(nonHeapMemoryUsage.getUsed())).println();
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "maximal", printMemory(nonHeapMemoryUsage.getMax())).println();
+ }
+ }
+
+ private void dumpGCInformation(final PrintWriter outPW) {
+ final List<GarbageCollectorMXBean> mxBeans = ManagementFactory.getGarbageCollectorMXBeans();
+ if( null == mxBeans || mxBeans.isEmpty()) {
+ return;
+ }
+ final MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();
+ if( memoryMxBean != null ) {
+ outPW.printf(INDENT_KEY_VALUE_FORMAT, "pending objects", formatLong(memoryMxBean.getObjectPendingFinalizationCount())).println();
+ }
+ final String gcFormat ="'%1$s' collections: %2$s\ttime: %3$s";
+ outPW.println();
+ for (final GarbageCollectorMXBean mxBean : mxBeans) {
+ if( null == mxBean) {
+ continue;
+ }
+ outPW.printf(KEY_VALUE_FORMAT, "Garbage Collectors", String.format(gcFormat, mxBean.getName(), formatLong(mxBean.getCollectionCount()), printDuration(mxBean.getCollectionTime()))).println();
+ }
+ }
+
+
+ private String formatLong(final long longValue) {
+ final NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));
+ return fmtI.format(longValue);
+ }
+
+ private String printMemory(final long bytes) {
+ if( bytes <= 1024) {
+ return formatLong(bytes)+" bytes";
+ }
+ return formatLong(bytes/1024)+" kbytes";
+ }
+
+ /**
+ * Prints the duration in a human readable format as X days Y hours Z minutes etc.
+ *
+ * @param uptime the uptime in millis
+ * @return the time used for displaying on screen or in logs
+ */
+ private String printDuration(double uptime) {
+ // Code based on code taken from Karaf
+ // https://svn.apache.org/repos/asf/karaf/trunk/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/InfoAction.java
+
+ uptime /= 1000;
+ if (uptime < 60) {
+ final NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));
+ return fmtD.format(uptime) + " seconds";
+ }
+ uptime /= 60;
+ if (uptime < 60) {
+ final long minutes = (long) uptime;
+ final String s = formatLong(minutes) + (minutes > 1 ? " minutes" : " minute");
+ return s;
+ }
+ uptime /= 60;
+ if (uptime < 24) {
+ final long hours = (long) uptime;
+ final long minutes = (long) ((uptime - hours) * 60);
+ String s = formatLong(hours) + (hours > 1 ? " hours" : " hour");
+ if (minutes != 0) {
+ s += " " + formatLong(minutes) + (minutes > 1 ? " minutes" : " minute");
+ }
+ return s;
+ }
+ uptime /= 24;
+ final long days = (long) uptime;
+ final long hours = (long) ((uptime - days) * 24);
+ String s = formatLong(days) + (days > 1 ? " days" : " day");
+ if (hours != 0) {
+ s += " " + formatLong(hours) + (hours > 1 ? " hours" : " hour");
+ }
+ return s;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/FeaturesDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/FeaturesDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/FeaturesDumpProvider.java
new file mode 100644
index 0000000..e5fa55e
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/FeaturesDumpProvider.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal;
+
+import java.io.OutputStreamWriter;
+
+import org.apache.karaf.diagnostic.core.common.TextDumpProvider;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+
+/**
+ * Dump provider which add file named features.txt with informations
+ * about installed features and repositories.
+ */
+public class FeaturesDumpProvider extends TextDumpProvider {
+
+ /**
+ * Feature service.
+ */
+ private final FeaturesService features;
+
+ /**
+ * Creates new dump entry witch contains information about
+ * karaf features.
+ *
+ * @param features Feature service.
+ */
+ public FeaturesDumpProvider(FeaturesService features) {
+ super("features.txt");
+ this.features = features;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void writeDump(OutputStreamWriter outputStreamWriter) throws Exception {
+ // creates header
+ outputStreamWriter.write("Repositories:\n");
+
+ // list repositories
+ for (Repository repo : features.listRepositories()) {
+ outputStreamWriter.write(repo.getURI() + " (" + repo.getName() + ")\n");
+ }
+
+ // list features
+ outputStreamWriter.write("\nfeatures:\n");
+ for (Feature feature : features.listFeatures()) {
+ outputStreamWriter.write(feature.getName() + " " + feature.getVersion());
+ outputStreamWriter.write(" installed: " + features.isInstalled(feature));
+ outputStreamWriter.write("\nBundles:\n");
+ for (BundleInfo bundle : feature.getBundles()) {
+ outputStreamWriter.write("\t" + bundle.getLocation());
+ if (bundle.getStartLevel() != 0) {
+ outputStreamWriter.write(" start level " + bundle.getStartLevel());
+ }
+ outputStreamWriter.write("\n\n");
+ }
+ }
+
+ // flush & close stream
+ outputStreamWriter.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/HeapDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/HeapDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/HeapDumpProvider.java
new file mode 100644
index 0000000..b86f57b
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/HeapDumpProvider.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import org.apache.karaf.diagnostic.core.DumpDestination;
+import org.apache.karaf.diagnostic.core.DumpProvider;
+
+import javax.management.MBeanServer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+
+/**
+ * Create a heap dump.
+ */
+public class HeapDumpProvider implements DumpProvider {
+
+ @Override
+ public void createDump(DumpDestination destination) throws Exception {
+ FileInputStream in = null;
+ OutputStream out = null;
+ try {
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ HotSpotDiagnosticMXBean diagnosticMXBean = ManagementFactory.newPlatformMXBeanProxy(mBeanServer,
+ "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
+ diagnosticMXBean.dumpHeap("heapdump.txt", false);
+ // copy the dump in the destination
+ File heapDumpFile = new File("heapdump.txt");
+ in = new FileInputStream(heapDumpFile);
+ out = destination.add("heapdump.txt");
+ byte[] buffer = new byte[2048];
+ while ((in.read(buffer) != -1)) {
+ out.write(buffer);
+ }
+ // remove the original dump
+ if (heapDumpFile.exists()) {
+ heapDumpFile.delete();
+ }
+ } catch (Exception e) {
+ // nothing to do
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ if (out != null) {
+ out.flush();
+ out.close();
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/LogDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/LogDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/LogDumpProvider.java
new file mode 100644
index 0000000..64b45f1
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/LogDumpProvider.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.apache.karaf.diagnostic.core.DumpDestination;
+import org.apache.karaf.diagnostic.core.DumpProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Dump provider which copies log files from data/log directory to
+ * destination.
+ */
+public class LogDumpProvider implements DumpProvider {
+
+ private final BundleContext bundleContext;
+
+ public LogDumpProvider(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * Attach log entries from directory.
+ */
+ public void createDump(DumpDestination destination) throws Exception {
+ // get the ConfigAdmin service
+ ServiceReference ref = bundleContext.getServiceReference(ConfigurationAdmin.class.getName());
+ if (ref == null) {
+ return;
+ }
+
+ // get the PAX Logging configuration
+ ConfigurationAdmin configurationAdmin = (ConfigurationAdmin) bundleContext.getService(ref);
+ try {
+ Configuration configuration = configurationAdmin.getConfiguration("org.ops4j.pax.logging");
+
+ // get the ".file" Pax Logging properties
+ Dictionary dictionary = configuration.getProperties();
+ for (Enumeration e = dictionary.keys(); e.hasMoreElements(); ) {
+ String property = (String) e.nextElement();
+ if (property.endsWith(".file")) {
+ // it's a file appender, get the file location
+ String location = (String) dictionary.get(property);
+ File file = new File(location);
+ if (file.exists()) {
+ FileInputStream inputStream = new FileInputStream(file);
+ OutputStream outputStream = destination.add("log/" + file.getName());
+ copy(inputStream, outputStream);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ bundleContext.ungetService(ref);
+ }
+ }
+
+ /**
+ * Rewrites data from input stream to output stream. This code is very common
+ * but we would avoid additional dependencies in diagnostic stuff.
+ *
+ * @param inputStream Source stream.
+ * @param outputStream Destination stream.
+ * @throws IOException When IO operation fails.
+ */
+ private void copy(InputStream inputStream, OutputStream outputStream) throws IOException {
+ byte[] buffer = new byte[4096];
+ int n = 0;
+ while (-1 != (n = inputStream.read(buffer))) {
+ outputStream.write(buffer, 0, n);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/MemoryDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/MemoryDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/MemoryDumpProvider.java
new file mode 100644
index 0000000..ff23f9d
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/MemoryDumpProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal;
+
+import org.apache.karaf.diagnostic.core.common.TextDumpProvider;
+
+import java.io.OutputStreamWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+
+/**
+ * Provider which dump the memory information in the memory.txt file.
+ */
+public class MemoryDumpProvider extends TextDumpProvider {
+
+ public MemoryDumpProvider() {
+ super("memory.txt");
+ }
+
+ @Override
+ protected void writeDump(OutputStreamWriter outputStream) throws Exception {
+ MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
+
+ outputStream.write("Number of objects waiting finalization: " + memoryMXBean.getObjectPendingFinalizationCount() + "\n\n");
+
+ outputStream.write("Heap:\n");
+ outputStream.write("\tInit: " + memoryMXBean.getHeapMemoryUsage().getInit() + "\n");
+ outputStream.write("\tUser: " + memoryMXBean.getHeapMemoryUsage().getUsed() + "\n");
+ outputStream.write("\tCommitted: " + memoryMXBean.getHeapMemoryUsage().getCommitted() + "\n");
+ outputStream.write("\tMax: " + memoryMXBean.getHeapMemoryUsage().getMax() + "\n");
+
+ outputStream.write("Non-Heap: \n");
+ outputStream.write("\tInit: " + memoryMXBean.getNonHeapMemoryUsage().getInit() + "\n");
+ outputStream.write("\tUser: " + memoryMXBean.getNonHeapMemoryUsage().getUsed() + "\n");
+ outputStream.write("\tCommitted: " + memoryMXBean.getNonHeapMemoryUsage().getCommitted() + "\n");
+ outputStream.write("\tMax: " + memoryMXBean.getNonHeapMemoryUsage().getMax() + "\n");
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/ThreadDumpProvider.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/ThreadDumpProvider.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/ThreadDumpProvider.java
new file mode 100644
index 0000000..31edad6
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/ThreadDumpProvider.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal;
+
+import java.io.OutputStreamWriter;
+import java.lang.management.LockInfo;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MonitorInfo;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+
+import org.apache.karaf.diagnostic.core.common.TextDumpProvider;
+
+/**
+ * Provider which dumps thread info to file named threads.txt.
+ */
+public class ThreadDumpProvider extends TextDumpProvider {
+
+ /**
+ * Creates new dump entry which contains information about threads.
+ */
+ public ThreadDumpProvider() {
+ super("threads.txt");
+ }
+
+ @Override
+ protected void writeDump(OutputStreamWriter outputStream) throws Exception {
+ ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+
+ outputStream.write("Number of threads: " + threadMXBean.getThreadCount() + "\n");
+
+ for (ThreadInfo threadInfo : threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), Integer.MAX_VALUE)) {
+ outputStream.write(getDumpThreadString(threadInfo) + "\n\n");
+ }
+
+ }
+
+ protected String getDumpThreadString(ThreadInfo threadInfo) {
+ StringBuilder sb = new StringBuilder("\"" + threadInfo.getThreadName() + "\"" + " Id=" + threadInfo.getThreadId() + " "
+ + threadInfo.getThreadState());
+ if (threadInfo.getLockName() != null) {
+ sb.append(" on " + threadInfo.getLockName());
+ }
+ if (threadInfo.getLockOwnerName() != null) {
+ sb.append(" owned by \"" + threadInfo.getLockOwnerName() + "\" Id=" + threadInfo.getLockOwnerId());
+ }
+ if (threadInfo.isSuspended()) {
+ sb.append(" (suspended)");
+ }
+ if (threadInfo.isInNative()) {
+ sb.append(" (in native)");
+ }
+ sb.append('\n');
+ int i = 0;
+ StackTraceElement[] stackTrace = threadInfo.getStackTrace();
+ for (; i < stackTrace.length; i++) {
+ StackTraceElement ste = stackTrace[i];
+ sb.append("\tat " + ste.toString());
+ sb.append('\n');
+ if (i == 0 && threadInfo.getLockInfo() != null) {
+ Thread.State ts = threadInfo.getThreadState();
+ switch (ts) {
+ case BLOCKED:
+ sb.append("\t- blocked on " + threadInfo.getLockInfo());
+ sb.append('\n');
+ break;
+ case WAITING:
+ sb.append("\t- waiting on " + threadInfo.getLockInfo());
+ sb.append('\n');
+ break;
+ case TIMED_WAITING:
+ sb.append("\t- waiting on " + threadInfo.getLockInfo());
+ sb.append('\n');
+ break;
+ default:
+ }
+ }
+
+ for (MonitorInfo mi : threadInfo.getLockedMonitors()) {
+ if (mi.getLockedStackDepth() == i) {
+ sb.append("\t- locked " + mi);
+ sb.append('\n');
+ }
+ }
+ }
+ if (i < stackTrace.length) {
+ sb.append("\t...");
+ sb.append('\n');
+ }
+
+ LockInfo[] locks = threadInfo.getLockedSynchronizers();
+ if (locks.length > 0) {
+ sb.append("\n\tNumber of locked synchronizers = " + locks.length);
+ sb.append('\n');
+ for (LockInfo li : locks) {
+ sb.append("\t- " + li);
+ sb.append('\n');
+ }
+ }
+ sb.append('\n');
+ return sb.toString();
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java
new file mode 100644
index 0000000..7a01daf
--- /dev/null
+++ b/diagnostic/src/main/java/org/apache/karaf/diagnostic/core/internal/osgi/Activator.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.diagnostic.core.internal.osgi;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.karaf.diagnostic.core.DumpProvider;
+import org.apache.karaf.diagnostic.core.internal.BundleDumpProvider;
+import org.apache.karaf.diagnostic.core.internal.DiagnosticDumpMBeanImpl;
+import org.apache.karaf.diagnostic.core.internal.EnvironmentDumpProvider;
+import org.apache.karaf.diagnostic.core.internal.FeaturesDumpProvider;
+import org.apache.karaf.diagnostic.core.internal.HeapDumpProvider;
+import org.apache.karaf.diagnostic.core.internal.LogDumpProvider;
+import org.apache.karaf.diagnostic.core.internal.MemoryDumpProvider;
+import org.apache.karaf.diagnostic.core.internal.ThreadDumpProvider;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class Activator implements BundleActivator {
+
+ private List<ServiceRegistration<DumpProvider>> registrations;
+ private ServiceRegistration<DumpProvider> featuresProviderRegistration;
+ private ServiceRegistration mbeanRegistration;
+ private SingleServiceTracker<FeaturesService> featuresServiceTracker;
+ private ServiceTracker<DumpProvider, DumpProvider> providersTracker;
+
+ @Override
+ public void start(final BundleContext context) throws Exception {
+ registrations = new ArrayList<ServiceRegistration<DumpProvider>>();
+ registrations.add(context.registerService(DumpProvider.class, new BundleDumpProvider(context), null));
+ registrations.add(context.registerService(DumpProvider.class, new EnvironmentDumpProvider(context), null));
+ registrations.add(context.registerService(DumpProvider.class, new HeapDumpProvider(), null));
+ registrations.add(context.registerService(DumpProvider.class, new LogDumpProvider(context), null));
+ registrations.add(context.registerService(DumpProvider.class, new MemoryDumpProvider(), null));
+ registrations.add(context.registerService(DumpProvider.class, new ThreadDumpProvider(), null));
+
+ featuresServiceTracker = new SingleServiceTracker<FeaturesService>(context, FeaturesService.class, new SingleServiceTracker.SingleServiceListener() {
+ @Override
+ public void serviceFound() {
+ featuresProviderRegistration =
+ context.registerService(
+ DumpProvider.class,
+ new FeaturesDumpProvider(featuresServiceTracker.getService()),
+ null);
+ }
+ @Override
+ public void serviceLost() {
+ }
+ @Override
+ public void serviceReplaced() {
+ featuresProviderRegistration.unregister();
+ }
+ });
+
+ final DiagnosticDumpMBeanImpl diagnostic = new DiagnosticDumpMBeanImpl();
+ providersTracker = new ServiceTracker<DumpProvider, DumpProvider>(
+ context, DumpProvider.class, new ServiceTrackerCustomizer<DumpProvider, DumpProvider>() {
+ @Override
+ public DumpProvider addingService(ServiceReference<DumpProvider> reference) {
+ DumpProvider service = context.getService(reference);
+ diagnostic.registerProvider(service);
+ return service;
+ }
+ @Override
+ public void modifiedService(ServiceReference<DumpProvider> reference, DumpProvider service) {
+ }
+ @Override
+ public void removedService(ServiceReference<DumpProvider> reference, DumpProvider service) {
+ diagnostic.unregisterProvider(service);
+ context.ungetService(reference);
+ }
+ });
+ providersTracker.open();
+
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put("jmx.objectname", "org.apache.karaf:type=diagnostic,name=" + System.getProperty("karaf.name"));
+ mbeanRegistration = context.registerService(
+ getInterfaceNames(diagnostic),
+ diagnostic,
+ props
+ );
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ mbeanRegistration.unregister();
+ featuresServiceTracker.close();
+ providersTracker.close();
+ for (ServiceRegistration<DumpProvider> reg : registrations) {
+ reg.unregister();
+ }
+ }
+
+ private String[] getInterfaceNames(Object object) {
+ List<String> names = new ArrayList<String>();
+ for (Class cl = object.getClass(); cl != Object.class; cl = cl.getSuperclass()) {
+ addSuperInterfaces(names, cl);
+ }
+ return names.toArray(new String[names.size()]);
+ }
+
+ private void addSuperInterfaces(List<String> names, Class clazz) {
+ for (Class cl : clazz.getInterfaces()) {
+ names.add(cl.getName());
+ addSuperInterfaces(names, cl);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/886863a2/diagnostic/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/diagnostic/src/main/resources/OSGI-INF/bundle.info b/diagnostic/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..15bc3cb
--- /dev/null
+++ b/diagnostic/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,18 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+The diagnostic core bundle is the diagnostic core implementation.
+
+It's used by the diagnostic commands bundle and is responsible of the dump generation (environment, features, logs, bundles, threads).
+
+h1. See also
+
+Diagnostic - section of the Karaf User Guide.