/*******************************************************************************
* Copyright (c) 2008, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware Inc. - initial contribution
*******************************************************************************/
package org.eclipse.virgo.shell.internal.formatting;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import org.eclipse.equinox.region.Region;
import org.eclipse.equinox.region.RegionDigraph;
import org.eclipse.virgo.kernel.model.BundleArtifact;
import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
import org.eclipse.virgo.kernel.module.ModuleContext;
import org.eclipse.virgo.kernel.module.ModuleContextAccessor;
import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
import org.eclipse.virgo.shell.internal.util.QuasiBundleUtil;
import org.eclipse.virgo.shell.internal.util.QuasiServiceUtil;
import org.eclipse.virgo.shell.internal.util.ServiceHolder;
import org.eclipse.virgo.util.common.StringUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
public final class BundleInstallArtifactCommandFormatter implements InstallArtifactCommandFormatter<ManageableArtifact> {
private static final int MAX_LINE_LENGTH = 80;
private static final String ID_COLUMN_NAME = "Id";
private static final int ID_COLUMN_MIN_WIDTH = ID_COLUMN_NAME.length();
private static final String SPRING_POWERED_COLUMN_NAME = " ";
private static final int SPRING_POWERED_COLUMN_WIDTH = SPRING_POWERED_COLUMN_NAME.length();
private static final String NAME_COLUMN_NAME = "Name";
private static final int NAME_COLUMN_MIN_WIDTH = NAME_COLUMN_NAME.length();
private static final String VERSION_COLUMN_NAME = "Version";
private static final int VERSION_COLUMN_MIN_WIDTH = VERSION_COLUMN_NAME.length();
private static final String STATE_COLUMN_NAME = "State";
private static final String USER_REGION_NAME = "org.eclipse.virgo.region.user";
/**
* longest state name from {@link BundleArtifact#mapBundleState()}
*/
private static final int STATE_COLUMN_MIN_WIDTH = 11;
private final ModuleContextAccessor moduleContextAccessor;
private final Region userRegion;
private final QuasiBundleUtil quasiBundleUtil;
private QuasiServiceUtil quasiServiceUtil;
public BundleInstallArtifactCommandFormatter(RegionDigraph regionDigraph, QuasiBundleUtil quasiBundleUtil, QuasiServiceUtil quasiServiceUtil, ModuleContextAccessor moduleContextAccessor) {
this.quasiBundleUtil = quasiBundleUtil;
this.quasiServiceUtil = quasiServiceUtil;
this.moduleContextAccessor = moduleContextAccessor;
this.userRegion = regionDigraph.getRegion(USER_REGION_NAME);
}
public List<String> formatList(List<ManageableArtifact> artifacts) {
List<ArtifactHolder> artifactHolders = getArtifactHolders(artifacts);
Collections.sort(artifactHolders);
int maxIdLength = ID_COLUMN_MIN_WIDTH;
int maxNameLength = NAME_COLUMN_MIN_WIDTH;
int maxVersionLength = VERSION_COLUMN_MIN_WIDTH;
for (ArtifactHolder artifact : artifactHolders) {
final int idLength = artifact.getId().toString().length();
maxIdLength = idLength > maxIdLength ? idLength : maxIdLength;
final int nameLength = artifact.getName().length();
maxNameLength = nameLength > maxNameLength ? nameLength : maxNameLength;
final int versionLength = artifact.getVersion().length();
maxVersionLength = versionLength > maxVersionLength ? versionLength : maxVersionLength;
}
List<String> lines = new ArrayList<String>();
int stateLength = MAX_LINE_LENGTH - (4 + maxIdLength + SPRING_POWERED_COLUMN_WIDTH + maxNameLength + maxVersionLength);
if (stateLength < STATE_COLUMN_MIN_WIDTH) {
stateLength = STATE_COLUMN_MIN_WIDTH;
}
final String singleLineFormat = String.format("%%-%ds %%s %%-%ds %%-%ds %%%ds", maxIdLength, maxNameLength, maxVersionLength, stateLength);
lines.add(String.format(singleLineFormat, ID_COLUMN_NAME, SPRING_POWERED_COLUMN_NAME, NAME_COLUMN_NAME, VERSION_COLUMN_NAME,
STATE_COLUMN_NAME));
for (ArtifactHolder artifact : artifactHolders) {
lines.add(String.format(singleLineFormat, artifact.getId(), artifact.getSpringPowered() ? "S" : " ", artifact.getName(),
artifact.getVersion(), artifact.getState()));
}
return lines;
}
public List<String> formatExamine(ManageableArtifact artifact) {
List<String> lines = new ArrayList<String>();
List<QuasiBundle> quasiBundles = this.quasiBundleUtil.getAllBundles();
ArtifactHolder artifactHolder = getArtifactHolder(artifact, quasiBundles);
if (artifactHolder == null) {
lines.add("No artifact found of type '" + artifact.getType() + "' name '" + artifact.getName() + "' and version '"
+ artifact.getVersion() + "'");
} else {
lines.add(String.format("Id: %s", artifactHolder.getId()));
lines.add(String.format("Name: %s", artifactHolder.getName()));
lines.add(String.format("Version %s", artifactHolder.getVersion()));
lines.add(String.format("State: %s", artifactHolder.getState()));
lines.add(String.format("Spring Powered: %s", artifactHolder.getSpringPowered()));
String bundleLocation = artifactHolder.getBundleLocation();
lines.add(String.format("Bundle Location: %s", bundleLocation == null ? "" : bundleLocation));
lines.addAll(formatImportedPackages(artifactHolder));
lines.addAll(formatExportedPackages(artifactHolder));
lines.addAll(formatPublishedServices(artifactHolder));
lines.addAll(formatConsumedServices(artifactHolder));
lines.addAll(formatFragments(artifactHolder));
lines.addAll(formatHost(artifactHolder));
}
return lines;
}
private List<String> formatConsumedServices(ArtifactHolder artifactHolder) {
List<String> lines = new ArrayList<String>();
lines.add("");
lines.add(String.format("Consumed services:"));
List<ServiceHolder> consumedServices = artifactHolder.getConsumedServices(this.quasiServiceUtil);
if (consumedServices.isEmpty()) {
lines.add(String.format(" None"));
} else {
for (ServiceHolder consumedService : consumedServices) {
String objectClass = extractFirstObjectClass(consumedService.getProperties().get(Constants.OBJECTCLASS));
lines.add(String.format(" %3s %s", consumedService.getServiceId(), objectClass));
lines.add(String.format(" published by %s", formatBundleSummary(consumedService.getProvider())));
}
}
return lines;
}
private List<String> formatPublishedServices(ArtifactHolder artifactHolder) {
List<String> lines = new ArrayList<String>();
lines.add("");
lines.add(String.format("Published services:"));
List<ServiceHolder> publishedServices = artifactHolder.getPublishedServices(this.quasiServiceUtil);
if (publishedServices.isEmpty()) {
lines.add(String.format(" None"));
} else {
for (ServiceHolder publishedService : publishedServices) {
String objectClass = extractFirstObjectClass(publishedService.getProperties().get(Constants.OBJECTCLASS));
lines.add(String.format(" %3s %s", publishedService.getServiceId(), objectClass));
List<QuasiBundle> consumers = publishedService.getConsumers();
for (QuasiBundle consumer : consumers) {
lines.add(String.format(" consumed by %s", formatBundleSummary(consumer)));
}
}
}
return lines;
}
private String extractFirstObjectClass(Object objectClass) {
String[] objectClasses;
if (objectClass instanceof String) {
objectClasses = StringUtils.commaDelimitedListToStringArray((String) objectClass);
} else if (objectClass instanceof Object[]) {
objectClasses = (String[]) objectClass;
} else {
objectClasses = StringUtils.commaDelimitedListToStringArray(objectClass.toString());
}
if (objectClasses.length > 0) {
return objectClasses[0];
} else {
return "<no object classes>";
}
}
private List<String> formatHost(ArtifactHolder artifactHolder) {
List<String> lines = new ArrayList<String>();
List<QuasiBundle> hosts = artifactHolder.getHosts();
if (hosts != null && !hosts.isEmpty()) {
lines.add("");
lines.add(String.format("Host:"));
QuasiBundle host = hosts.get(0);
lines.add(String.format(" %s", formatBundleSummary(host)));
}
return lines;
}
private List<String> formatFragments(ArtifactHolder artifactHolder) {
List<String> lines = new ArrayList<String>();
lines.add("");
lines.add(String.format("Fragments:"));
List<QuasiBundle> fragments = artifactHolder.getFragments();
if (fragments.isEmpty()) {
lines.add(String.format(" None"));
} else {
for (QuasiBundle fragment : fragments) {
lines.add(String.format(" %s", formatBundleSummary(fragment)));
}
}
return lines;
}
private List<String> formatExportedPackages(ArtifactHolder artifactHolder) {
List<String> lines = new ArrayList<String>();
lines.add("");
lines.add(String.format("Exported Packages:"));
List<QuasiExportPackage> exportPackages = artifactHolder.getExportPackages();
if (exportPackages.isEmpty()) {
lines.add(String.format(" None"));
} else {
for (QuasiExportPackage exportPackage : exportPackages) {
lines.add(String.format(" %s %s", exportPackage.getPackageName(), exportPackage.getVersion().toString()));
for (QuasiImportPackage consumer : exportPackage.getConsumers()) {
QuasiBundle bundle = consumer.getImportingBundle();
lines.add(String.format(" imported by %s", formatBundleSummary(bundle)));
}
}
}
return lines;
}
private List<String> formatImportedPackages(ArtifactHolder artifactHolder) {
List<String> lines = new ArrayList<String>();
lines.add("");
lines.add(String.format("Imported Packages:"));
List<QuasiImportPackage> importPackages = artifactHolder.getImportPackages();
if (importPackages.isEmpty()) {
lines.add(String.format(" None"));
} else {
for (QuasiImportPackage importPackage : importPackages) {
if (importPackage.isResolved()) {
lines.add(String.format(" %s %s", importPackage.getPackageName(), importPackage.getVersionConstraint().toString()));
QuasiBundle bundle = importPackage.getProvider().getExportingBundle();
lines.add(String.format(" exported by %s", formatBundleSummary(bundle)));
}
}
}
return lines;
}
private String formatBundleSummary(QuasiBundle bundle) {
return String.format("%s %s [%s]", bundle.getSymbolicName(), bundle.getVersion(), bundle.getBundleId());
}
public List<String> formatDiag(QuasiBundle bundle, List<QuasiResolutionFailure> resolverReport) {
if (bundle == null) {
return Arrays.asList("Unable to locate bundle");
}
if (resolverReport.size() == 0) {
return Arrays.asList("No resolution errors found");
}
List<String> lines = new ArrayList<String>();
for (QuasiResolutionFailure quasiResolutionFailure : resolverReport) {
lines.add(String.format("%s", quasiResolutionFailure.getDescription()));
}
return lines;
}
public List<String> formatHeaders(QuasiBundle quasiBundle) {
if (quasiBundle == null) {
return Arrays.asList("Unable to locate bundle");
}
List<String> lines = new ArrayList<String>();
Bundle bundle = quasiBundle.getBundle();
if(bundle != null){
Dictionary<String, String> headers = bundle.getHeaders();
Enumeration<String> keys = headers.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
lines.add(String.format("%s: ", key));
lines.addAll(formatHeaderValue(headers.get(key)));
}
}
return lines;
}
private List<ArtifactHolder> getArtifactHolders(List<ManageableArtifact> artifacts) {
List<ArtifactHolder> artifactHolders = new ArrayList<ArtifactHolder>(artifacts.size());
List<QuasiBundle> bundles = this.quasiBundleUtil.getAllBundles();
for (ManageableArtifact artifact : artifacts) {
ArtifactHolder artifactHolder = getArtifactHolder(artifact, bundles);
if (artifactHolder != null) {
artifactHolders.add(artifactHolder);
}
}
return artifactHolders;
}
private ArtifactHolder getArtifactHolder(ManageableArtifact artifact, List<QuasiBundle> bundles) {
Version v = new Version(artifact.getVersion());
Set<Long> bundleIds = userRegion.getBundleIds();
for (QuasiBundle bundle : bundles) {
if (bundle.getSymbolicName().equals(artifact.getName()) && bundle.getVersion().equals(v) && bundleIds.contains(bundle.getBundleId())) {
return new ArtifactHolder(artifact, bundle, moduleContextAccessor);
}
}
return null;
}
private List<String> formatHeaderValue(String value) {
List<String> lines = new ArrayList<String>();
Reader reader = new StringReader(value);
char[] buffer = new char[71];
int length = 0;
try {
while ((length = reader.read(buffer)) != -1) {
lines.add(String.format(" %s", new String(buffer, 0, length)));
}
} catch (IOException e) {
// Do nothing
}
return lines;
}
private static class ArtifactHolder implements Comparable<ArtifactHolder> {
private final ModuleContextAccessor moduleContextAccessor;
private final ManageableArtifact artifact;
private final QuasiBundle bundle;
public ArtifactHolder(ManageableArtifact artifact, QuasiBundle bundle, ModuleContextAccessor moduleContextAccessor) {
this.artifact = artifact;
this.bundle = bundle;
this.moduleContextAccessor = moduleContextAccessor;
}
public Long getId() {
return this.bundle.getBundleId();
}
public String getName() {
return artifact.getName();
}
public String getState() {
return artifact.getState();
}
public String getVersion() {
return artifact.getVersion();
}
public String getBundleLocation() {
return this.bundle.getBundleLocation();
}
public boolean getSpringPowered() {
Bundle realBundle = bundle.getBundle();
if (realBundle != null) {
ModuleContext moduleContext = moduleContextAccessor.getModuleContext(realBundle);
if (moduleContext != null) {
return true;
}
}
return false;
}
public List<QuasiExportPackage> getExportPackages() {
return bundle.getExportPackages();
}
public List<QuasiImportPackage> getImportPackages() {
return bundle.getImportPackages();
}
public List<QuasiBundle> getFragments() {
return bundle.getFragments();
}
public List<QuasiBundle> getHosts() {
return bundle.getHosts();
}
public List<ServiceHolder> getPublishedServices(QuasiServiceUtil quasiServiceUtil) {
List<ServiceHolder> services = new ArrayList<ServiceHolder>();
List<ServiceHolder> allServices = quasiServiceUtil.getAllServices();
for (ServiceHolder quasiLiveService : allServices) {
if(quasiLiveService.getProvider().equals(bundle)){
services.add(quasiLiveService);
}
}
return services;
}
public List<ServiceHolder> getConsumedServices(QuasiServiceUtil quasiServiceUtil) {
List<ServiceHolder> services = new ArrayList<ServiceHolder>();
List<ServiceHolder> allServices = quasiServiceUtil.getAllServices();
for (ServiceHolder quasiLiveService : allServices) {
List<QuasiBundle> consumers = quasiLiveService.getConsumers();
for (QuasiBundle quasiBundle : consumers) {
if(quasiBundle.equals(bundle) && !services.contains(quasiLiveService)){
services.add(quasiLiveService);
}
}
}
return services;
}
public int compareTo(ArtifactHolder o) {
return getId().compareTo(o.getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof ArtifactHolder && getId().equals(((ArtifactHolder) obj).getId());
}
}
}