package org.springframework.roo.felix;
import java.io.PrintStream;
import java.util.logging.Level;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.shell.ShellService;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.shell.CliCommand;
import org.springframework.roo.shell.CliOption;
import org.springframework.roo.shell.CommandMarker;
import org.springframework.roo.shell.ExitShellRequest;
import org.springframework.roo.shell.Shell;
import org.springframework.roo.shell.converters.StaticFieldConverter;
import org.springframework.roo.shell.event.ShellStatus;
import org.springframework.roo.shell.event.ShellStatus.Status;
import org.springframework.roo.shell.event.ShellStatusListener;
import org.springframework.roo.support.logging.LoggingOutputStream;
/**
* Delegates to commands provided via Felix's Shell API.
* <p>
* Also monitors the Roo Shell to determine when it wishes to shutdown. This
* shutdown request is then passed through to Felix for processing.
*
* @author Ben Alex
*/
@Component(immediate = true)
@Service
public class FelixDelegator implements CommandMarker, ShellStatusListener {
private ComponentContext context;
@Reference private Shell rooShell;
@Reference private ShellService shellService;
@Reference private StaticFieldConverter staticFieldConverter;
protected void activate(final ComponentContext context) {
this.context = context;
rooShell.addShellStatusListener(this);
staticFieldConverter.add(LogLevel.class);
staticFieldConverter.add(PsOptions.class);
}
protected void deactivate(final ComponentContext context) {
this.context = null;
rooShell.removeShellStatusListener(this);
staticFieldConverter.remove(LogLevel.class);
staticFieldConverter.remove(PsOptions.class);
}
@CliCommand(value = "osgi find", help = "Finds bundles by name")
public void find(
@CliOption(key = "bundleSymbolicName", mandatory = true, help = "A bundle symbolic name to find") final BundleSymbolicName bsn)
throws Exception {
perform("find " + bsn.getKey());
}
@CliCommand(value = "osgi headers", help = "Display headers for a specific bundle")
public void headers(
@CliOption(key = "bundleSymbolicName", mandatory = false, help = "Limit results to a specific bundle symbolic name") final BundleSymbolicName bsn)
throws Exception {
if (bsn == null) {
perform("headers");
}
else {
perform("headers "
+ bsn.findBundleIdWithoutFail(context.getBundleContext()));
}
}
@CliCommand(value = "osgi install", help = "Installs a bundle JAR from a given URL")
public void install(
@CliOption(key = "url", mandatory = true, help = "The URL to obtain the bundle from") final String url)
throws Exception {
perform("install " + url);
}
@CliCommand(value = "osgi log", help = "Displays the OSGi log information")
public void log(
@CliOption(key = "maximumEntries", mandatory = false, help = "The maximum number of log messages to display") final Integer maximumEntries,
@CliOption(key = "level", mandatory = false, help = "The minimum level of messages to display") final LogLevel logLevel)
throws Exception {
final StringBuilder sb = new StringBuilder();
sb.append("log");
if (maximumEntries != null) {
sb.append(" ").append(maximumEntries);
}
if (logLevel != null) {
sb.append(" ").append(logLevel.getFelixCode());
}
perform(sb.toString());
}
@CliCommand(value = "osgi ps", help = "Displays OSGi bundle information")
public void log(
@CliOption(key = "format", mandatory = false, specifiedDefaultValue = "BUNDLE_NAME", unspecifiedDefaultValue = "BUNDLE_NAME", help = "The format of bundle information") final PsOptions format)
throws Exception {
final StringBuilder sb = new StringBuilder();
sb.append("ps");
if (format != null) {
sb.append(format.getFelixCode());
}
perform(sb.toString());
}
@CliCommand(value = "osgi obr deploy", help = "Deploys a specific OSGi Bundle Repository (OBR) bundle")
public void obrDeploy(
@CliOption(key = "bundleSymbolicName", mandatory = true, optionContext = "obr", help = "The specific bundle to deploy") final BundleSymbolicName bsn)
throws Exception {
perform("obr deploy " + bsn.getKey());
}
@CliCommand(value = "osgi obr info", help = "Displays information on a specific OSGi Bundle Repository (OBR) bundle")
public void obrInfo(
@CliOption(key = "bundleSymbolicName", mandatory = true, optionContext = "obr", help = "The specific bundle to display information for") final BundleSymbolicName bsn)
throws Exception {
perform("obr info " + bsn.getKey());
}
@CliCommand(value = "osgi obr list", help = "Lists all available bundles from the OSGi Bundle Repository (OBR) system")
public void obrList(
@CliOption(key = "keywords", mandatory = false, help = "Keywords to locate") final String keywords)
throws Exception {
final StringBuilder sb = new StringBuilder();
sb.append("obr list -v");
if (keywords != null) {
sb.append(" ").append(keywords);
}
perform(sb.toString());
}
@CliCommand(value = "osgi obr start", help = "Starts a specific OSGi Bundle Repository (OBR) bundle")
public void obrStart(
@CliOption(key = "bundleSymbolicName", mandatory = true, optionContext = "obr", help = "The specific bundle to start") final BundleSymbolicName bsn)
throws Exception {
perform("obr start " + bsn.getKey());
}
@CliCommand(value = "osgi obr url add", help = "Adds a new OSGi Bundle Repository (OBR) repository file URL")
public void obrUrlAdd(
@CliOption(key = "url", mandatory = true, help = "The URL to add (eg http://felix.apache.org/obr/releases.xml)") final String url)
throws Exception {
perform("obr add-url " + url);
}
@CliCommand(value = "osgi obr url list", help = "Lists the currently-configured OSGi Bundle Repository (OBR) repository file URLs")
public void obrUrlList() throws Exception {
perform("obr list-url");
}
@CliCommand(value = "osgi obr url refresh", help = "Refreshes an existing OSGi Bundle Repository (OBR) repository file URL")
public void obrUrlRefresh(
@CliOption(key = "url", mandatory = true, help = "The URL to refresh (list existing URLs via 'osgi obr url list')") final String url)
throws Exception {
perform("obr refresh-url " + url);
}
@CliCommand(value = "osgi obr url remove", help = "Removes an existing OSGi Bundle Repository (OBR) repository file URL")
public void obrUrlRemove(
@CliOption(key = "url", mandatory = true, help = "The URL to remove (list existing URLs via 'osgi obr url list')") final String url)
throws Exception {
perform("obr remove-url " + url);
}
public void onShellStatusChange(final ShellStatus oldStatus,
final ShellStatus newStatus) {
if (newStatus.getStatus().equals(Status.SHUTTING_DOWN)) {
try {
if (rooShell != null) {
if (rooShell.getExitShellRequest() != null) {
// ROO-836
System.setProperty("roo.exit", Integer
.toString(rooShell.getExitShellRequest()
.getExitCode()));
}
System.setProperty("developmentMode",
Boolean.toString(rooShell.isDevelopmentMode()));
}
perform("shutdown");
}
catch (final Exception e) {
throw new IllegalStateException(e);
}
}
}
private void perform(final String commandLine) throws Exception {
final LoggingOutputStream sysOut = new LoggingOutputStream(Level.INFO);
final LoggingOutputStream sysErr = new LoggingOutputStream(Level.SEVERE);
sysOut.setSourceClassName(FelixDelegator.class.getName());
sysErr.setSourceClassName(FelixDelegator.class.getName());
final PrintStream printStreamOut = new PrintStream(sysOut);
final PrintStream printErrOut = new PrintStream(sysErr);
try {
shellService.executeCommand(commandLine, printStreamOut,
printErrOut);
}
finally {
printStreamOut.close();
printErrOut.close();
}
}
@CliCommand(value = { "exit", "quit" }, help = "Exits the shell")
public ExitShellRequest quit() {
return ExitShellRequest.NORMAL_EXIT;
}
@CliCommand(value = "osgi resolve", help = "Resolves a specific bundle ID")
public void resolve(
@CliOption(key = "bundleSymbolicName", mandatory = true, help = "The specific bundle to resolve") final BundleSymbolicName bsn)
throws Exception {
perform("resolve "
+ bsn.findBundleIdWithoutFail(context.getBundleContext()));
}
@CliCommand(value = "osgi scr config", help = "Lists the current SCR configuration")
public void scrConfig() throws Exception {
perform("scr config");
}
@CliCommand(value = "osgi scr disable", help = "Disables a specific SCR-defined component")
public void scrDisable(
@CliOption(key = "componentId", mandatory = true, help = "The specific component identifier (use 'osgi scr list' to list component identifiers)") final Integer id)
throws Exception {
perform("scr disable " + id);
}
@CliCommand(value = "osgi scr enable", help = "Enables a specific SCR-defined component")
public void scrEnable(
@CliOption(key = "componentId", mandatory = true, help = "The specific component identifier (use 'osgi scr list' to list component identifiers)") final Integer id)
throws Exception {
perform("scr enable " + id);
}
@CliCommand(value = "osgi scr info", help = "Lists information about a specific SCR-defined component")
public void scrInfo(
@CliOption(key = "componentId", mandatory = true, help = "The specific component identifier (use 'osgi scr list' to list component identifiers)") final Integer id)
throws Exception {
perform("scr info " + id);
}
@CliCommand(value = "osgi scr list", help = "Lists all SCR-defined components")
public void scrList(
@CliOption(key = "bundleId", mandatory = false, help = "Limit results to a specific bundle") final BundleSymbolicName bsn)
throws Exception {
if (bsn == null) {
perform("scr list");
}
else {
perform("scr list "
+ bsn.findBundleIdWithoutFail(context.getBundleContext()));
}
}
@CliCommand(value = "osgi framework command", help = "Passes a command directly through to the Felix shell infrastructure")
public void shell(
@CliOption(key = "", mandatory = false, specifiedDefaultValue = "help", unspecifiedDefaultValue = "help", help = "The command to pass to Felix (WARNING: no validation or security checks are performed)") final String commandLine)
throws Exception {
perform(commandLine);
}
@CliCommand(value = "osgi start", help = "Starts a bundle JAR from a given URL")
public void start(
@CliOption(key = "url", mandatory = true, help = "The URL to obtain the bundle from") final String url)
throws Exception {
perform("start " + url);
}
@CliCommand(value = "osgi uninstall", help = "Uninstalls a specific bundle")
public void uninstall(
@CliOption(key = "bundleSymbolicName", mandatory = true, help = "The specific bundle to uninstall") final BundleSymbolicName bsn)
throws Exception {
perform("uninstall "
+ bsn.findBundleIdWithoutFail(context.getBundleContext()));
}
@CliCommand(value = "osgi update", help = "Updates a specific bundle")
public void update(
@CliOption(key = "bundleSymbolicName", mandatory = true, help = "The specific bundle to update ") final BundleSymbolicName bsn,
@CliOption(key = "url", mandatory = false, help = "The URL to obtain the updated bundle from") final String url)
throws Exception {
final Long id = bsn.findBundleIdWithoutFail(context.getBundleContext());
if (url == null) {
perform("update " + id);
}
else {
perform("update " + id + " " + url);
}
}
@CliCommand(value = "osgi version", help = "Displays OSGi framework version")
public void version() throws Exception {
perform("version");
}
}