org.apache.felix.gogo.command.Inspect Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.felix.gogo.command Show documentation
Show all versions of org.apache.felix.gogo.command Show documentation
Provides basic shell commands for Gogo.
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.gogo.command;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.felix.service.command.Descriptor;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
public class Inspect
{
public static final String NONSTANDARD_SERVICE_NAMESPACE = "service";
public static final String CAPABILITY = "capability";
public static final String REQUIREMENT = "requirement";
private static final String EMPTY_MESSAGE = "[EMPTY]";
private static final String UNUSED_MESSAGE = "[UNUSED]";
private static final String UNRESOLVED_MESSAGE = "[UNRESOLVED]";
private final BundleContext m_bc;
public Inspect(BundleContext bc)
{
m_bc = bc;
}
@Descriptor("inspects bundle capabilities and requirements")
public String inspect(
@Descriptor("('capability' | 'requirement')") String direction,
@Descriptor("( | 'service')") String namespace,
@Descriptor("target bundles") Bundle[] bundles)
{
return inspect(m_bc, direction, namespace, bundles);
}
private static String inspect(
BundleContext bc, String direction, String namespace, Bundle[] bundles)
{
// Verify arguments.
if (isValidDirection(direction))
{
bundles = ((bundles == null) || (bundles.length == 0))
? bc.getBundles() : bundles;
if (CAPABILITY.startsWith(direction))
{
return printCapabilities(bc, Util.parseSubstring(namespace), bundles);
}
else
{
return printRequirements(bc, Util.parseSubstring(namespace), bundles);
}
}
return "Invalid argument: " + direction;
}
public static String printCapabilities(
BundleContext bc, List namespace, Bundle[] bundles)
{
try (Formatter f = new Formatter()) {
for (Bundle b : bundles)
{
// Print out any matching generic capabilities.
BundleWiring wiring = b.adapt(BundleWiring.class);
if (wiring != null)
{
String title = b + " provides:";
f.format("%s%n%s%n", title, Util.getUnderlineString(title.length()));
// Print generic capabilities for matching namespaces.
boolean matches = printMatchingCapabilities(wiring, namespace, f);
// Handle service capabilities separately, since they aren't part
// of the generic model in OSGi.
if (matchNamespace(namespace, NONSTANDARD_SERVICE_NAMESPACE))
{
matches |= printServiceCapabilities(b, f);
}
// If there were no capabilities for the specified namespace,
// then say so.
if (!matches)
{
f.format("%s %s%n", Util.unparseSubstring(namespace), EMPTY_MESSAGE);
}
}
else
{
f.format("Bundle %s is not resolved.",
b.getBundleId());
}
}
return f.toString();
}
}
private static boolean printMatchingCapabilities(BundleWiring wiring, List namespace, Formatter f)
{
List wires = wiring.getProvidedWires(null);
Map> aggregateCaps =
aggregateCapabilities(namespace, wires);
List allCaps = wiring.getCapabilities(null);
boolean matches = false;
for (BundleCapability cap : allCaps)
{
if (matchNamespace(namespace, cap.getNamespace()))
{
if ("osgi.service".equals(cap.getNamespace())) {
continue;
}
matches = true;
List dependents = aggregateCaps.get(cap);
Object keyAttr =
cap.getAttributes().get(cap.getNamespace());
if ("osgi.native".equals(cap.getNamespace()))
{
f.format("%s with properties:%n", cap.getNamespace());
List> sortedEntries =
new ArrayList>(cap.getAttributes().entrySet());
Collections.sort(sortedEntries, new Comparator>() {
@Override
public int compare(Entry o1, Entry o2) {
return o1.getKey().compareTo(o2.getKey());
}});
for (Entry e : sortedEntries) {
f.format(" %s = %s%n", e.getKey(), e.getValue());
}
if (dependents != null)
{
f.format(" required by:%n");
for (BundleWire wire : dependents) {
f.format(" %s%n", wire.getRequirerWiring().getBundle());
}
}
else
{
f.format(" %s%n", UNUSED_MESSAGE);
}
}
else if (dependents != null)
{
if (keyAttr != null)
{
f.format("%s; %s %s required by:%n",
cap.getNamespace(),
format(keyAttr),
getVersionFromCapability(cap));
}
else
{
f.format("%s required by:%n", cap.toString());
}
for (BundleWire wire : dependents)
{
f.format(" %s%n", wire.getRequirerWiring().getBundle());
}
}
else if (keyAttr != null)
{
f.format("%s; %s %s %s%n",
cap.getNamespace(),
format(keyAttr),
getVersionFromCapability(cap),
UNUSED_MESSAGE);
}
else
{
f.format("%s %s%n", cap, UNUSED_MESSAGE);
}
}
}
return matches;
}
private static String format(Object object) {
String retVal;
if (object.getClass().isArray() || object instanceof Collection) {
StringBuffer buffer = new StringBuffer();
@SuppressWarnings("rawtypes")
Iterable formatTarget = object.getClass().isArray() ? Arrays.asList(object) : (Iterable) object;
for (Object elem : formatTarget) {
if (buffer.length()>0) {
buffer.append(',');
}
buffer.append(elem.toString());
}
retVal = buffer.toString();
}
else {
retVal = String.valueOf(object);
}
return retVal;
}
private static Map> aggregateCapabilities(
List namespace, List wires)
{
// Aggregate matching capabilities.
Map> map =
new HashMap<>();
for (BundleWire wire : wires)
{
if (matchNamespace(namespace, wire.getCapability().getNamespace()))
{
List dependents = map.get(wire.getCapability());
if (dependents == null)
{
dependents = new ArrayList<>();
map.put(wire.getCapability(), dependents);
}
dependents.add(wire);
}
}
return map;
}
static boolean printServiceCapabilities(Bundle b, Formatter f)
{
boolean matches = false;
try
{
ServiceReference>[] refs = b.getRegisteredServices();
if ((refs != null) && (refs.length > 0))
{
matches = true;
// Print properties for each service.
for (ServiceReference> ref : refs)
{
// Print object class with "namespace".
f.format("%s; %s with properties:%n",
NONSTANDARD_SERVICE_NAMESPACE,
Util.getValueString(ref.getProperty("objectClass")));
// Print service properties.
String[] keys = ref.getPropertyKeys();
for (String key : keys)
{
if (!key.equalsIgnoreCase(Constants.OBJECTCLASS))
{
Object v = ref.getProperty(key);
f.format(" %s = %s%n", key, Util.getValueString(v));
}
}
Bundle[] users = ref.getUsingBundles();
if ((users != null) && (users.length > 0))
{
f.format(" Used by:%n");
for (Bundle user : users)
{
f.format(" %s%n", user);
}
}
}
}
}
catch (Exception ex)
{
f.format("%s%n", ex.toString());
}
return matches;
}
public static String printRequirements(
BundleContext bc, List namespace, Bundle[] bundles)
{
try (Formatter f = new Formatter()) {
for (Bundle b : bundles)
{
// Print out any matching generic requirements.
BundleWiring wiring = b.adapt(BundleWiring.class);
if (wiring != null)
{
String title = b + " requires:";
f.format("%s%n%s%n", title, Util.getUnderlineString(title.length()));
boolean matches = printMatchingRequirements(wiring, namespace, f);
// Handle service requirements separately, since they aren't part
// of the generic model in OSGi.
if (matchNamespace(namespace, NONSTANDARD_SERVICE_NAMESPACE))
{
matches |= printServiceRequirements(b, f);
}
// If there were no requirements for the specified namespace,
// then say so.
if (!matches)
{
f.format("%s %s%n", Util.unparseSubstring(namespace), EMPTY_MESSAGE);
}
}
else
{
f.format("Bundle %s is not resolved.%n",
b.getBundleId());
}
}
return f.toString();
}
}
private static boolean printMatchingRequirements(BundleWiring wiring, List namespace, Formatter f)
{
List wires = wiring.getRequiredWires(null);
Map> aggregateReqs =
aggregateRequirements(namespace, wires);
List allReqs = wiring.getRequirements(null);
boolean matches = false;
for (BundleRequirement req : allReqs)
{
if (matchNamespace(namespace, req.getNamespace()))
{
matches = true;
List providers = aggregateReqs.get(req);
if (providers != null)
{
f.format("%s; %s resolved by:%n",
req.getNamespace(),
req.getDirectives().get(Constants.FILTER_DIRECTIVE));
for (BundleWire wire : providers)
{
String msg;
Object keyAttr =
wire.getCapability().getAttributes()
.get(wire.getCapability().getNamespace());
if (keyAttr != null)
{
msg = wire.getCapability().getNamespace()
+ "; "
+ keyAttr
+ " "
+ getVersionFromCapability(wire.getCapability());
}
else
{
msg = wire.getCapability().toString();
}
f.format(" %s from %s%n", msg, wire.getProviderWiring().getBundle());
}
}
else
{
f.format("%s; %s %s%n",
req.getNamespace(),
req.getDirectives().get(Constants.FILTER_DIRECTIVE),
UNRESOLVED_MESSAGE);
}
}
}
return matches;
}
private static Map> aggregateRequirements(
List namespace, List wires)
{
// Aggregate matching capabilities.
Map> map =
new HashMap<>();
for (BundleWire wire : wires)
{
if (matchNamespace(namespace, wire.getRequirement().getNamespace()))
{
List providers = map.get(wire.getRequirement());
if (providers == null)
{
providers = new ArrayList<>();
map.put(wire.getRequirement(), providers);
}
providers.add(wire);
}
}
return map;
}
static boolean printServiceRequirements(Bundle b, Formatter f)
{
boolean matches = false;
try
{
ServiceReference>[] refs = b.getServicesInUse();
if ((refs != null) && (refs.length > 0))
{
matches = true;
// Print properties for each service.
for (ServiceReference> ref : refs)
{
// Print object class with "namespace".
f.format("%s; %s provided by:%n %s%n",
NONSTANDARD_SERVICE_NAMESPACE,
Util.getValueString(ref.getProperty("objectClass")),
ref.getBundle());
}
}
}
catch (Exception ex)
{
System.err.println(ex.toString());
}
return matches;
}
private static String getVersionFromCapability(BundleCapability c)
{
Object o = c.getAttributes().get(Constants.VERSION_ATTRIBUTE);
if (o == null)
{
o = c.getAttributes().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
}
return (o == null) ? "" : o.toString();
}
private static boolean matchNamespace(List namespace, String actual)
{
return Util.compareSubstring(namespace, actual);
}
private static boolean isValidDirection(String direction)
{
return (CAPABILITY.startsWith(direction) || REQUIREMENT.startsWith(direction));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy