blob: 56aac3baaf20483fb6f1a6ff31f5326fe79576f7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2011 IBM Corporation, SAP AG.
* 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:
* Thomas Watson, IBM Corporation - initial API and implementation
* Lazar Kirchev, SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.console.command.adapter;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import org.apache.felix.service.command.CommandProcessor;
import org.apache.felix.service.command.CommandSession;
import org.eclipse.equinox.console.commands.DisconnectCommand;
import org.eclipse.equinox.console.commands.EquinoxCommandProvider;
import org.eclipse.equinox.console.commands.HelpCommand;
import org.eclipse.equinox.console.commands.ManCommand;
import org.eclipse.equinox.console.ssh.SshCommand;
import org.eclipse.equinox.console.telnet.TelnetCommand;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.eclipse.osgi.framework.console.ConsoleSession;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.startlevel.StartLevel;
import org.osgi.service.permissionadmin.PermissionAdmin;
import org.eclipse.osgi.service.resolver.PlatformAdmin;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator implements BundleActivator {
private ServiceTracker<StartLevel, ?> startLevelManagerTracker;
private ServiceTracker<ConditionalPermissionAdmin, ?> condPermAdminTracker;
private ServiceTracker<PermissionAdmin, ?> permissionAdminTracker;
private ServiceTracker<PackageAdmin, PackageAdmin> packageAdminTracker;
private ServiceTracker<PlatformAdmin, ?> platformAdminTracker;
private static List<TelnetCommand> telnetConnections = new ArrayList<TelnetCommand>();
private static List<SshCommand> sshConnections = new ArrayList<SshCommand>();
private ServiceTracker<CommandProcessor, ServiceTracker<ConsoleSession, CommandSession>> commandProcessorTracker;
// Tracker for Equinox CommandProviders
private ServiceTracker<CommandProvider, List<ServiceRegistration<?>>> commandProviderTracker;
private EquinoxCommandProvider equinoxCmdProvider;
public static class ProcessorCustomizer implements
ServiceTrackerCustomizer<CommandProcessor, ServiceTracker<ConsoleSession, CommandSession>> {
private final BundleContext context;
public ProcessorCustomizer(BundleContext context) {
this.context = context;
}
public ServiceTracker<ConsoleSession, CommandSession> addingService(
ServiceReference<CommandProcessor> reference) {
CommandProcessor processor = context.getService(reference);
if (processor == null)
return null;
TelnetCommand telnetCommand = new TelnetCommand(processor, context);
telnetCommand.start();
telnetConnections.add(telnetCommand);
SshCommand sshCommand = new SshCommand(processor, context);
sshCommand.start();
sshConnections.add(sshCommand);
ServiceTracker<ConsoleSession, CommandSession> tracker = new ServiceTracker<ConsoleSession, CommandSession>(context, ConsoleSession.class, new SessionCustomizer(context, processor));
tracker.open();
return tracker;
}
public void modifiedService(
ServiceReference<CommandProcessor> reference,
ServiceTracker<ConsoleSession, CommandSession> service) {
// nothing
}
public void removedService(
ServiceReference<CommandProcessor> reference,
ServiceTracker<ConsoleSession, CommandSession> tracker) {
tracker.close();
}
}
// Provides support for Equinox ConsoleSessions
public static class SessionCustomizer implements
ServiceTrackerCustomizer<ConsoleSession, CommandSession> {
private final BundleContext context;
final CommandProcessor processor;
public SessionCustomizer(BundleContext context, CommandProcessor processor) {
this.context = context;
this.processor = processor;
}
public CommandSession addingService(
ServiceReference<ConsoleSession> reference) {
final ConsoleSession equinoxSession = context.getService(reference);
if (equinoxSession == null)
return null;
PrintStream output = new PrintStream(equinoxSession.getOutput());
final CommandSession gogoSession = processor.createSession(equinoxSession.getInput(), output, output);
new Thread(new Runnable(){
public void run() {
try {
gogoSession.put("SCOPE", "equinox:*");
gogoSession.put("prompt", "osgi> ");
gogoSession.execute("gosh --login --noshutdown");
}
catch (Exception e) {
e.printStackTrace();
}
finally {
gogoSession.close();
equinoxSession.close();
}
}
}, "Equinox Console Session").start();
return null;
}
public void modifiedService(ServiceReference<ConsoleSession> reference,
CommandSession service) {
// nothing
}
public void removedService(ServiceReference<ConsoleSession> reference,
CommandSession session) {
session.close();
}
}
// All commands, provided by an Equinox CommandProvider, are registered as provided by a CommandProviderAdapter.
public class CommandCustomizer implements
ServiceTrackerCustomizer<CommandProvider, List<ServiceRegistration<?>>> {
private BundleContext context;
public CommandCustomizer(BundleContext context) {
this.context = context;
}
public List<ServiceRegistration<?>> addingService(ServiceReference<CommandProvider> reference) {
if (reference.getProperty("osgi.command.function") != null) {
// must be a gogo function already; don' track
return null;
}
CommandProvider command = context.getService(reference);
try {
Method[] commandMethods = getCommandMethods(command);
if (commandMethods.length > 0) {
List<ServiceRegistration<?>> registrations = new ArrayList<ServiceRegistration<?>>();
registrations.add(context.registerService(Object.class, new CommandProviderAdapter((CommandProvider) command, commandMethods), getAttributes(commandMethods)));
return registrations;
} else {
context.ungetService(reference);
return null;
}
} catch (Exception e) {
context.ungetService(reference);
return null;
}
}
public void modifiedService(ServiceReference<CommandProvider> reference, List<ServiceRegistration<?>> service) {
// Nothing to do.
}
public void removedService(ServiceReference<CommandProvider> reference, List<ServiceRegistration<?>> registrations) {
for (ServiceRegistration<?> serviceRegistration : registrations) {
serviceRegistration.unregister();
}
}
}
public void start(BundleContext context) throws Exception {
commandProviderTracker = new ServiceTracker<CommandProvider, List<ServiceRegistration<?>>>(context, CommandProvider.class.getName(), new CommandCustomizer(context));
commandProviderTracker.open();
commandProcessorTracker = new ServiceTracker<CommandProcessor, ServiceTracker<ConsoleSession,CommandSession>>(context, CommandProcessor.class, new ProcessorCustomizer(context));
commandProcessorTracker.open();
condPermAdminTracker = new ServiceTracker<ConditionalPermissionAdmin, Object>(context, ConditionalPermissionAdmin.class.getName(), null);
condPermAdminTracker.open();
// grab permission admin
permissionAdminTracker = new ServiceTracker<PermissionAdmin, Object>(context, PermissionAdmin.class.getName(), null);
permissionAdminTracker.open();
startLevelManagerTracker = new ServiceTracker<StartLevel, Object>(context, StartLevel.class.getName(), null);
startLevelManagerTracker.open();
packageAdminTracker = new ServiceTracker<PackageAdmin, PackageAdmin>(context, PackageAdmin.class, null);
packageAdminTracker.open();
platformAdminTracker = new ServiceTracker<PlatformAdmin, Object>(context, PlatformAdmin.class.getName(), null);
platformAdminTracker.open();
equinoxCmdProvider = new EquinoxCommandProvider(context, this);
equinoxCmdProvider.start();
HelpCommand helpCommand = new HelpCommand(context);
helpCommand.start();
ManCommand manCommand = new ManCommand(context);
manCommand.start();
DisconnectCommand disconnectCommand = new DisconnectCommand(context);
disconnectCommand.start();
startBundle("org.apache.felix.gogo.runtime", true);
startBundle("org.apache.felix.gogo.shell", true);
startBundle("org.apache.felix.gogo.command", false);
}
private void startBundle(String bsn, boolean required) throws BundleException {
PackageAdmin pa = packageAdminTracker.getService();
if (pa != null) {
@SuppressWarnings("deprecation")
Bundle[] shells = pa.getBundles(bsn, null);
if (shells != null && shells.length > 0) {
shells[0].start(Bundle.START_TRANSIENT);
} else if (required) {
throw new BundleException("Missing required bundle: " + bsn);
}
}
}
public StartLevel getStartLevel() {
return (StartLevel) getServiceFromTracker(startLevelManagerTracker, StartLevel.class.getName());
}
public PermissionAdmin getPermissionAdmin() {
return (PermissionAdmin) getServiceFromTracker(permissionAdminTracker, PermissionAdmin.class.getName());
}
public ConditionalPermissionAdmin getConditionalPermissionAdmin() {
return (ConditionalPermissionAdmin) getServiceFromTracker(condPermAdminTracker, ConditionalPermissionAdmin.class.getName());
}
public PackageAdmin getPackageAdmin() {
return (PackageAdmin) getServiceFromTracker(packageAdminTracker, PackageAdmin.class.getName());
}
public PlatformAdmin getPlatformAdmin() {
return (PlatformAdmin) getServiceFromTracker(platformAdminTracker, PlatformAdmin.class.getName());
}
private static Object getServiceFromTracker(ServiceTracker<?, ?> tracker, String serviceClass) {
if (tracker == null)
throw new IllegalStateException("Missing service: " + serviceClass);
Object result = tracker.getService();
if (result == null)
throw new IllegalStateException("Missing service: " + serviceClass);
return result;
}
Method[] getCommandMethods(Object command) {
ArrayList<Method> names = new ArrayList<Method>();
Class<?> c = command.getClass();
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().startsWith("_")
&& method.getModifiers() == Modifier.PUBLIC && !method.getName().equals("_help")) {
Type[] types = method.getGenericParameterTypes();
if (types.length == 1
&& types[0].equals(CommandInterpreter.class)) {
names.add(method);
}
}
}
return names.toArray(new Method[names.size()]);
}
Dictionary<String, Object> getAttributes(Method[] commandMethods) {
Dictionary<String, Object> dict = new Hashtable<String, Object>();
dict.put("osgi.command.scope", "equinox");
String[] methodNames = new String[commandMethods.length];
for (int i = 0; i < commandMethods.length; i++) {
String methodName = "" + commandMethods[i].getName().substring(1);
methodNames[i] = methodName;
}
dict.put("osgi.command.function", methodNames);
return dict;
}
public void stop(BundleContext context) throws Exception {
commandProviderTracker.close();
commandProcessorTracker.close();
if (equinoxCmdProvider != null) {
equinoxCmdProvider.stop();
}
for (TelnetCommand telnetCommand : telnetConnections) {
try {
telnetCommand.telnet(new String[]{"stop"});
} catch (Exception e) {
// expected if the telnet server is not started
}
}
for (SshCommand sshCommand : sshConnections) {
try {
sshCommand.ssh(new String[]{"stop"});
} catch (Exception e) {
// expected if the ssh server is not started
}
}
}
}