package org.ow2.chameleon.fuchsia.tools.shell;
/*
* #%L
* OW2 Chameleon - Fuchsia Tool Gogo command
* %%
* Copyright (C) 2009 - 2014 OW2 Chameleon
* %%
* 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.
* #L%
*/
import org.apache.felix.ipojo.annotations.*;
import org.apache.felix.service.command.Descriptor;
import org.osgi.framework.*;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.ow2.chameleon.fuchsia.core.component.*;
import org.ow2.chameleon.fuchsia.core.declaration.Declaration;
import org.ow2.chameleon.fuchsia.core.declaration.ExportDeclaration;
import org.ow2.chameleon.fuchsia.core.declaration.ImportDeclaration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static org.apache.felix.ipojo.Factory.INSTANCE_NAME_PROPERTY;
import static org.ow2.chameleon.fuchsia.core.declaration.Constants.ID;
import static org.ow2.chameleon.fuchsia.tools.shell.util.FuchsiaGogoUtil.createASCIIBox;
import static org.ow2.chameleon.fuchsia.tools.shell.util.FuchsiaGogoUtil.getArgumentValue;
@Component(immediate = true)
@Instantiate
@Provides(specifications = FuchsiaGogoCommand.class)
@SuppressWarnings("PMD.SystemPrintln")
/**
* {@link FuchsiaGogoCommand} is basic shell command set.
* Gogo {@link http://felix.apache.org/site/apache-felix-gogo.html} is used as base for this command
*
* @author jander nascimento (botelho at imag.fr)
*/
public class FuchsiaGogoCommand {
private static final Logger LOG = LoggerFactory.getLogger(FuchsiaGogoCommand.class);
public static final int ASCIIBOX_MAX_COLUMNS = 45;
private final BundleContext context;
@ServiceProperty(name = "osgi.command.scope", value = "fuchsia")
private String scope;
@ServiceProperty(name = "osgi.command.function", value = "{}")
private String[] function = new String[]{"declarations", "declaration", "linker", "discovery", "importer", "exporter", "sendmessage"};
@Requires
private EventAdmin eventAdmin;
public FuchsiaGogoCommand(BundleContext context) {
this.context = context;
}
public void print(String message) {
System.out.println(message);
}
// ---------------- DECLARATION
@Descriptor("Gets info about the declarations available")
public void declarations(@Descriptor("declarations [--type import|export]") String... parameters) {
String type = getArgumentValue("--type", parameters);
try {
if ((type == null) || "import".equals(type)) {
List<ServiceReference> allServiceRef = getAllServiceRefs(ImportDeclaration.class);
displayDeclarationList(allServiceRef);
}
if ((type == null) || "export".equals(type)) {
List<ServiceReference> allServiceRef = getAllServiceRefs(ExportDeclaration.class);
displayDeclarationList(allServiceRef);
}
} catch (Exception e) {
LOG.error("failed to execute command", e);
print("failed to execute the command");
}
}
private String getIdentifier(Declaration declaration) {
String type = null;
if (declaration instanceof ImportDeclaration) {
type = "import";
} else if (declaration instanceof ExportDeclaration) {
type = "export";
}
return (String) declaration.getMetadata().get(ID);
}
private void displayDeclarationList(List<ServiceReference> references) {
for (ServiceReference reference : references) {
Declaration declaration = (Declaration) context.getService(reference);
String state;
if (declaration.getStatus().isBound()) {
state = " BOUND ";
} else {
state = "UNBOUND";
}
String identifier = getIdentifier(declaration);
print(String.format("[%s]\t%s%n", state, identifier));
}
}
@Descriptor("Gets info about the declaration")
public void declaration(@Descriptor("declaration [-f LDAP_FILTER] [DECLARATION_ID]") String... parameters) {
Filter filter = null;
try {
String explicitFilterArgument = getArgumentValue("-f", parameters);
if (explicitFilterArgument == null) {
String idFilterArgument = getArgumentValue(null, parameters);
if (idFilterArgument == null) {
filter = null;
} else {
filter = FrameworkUtil.createFilter(String.format("(id=%s)", idFilterArgument));
}
} else {
filter = FrameworkUtil.createFilter(getArgumentValue(null, parameters));
}
} catch (InvalidSyntaxException e) {
LOG.error("Failed to create the appropriate filter.", e);
return;
}
String type = getArgumentValue("-t", parameters);
Map<ServiceReference, Declaration> declarations = getDeclarations(type);
StringBuilder sb = displayDeclarations(declarations, filter);
print(sb.toString());
}
private Map<ServiceReference, Declaration> getDeclarations(String type) {
Map<ServiceReference, Declaration> declarations;
if ((type != null) && "import".equals(type)) {
declarations = new HashMap<ServiceReference, Declaration>(getAllServiceRefsAndServices(ImportDeclaration.class));
} else if ((type != null) && "export".equals(type)) {
declarations = new HashMap<ServiceReference, Declaration>(getAllServiceRefsAndServices(ExportDeclaration.class));
} else {
declarations = new HashMap<ServiceReference, Declaration>(getAllServiceRefsAndServices(Declaration.class));
declarations.putAll(new HashMap<ServiceReference, Declaration>(getAllServiceRefsAndServices(ImportDeclaration.class)));
declarations.putAll(new HashMap<ServiceReference, Declaration>(getAllServiceRefsAndServices(ExportDeclaration.class)));
}
return declarations;
}
private StringBuilder displayDeclarations(Map<ServiceReference, Declaration> declarations, Filter filter) {
StringBuilder sb = new StringBuilder();
if (declarations.isEmpty()) {
sb.append("No declarations found.");
}
for (Map.Entry<ServiceReference, Declaration> declaration : declarations.entrySet()) {
if (filter == null || filter.matches(declaration.getValue().getMetadata())) {
StringBuilder boxedDeclaration = createASCIIBox("Declaration", displayDeclaration(getIdentifier(declaration.getValue()), declaration.getKey(), declaration.getValue()));
sb.append(boxedDeclaration);
}
}
return sb;
}
private StringBuilder displayDeclaration(String identifier, ServiceReference reference, Declaration declaration) {
StringBuilder completeOutput = new StringBuilder();
completeOutput.append("Declaration binded to ")
.append(declaration.getStatus().getServiceReferencesBounded().size())
.append(" services.\n");
completeOutput.append("Declaration handled by ")
.append(declaration.getStatus().getServiceReferencesHandled().size())
.append(" services.\n");
StringBuilder sgMetadata = new StringBuilder();
for (Map.Entry<String, Object> entry : declaration.getMetadata().entrySet()) {
sgMetadata.append(String.format("%s = %s%n", entry.getKey(), entry.getValue()));
}
completeOutput.append(createASCIIBox("Metadata", sgMetadata));
StringBuilder sgExtraMetadata = new StringBuilder();
for (Map.Entry<String, Object> entry : declaration.getExtraMetadata().entrySet()) {
sgExtraMetadata.append(String.format("%s = %s%n", entry.getKey(), entry.getValue()));
}
completeOutput.append(createASCIIBox("Extra-Metadata", sgExtraMetadata));
StringBuilder sgProperties = new StringBuilder();
for (String propertyKey : reference.getPropertyKeys()) {
sgProperties.append(String.format("%s = %s%n", propertyKey, reference.getProperty(propertyKey)));
}
if (reference.getPropertyKeys().length == 0) {
sgProperties.append("EMPTY\n");
}
completeOutput.append(createASCIIBox("Service Properties", sgProperties));
return completeOutput;
}
// ---------------- LINKER
@Descriptor("Gets the importation/exportation linker available")
public void linker(@Descriptor("linker [-(import|export)] [ID name]") String... parameters) {
List<ServiceReference> exportationLinkerRef = getAllServiceRefs(ExportationLinker.class);
List<ServiceReference> importationLinkerRef = getAllServiceRefs(ImportationLinker.class);
StringBuilder sbFinal = new StringBuilder();
if (exportationLinkerRef.isEmpty() && importationLinkerRef.isEmpty()) {
sbFinal.append("No linkers available.\n");
} else {
if (!exportationLinkerRef.isEmpty()) {
for (ServiceReference reference : exportationLinkerRef) {
StringBuilder sb = new StringBuilder();
sb.append(displayServiceInfo(reference));
sb.append(createASCIIBox("Properties", displayServiceProperties(reference)));
sbFinal.append(createASCIIBox("Exportation Linker", sb));
}
}
if (!importationLinkerRef.isEmpty()) {
for (ServiceReference reference : importationLinkerRef) {
StringBuilder sb = new StringBuilder();
sb.append(displayServiceInfo(reference));
sb.append(createASCIIBox("Properties", displayServiceProperties(reference)));
sbFinal.append(createASCIIBox("Importation Linker", sb));
}
}
}
print(sbFinal.toString());
}
// ---------------- DISCOVERY
@Descriptor("Gets the discovery available in the platform")
public void discovery(@Descriptor("discovery [discovery name]") String... parameters) {
List<ServiceReference> discoveryRef = getAllServiceRefs(DiscoveryService.class);
StringBuilder sbFinal = new StringBuilder();
if (discoveryRef.isEmpty()) {
sbFinal.append("No discovery available.\n");
} else {
for (ServiceReference reference : discoveryRef) {
StringBuilder sb = new StringBuilder();
sb.append(displayServiceInfo(reference));
sb.append(createASCIIBox("Properties", displayServiceProperties(reference)));
sbFinal.append(createASCIIBox("Discovery", sb));
}
}
print(sbFinal.toString());
}
// ---------------- IMPORTER
@Descriptor("Gets the importer available in the platform")
public void importer(@Descriptor("importer [importer name]") String... parameters) {
Map<ServiceReference, ImporterService> importerRefsAndServices = getAllServiceRefsAndServices(ImporterService.class);
StringBuilder sbFinal = new StringBuilder();
if (importerRefsAndServices.isEmpty()) {
sbFinal.append("No importers available.\n");
} else {
for (Map.Entry<ServiceReference, ImporterService> e : importerRefsAndServices.entrySet()) {
StringBuilder sb = new StringBuilder();
sb.append(displayServiceInfo(e.getKey()));
sb.append(String.format("importer name = %s%n", e.getValue().getName()));
sb.append(createASCIIBox("Properties", displayServiceProperties(e.getKey())));
sbFinal.append(createASCIIBox("Importer", sb));
}
}
print(sbFinal.toString());
}
// ---------------- EXPORTER
@Descriptor("Gets the exporter available in the platform")
public void exporter(@Descriptor("exporter [exporter name]") String... parameters) {
Map<ServiceReference, ExporterService> exporterRefsAndServices = getAllServiceRefsAndServices(ExporterService.class);
StringBuilder sbFinal = new StringBuilder();
if (exporterRefsAndServices.isEmpty()) {
print("No exporter available.");
} else {
for (Map.Entry<ServiceReference, ExporterService> e : exporterRefsAndServices.entrySet()) {
StringBuilder sb = new StringBuilder();
sb.append(displayServiceInfo(e.getKey()));
sb.append(String.format("exporter name = %s%n", e.getValue().getName()));
sb.append(createASCIIBox("Properties", displayServiceProperties(e.getKey())));
sbFinal.append(createASCIIBox("Exporter", sb));
}
}
print(sbFinal.toString());
}
// ---------------- SEND MESSAGE
@Descriptor("Send event admin messages")
public void sendmessage(@Descriptor("sendmessage BUS [KEY=VALUE ]*") String... parameters) {
assert parameters[0] != null;
String bus = parameters[0];
Dictionary eventAdminPayload = new Hashtable();
for (String m : parameters) {
if (m.contains("=")) {
StringTokenizer st = new StringTokenizer(m, "=");
assert st.countTokens() == 2;
String key = st.nextToken();
String value = st.nextToken();
eventAdminPayload.put(key, value);
}
}
Event eventAdminMessage = new Event(bus, eventAdminPayload);
print(String.format("Sending message to the bus %s with the arguments %s", bus, eventAdminPayload));
print("Event admin message sent");
eventAdmin.sendEvent(eventAdminMessage);
}
// ---------------- UTILS SERVICES
private <T> List<ServiceReference> getAllServiceRefs(Class<T> klass) {
ServiceReference[] importDeclarationsRef;
try {
importDeclarationsRef = context.getAllServiceReferences(klass.getName(), null);
} catch (InvalidSyntaxException e) {
LOG.error("Failed to retrieved services " + klass.getName(), e);
return new ArrayList<ServiceReference>();
}
if (importDeclarationsRef != null) {
return Arrays.asList(importDeclarationsRef);
}
return new ArrayList<ServiceReference>();
}
private <T> List<T> getAllServices(Class<T> klass) {
List<T> services = new ArrayList<T>();
for (ServiceReference sr : getAllServiceRefs(klass)) {
services.add((T) context.getService(sr));
}
return services;
}
private <T> Map<ServiceReference, T> getAllServiceRefsAndServices(Class<T> klass) {
Map<ServiceReference, T> services = new HashMap<ServiceReference, T>();
for (ServiceReference sr : getAllServiceRefs(klass)) {
services.put(sr, (T) context.getService(sr));
}
return services;
}
// ---------------- UTILS DISPLAY
private static StringBuilder displayServiceProperties(ServiceReference reference) {
StringBuilder sb = new StringBuilder();
for (String propertyKey : reference.getPropertyKeys()) {
sb.append(String.format("%s = %s%n", propertyKey, reference.getProperty(propertyKey)));
}
if (reference.getPropertyKeys().length == 0) {
sb.append("EMPTY");
}
return sb;
}
private static StringBuilder displayServiceInfo(ServiceReference reference) {
StringBuilder sb = new StringBuilder();
sb.append("name:").append(reference.getProperty(INSTANCE_NAME_PROPERTY)).append('\n');
sb.append("bundle:").append(reference.getBundle().getSymbolicName()).append('[')
.append(reference.getBundle().getBundleId())
.append(']').append('\n');
return sb;
}
}