/*******************************************************************************
 * Copyright (c) 2003, 2011 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *     Lazar Kirchev, SAP AG - derivative implementation to migrate the commands from FrameworkCommandProvider to Gogo shell commands
 *******************************************************************************/

package org.eclipse.equinox.console.commands;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TreeSet;

import org.apache.felix.service.command.CommandProcessor;
import org.apache.felix.service.command.Converter;
import org.apache.felix.service.command.Descriptor;
import org.apache.felix.service.command.Parameter;
import org.eclipse.equinox.console.command.adapter.Activator;
import org.eclipse.osgi.service.environment.EnvironmentInfo;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.BundleSpecification;
import org.eclipse.osgi.service.resolver.DisabledInfo;
import org.eclipse.osgi.service.resolver.ExportPackageDescription;
import org.eclipse.osgi.service.resolver.GenericSpecification;
import org.eclipse.osgi.service.resolver.HostSpecification;
import org.eclipse.osgi.service.resolver.ImportPackageSpecification;
import org.eclipse.osgi.service.resolver.NativeCodeSpecification;
import org.eclipse.osgi.service.resolver.PlatformAdmin;
import org.eclipse.osgi.service.resolver.ResolverError;
import org.eclipse.osgi.service.resolver.State;
import org.eclipse.osgi.service.resolver.StateHelper;
import org.eclipse.osgi.service.resolver.VersionConstraint;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
import org.osgi.service.condpermadmin.ConditionalPermissionInfo;
import org.osgi.service.condpermadmin.ConditionalPermissionUpdate;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.packageadmin.RequiredBundle;
import org.osgi.service.permissionadmin.PermissionAdmin;
import org.osgi.service.startlevel.StartLevel;

/**
 * This class provides methods to execute commands from the command line.  It registers
 * itself as a service so it can be invoked by a CommandProcessor. 
 *
 * The commands provided by this class are:
 ---Controlling the OSGi framework---
 close - shutdown and exit
 exit - exit immediately (System.exit)
 gc - perform a garbage collection
 init - uninstall all bundles
 launch - start the Service Management Framework
 setprop <key>=<value> - set the OSGI property
 shutdown - shutdown the Service Management Framework
 ---Controlliing Bundles---
 install <url> {s[tart]} - install and optionally start bundle from the given URL
 refresh (<id>|<location>) - refresh the packages of the specified bundles
 start (<id>|<location>) - start the specified bundle(s)
 stop (<id>|<location>) - stop the specified bundle(s)
 uninstall (<id>|<location>) - uninstall the specified bundle(s)
 update (<id>|<location>|<*>) - update the specified bundle(s)
 ---Displaying Status---
 bundle (<id>|<location>) - display details for the specified bundle(s)
 bundles - display details for all installed bundles
 headers (<id>|<location>) - print bundle headers
 packages {<pkgname>|<id>|<location>} - display imported/exported package details
 props - display System properties
 services {filter} - display registered service details. Examples for [filter]: (objectClass=com.xyz.Person); (&(objectClass=com.xyz.Person)(|(sn=Jensen)(cn=Babs J*))); passing only com.xyz.Person is a shortcut for (objectClass=com.xyz.Person). The filter syntax specification is available at http://www.ietf.org/rfc/rfc1960.txt
 ss - display installed bundles (short status)
 status - display installed bundles and registered services
 threads - display threads and thread groups
 ---Extras---
 exec <command> - execute a command in a separate process and wait
 fork <command> - execute a command in a separate process
 getprop <name> -  Displays the system properties with the given name, or all of them.
 requiredBundles [<bsn>] - lists required bundles having the specified symbolic name or all if no bsn is specified
 classSpaces [<bsn>] - lists required bundles having the specified symbolic name or all if no bsn is specified
 ---Controlling StartLevel---
 sl {(<id>|<location>)} - display the start level for the specified bundle, or for the framework if no bundle specified
 setfwsl <start level> - set the framework start level
 setbsl <start level> (<id>|<location>) - set the start level for the bundle(s)
 setibsl <start level> - set the initial bundle start level
 ---Eclipse Runtime commands---
 diag - Displays unsatisfied constraints for the specified bundle(s)
 enableBundle - Enable the specified bundle(s)
 disableBundle - Disable the specified bundle(s)
 disabledBundles - List disabled bundles in the system
*/

public class EquinoxCommandProvider implements SynchronousBundleListener {

	/** The system bundle context */
	private final BundleContext context;
	private ServiceRegistration<?> providerReg;
	private ServiceRegistration<?> converterReg;

	/** Strings used to format other strings */
	private final static String tab = "\t"; //$NON-NLS-1$
	private final static String newline = "\r\n"; //$NON-NLS-1$

	/** this list contains the bundles known to be lazily awaiting activation */
	private final List<Bundle> lazyActivation = new ArrayList<Bundle>();
	
	private Activator activator;
	
	/** commands provided by this command provider */ 
	private static final String[] functions = new String[] {"exit", "shutdown", "sta", "start", "sto", "stop", "i", 
		"install", "up", "up", "up", "update", "update", "update", "un", "uninstall", "s", "status", "se", "services",
		"p", "p", "packages", "packages", "bundles", "b", "bundle", "gc", "init", "close", "r", "refresh", "exec",
		"fork", "h", "headers", "pr", "props", "setp", "setprop", "ss", "t", "threads", "sl", "setfwsl", "setbsl",
		"setibsl", "requiredBundles", "classSpaces", "profilelog", "getPackages", "getprop", "diag", "enableBundle", 
		"disableBundle", "disabledBundles"};
	
	private static final String POLICY_CONSOLE = "org.eclipse.equinox.console"; //$NON-NLS-1$
	
	/**
	 *  Constructor.
	 *
	 *  start() must be called after creating this object.
	 *
	 *  @param framework The current instance of the framework
	 */
	public EquinoxCommandProvider(BundleContext context, Activator activator) {
		this.context = context;
		this.activator = activator;
	}

	/**
	 *  Starts this CommandProvider.
	 *
	 *  Registers this object as a service providing commands
	 *  Adds this object as a SynchronousBundleListener.
	 */
	public void start() {
		EquinoxCommandsConverter converter = new EquinoxCommandsConverter(context);
		converterReg = context.registerService(Converter.class.getName(), converter, null);
		
		Dictionary<String, Object> props = new Hashtable<String, Object>();
		props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
		props.put(CommandProcessor.COMMAND_SCOPE, "equinox");
		props.put(CommandProcessor.COMMAND_FUNCTION, functions);
		providerReg = context.registerService(EquinoxCommandProvider.class.getName(), this, props);
		context.addBundleListener(this);
	}

	public void stop() {
		if (converterReg != null) {
			converterReg.unregister();
		}
		
		context.removeBundleListener(this);
		
		if (providerReg != null) {
			providerReg.unregister();
		}
	}

	/**
	 *  Handle the exit command.  Exit immediately (System.exit)
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_EXIT_COMMAND_DESCRIPTION)
	public void exit() throws Exception {
		System.out.println();
		System.exit(0);
	}

	/**
	 *  Handle the shutdown command.  Shutdown the OSGi framework.
	 *
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SHUTDOWN_COMMAND_DESCRIPTION)
	public void shutdown() throws Exception {
		context.getBundle(0).stop();
	}

	/**
	 *  Handle the start command's abbreviation.  Invoke start()
	 *
	 *  @param bundles bundle(s) to be started
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_START_COMMAND_DESCRIPTION)
	public void sta(@Descriptor(ConsoleMsg.CONSOLE_HELP_START_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		start(bundles);
	}

	/**
	 *  Handle the start command.  Start the specified bundle(s).
	 *
	 *  @param bundles bundle(s) to be started
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_START_COMMAND_DESCRIPTION)
	public void start(@Descriptor(ConsoleMsg.CONSOLE_HELP_START_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		if (bundles == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		if (bundles.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		for(Bundle bundle : bundles) {
				bundle.start();
		}
	}

	/**
	 *  Handle the stop command's abbreviation.  Invoke stop()
	 *
	 *  @param bundles bundle(s) to be stopped.
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_STOP_COMMAND_DESCRIPTION)
	public void sto(@Descriptor(ConsoleMsg.CONSOLE_HELP_STOP_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		stop(bundles);
	}

	/**
	 *  Handle the stop command.  Stop the specified bundle(s).
	 *
	 *  @param bundles bundle(s) to be stopped.
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_STOP_COMMAND_DESCRIPTION)
	public void stop(@Descriptor(ConsoleMsg.CONSOLE_HELP_STOP_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		if (bundles == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		if (bundles.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		for(Bundle bundle : bundles) {
				bundle.stop();
		}
	}

	/**
	 *  Handle the install command's abbreviation.  Invoke install()
	 *
	 *	@param shouldStart if the bundle should be start after installation
	 *  @param url location of the bundle to be installed
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_INSTALL_COMMAND_DESCRIPTION)
	public void i(
			@Descriptor(ConsoleMsg.CONSOLE_HELP_INSTALL_START_OPTION_DESCRIPTION)
			@Parameter(absentValue = "false", presentValue = "true", names = { "-start" })
			boolean shouldStart,
			@Descriptor(ConsoleMsg.CONSOLE_HELP_INSTALL_START_ARGUMENT_DESCRIPTION) String url) throws Exception {
		install(shouldStart, url);
	}

	/**
	 *  Handle the install command.  Install and optionally start bundle from the given URL
	 *
	 *  @param shouldStart if the bundle should be start after installation
	 *  @param url location of the bundle to be installed
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_INSTALL_COMMAND_DESCRIPTION)
	public Bundle install(
			@Descriptor(ConsoleMsg.CONSOLE_HELP_INSTALL_START_OPTION_DESCRIPTION)
			@Parameter(absentValue = "false", presentValue = "true", names = { "-start" })
			boolean shouldStart,
			@Descriptor(ConsoleMsg.CONSOLE_HELP_INSTALL_START_ARGUMENT_DESCRIPTION) String url) throws Exception {
		if (url == null) {
			System.out.println(ConsoleMsg.CONSOLE_NOTHING_TO_INSTALL_ERROR);
			return null;
		} else {
			Bundle bundle = context.installBundle(url);
			System.out.print(ConsoleMsg.CONSOLE_BUNDLE_ID_MESSAGE);
			System.out.println(bundle.getBundleId());
			if (shouldStart == true) {
				bundle.start();
			}
			return bundle;
		}
	}

	/**
	 *  Handle the update command's abbreviation.  Invoke update()
	 *
	 *  @param bundles bundle(s) to be updated
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_COMMAND_DESCRIPTION)
	public void up(@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		update(bundles);
	}
	
	/**
	 *  Handle the update command's abbreviation.  Invoke update()
	 *
	 *  @param bundle bundle to be updated
	 *  @param source location to get the new bundle's content
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_SOURCE_COMMAND_DESCRIPTION)
	public void up(
			@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_SOURCE_COMMAND_BUNDLE_ARGUMENT_DESCRIPTION)
			Bundle bundle, 
			@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_SOURCE_COMMAND_URL_ARGUMENT_DESCRIPTION)
			URL source) throws Exception {
		update(bundle, source);
	}
	
	/**
	 *  Handle the update command.  Update the specified bundle(s).
	 *
	 *  @param bundles bundle(s) to be updated
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_COMMAND_DESCRIPTION)
	public void update(@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		if (bundles == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		if(bundles.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		for(Bundle bundle : bundles) {
			bundle.update();
		}
	}

	/**
	 *  Handle the update command.  Update the specified bundle with the specified content.
	 *
	 *  @param bundle bundle to be updated
	 *  @param source location to get the new bundle's content
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_SOURCE_COMMAND_DESCRIPTION)
	public void update(
			@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_SOURCE_COMMAND_BUNDLE_ARGUMENT_DESCRIPTION)
			Bundle bundle, 
			@Descriptor(ConsoleMsg.CONSOLE_HELP_UPDATE_SOURCE_COMMAND_URL_ARGUMENT_DESCRIPTION)
			URL source) throws Exception {
		bundle.update(source.openStream());
	}

	/**
	 *  Handle the uninstall command's abbreviation.  Invoke uninstall()
	 *
	 *  @param bundles bundle(s) to uninstall
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_UNINSTALL_COMMAND_DESCRIPTION)
	public void un(@Descriptor(ConsoleMsg.CONSOLE_HELP_UNINSTALL_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		uninstall(bundles);
	}

	/**
	 *  Handle the uninstall command.  Uninstall the specified bundle(s).
	 *
	 *  @param bundles bundle(s) to uninstall
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_UNINSTALL_COMMAND_DESCRIPTION)
	public void uninstall(@Descriptor(ConsoleMsg.CONSOLE_HELP_UNINSTALL_COMMAND_ARGUMENT_DESCRIPTION) Bundle[] bundles) throws Exception {
		if(bundles == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		if(bundles.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		for (Bundle bundle : bundles) {
				bundle.uninstall();
		}
	}

	private int getStatesFromConstants(String states) throws IllegalArgumentException{
		int stateFilter = -1;
		if(!states.equals("")) {
			StringTokenizer tokens = new StringTokenizer(states, ","); //$NON-NLS-1
			while (tokens.hasMoreElements()) {
				String desiredState = (String) tokens.nextElement();
				Field match = null;
				try {
					match = Bundle.class.getField(desiredState.toUpperCase());
					if (stateFilter == -1)
						stateFilter = 0;
					stateFilter |= match.getInt(match);
				} catch (NoSuchFieldException e) {
					System.out.println(ConsoleMsg.CONSOLE_INVALID_INPUT + ": " + desiredState); //$NON-NLS-1$
					throw new IllegalArgumentException();
				} catch (IllegalAccessException e) {
					System.out.println(ConsoleMsg.CONSOLE_INVALID_INPUT + ": " + desiredState); //$NON-NLS-1$
					throw new IllegalArgumentException();
				}
			}
		}
		return stateFilter;
	}
	
	/**
	 *  Handle the status command's abbreviation.  Invoke status()
	 *
	 *  @param arguments 
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_STATUS_COMMAND_DESCRIPTION)
	public void s(@Descriptor(ConsoleMsg.CONSOLE_HELP_STATUS_ARGUMENT_DESCRIPTION) String... arguments) throws Exception {
		status(arguments);
	}

	/**
	 *  Handle the status command.  Display installed bundles and registered services.
	 *
	 *  @param arguments
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_STATUS_COMMAND_DESCRIPTION)
	public void status(@Descriptor(ConsoleMsg.CONSOLE_HELP_STATUS_ARGUMENT_DESCRIPTION) String... arguments) throws Exception {
		if (context.getBundle(0).getState() == Bundle.ACTIVE) {
			System.out.println(ConsoleMsg.CONSOLE_FRAMEWORK_IS_LAUNCHED_MESSAGE);
		} else {
			System.out.println(ConsoleMsg.CONSOLE_FRAMEWORK_IS_SHUTDOWN_MESSAGE);
		}
		System.out.println();
		
		String states = "";
		String[] bsnSegments = null;
		
		if(arguments != null && arguments.length > 0) {
			if(arguments[0].equals("-s")) {
				if (arguments.length > 1) {
					states = arguments[1];
					if(arguments.length > 2) {
						bsnSegments = new String[arguments.length - 2];
						System.arraycopy(arguments, 2, bsnSegments, 0, bsnSegments.length);
					}
				}
			} else {
				bsnSegments = arguments;
			}
		}

		int stateFilter;
		
		try {
			stateFilter = getStatesFromConstants(states);
		} catch (IllegalArgumentException e) {
			return;
		}
		
		Bundle[] bundles = context.getBundles();
		int size = bundles.length;

		if (size == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_INSTALLED_BUNDLES_ERROR);
			return;
		}
		
		System.out.print(ConsoleMsg.CONSOLE_ID);
		System.out.print(tab);
		System.out.println(ConsoleMsg.CONSOLE_BUNDLE_LOCATION_MESSAGE);
		System.out.println(ConsoleMsg.CONSOLE_STATE_BUNDLE_FILE_NAME_HEADER);
		for (int i = 0; i < size; i++) {
			Bundle bundle = bundles[i];
			if (!match(bundle, bsnSegments, stateFilter))
				continue;
			System.out.print(bundle.getBundleId());
			System.out.print(tab);
			System.out.println(bundle.getLocation());
			System.out.print("  "); //$NON-NLS-1$
			System.out.print(getStateName(bundle));
			System.out.println(bundle.toString());
		}

		ServiceReference<?>[] services = context.getServiceReferences((String) null, (String) null);
		if (services != null) {
			System.out.println(ConsoleMsg.CONSOLE_REGISTERED_SERVICES_MESSAGE);
			for(ServiceReference<?> service : services) {
				System.out.println(service);
			}
		}
	}

	/**
	 *  Handle the services command's abbreviation.  Invoke services()
	 *
	 *  @param filters filters for services
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SERVICES_COMMAND_DESCRIPTION)
	public void se(@Descriptor(ConsoleMsg.CONSOLE_HELP_FILTER_ARGUMENT_DESCRIPTION)String... filters) throws Exception {
		services(filters);
	}

	/**
	 *  Handle the services command.  Display registered service details.
	 *
	 *  @param filters filters for services
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SERVICES_COMMAND_DESCRIPTION)
	public void services(@Descriptor(ConsoleMsg.CONSOLE_HELP_FILTER_ARGUMENT_DESCRIPTION)String... filters) throws Exception {
		String filter = null;
		if (filters != null && filters.length > 0) {
			StringBuffer buf = new StringBuffer();
			for (String singleFilter : filters) {
				buf.append(' ');
				buf.append(singleFilter);
			}
			filter = buf.toString();
		}

		InvalidSyntaxException originalException = null;
		ServiceReference<?>[] services = null;

		try {
			services = context.getServiceReferences((String) null, filter);
		} catch (InvalidSyntaxException e) {
			originalException = e;
		}

		if (filter != null) {
			filter = filter.trim();
		}
		// If the filter is invalid and does not start with a bracket, probably the argument was the name of an interface.
		// Try to construct an object class filter with this argument, and if still invalid - throw the original InvalidSyntaxException
		if (originalException != null && !filter.startsWith("(") && !filter.contains(" ")) { //$NON-NLS-1$ //$NON-NLS-2$
			try {
				filter = "(" + Constants.OBJECTCLASS + "=" + filter + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				services = context.getServiceReferences((String) null, filter);
			} catch (InvalidSyntaxException e) {
				throw originalException;
			}
		} else if (originalException != null) {
			throw originalException;
		}

		if (services != null) {
			int size = services.length;
			if (size > 0) {
				for (int j = 0; j < size; j++) {
					ServiceReference<?> service = services[j];
					System.out.println(service);
					System.out.print("  "); //$NON-NLS-1$
					System.out.print(ConsoleMsg.CONSOLE_REGISTERED_BY_BUNDLE_MESSAGE);
					System.out.print(" "); //$NON-NLS-1$
					System.out.println(service.getBundle());
					Bundle[] users = service.getUsingBundles();
					if (users != null) {
						System.out.print("  "); //$NON-NLS-1$
						System.out.println(ConsoleMsg.CONSOLE_BUNDLES_USING_SERVICE_MESSAGE);
						for (int k = 0; k < users.length; k++) {
							System.out.print("    "); //$NON-NLS-1$
							System.out.println(users[k]);
						}
					} else {
						System.out.print("  "); //$NON-NLS-1$
						System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLES_USING_SERVICE_MESSAGE);
					}
				}
				return;
			}
		}
		System.out.println(ConsoleMsg.CONSOLE_NO_REGISTERED_SERVICES_MESSAGE);
	}

	/**
	 *  Handle the packages command's abbreviation.  Invoke packages()
	 *
	 *  @param bundle bundle for which to display package details
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_COMMAND_DESCRIPTION)
	public void p(@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_BUNDLE_ARGUMENT_DESCRIPTION)Bundle... bundle) throws Exception {
		packages(bundle);
	}
	
	/**
	 *  Handle the packages command's abbreviation.  Invoke packages()
	 *
	 *  @param packageName package for which to display details
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_COMMAND_DESCRIPTION)
	public void p(@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_PACKAGE_ARGUMENT_DESCRIPTION)String packageName) throws Exception {
		packages(packageName);
	}
	
	/**
	 *  Handle the packages command.  Display imported/exported packages details.
	 *
	 *  @param bundle bundle for which to display package details
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_COMMAND_DESCRIPTION)
	public void packages(@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_BUNDLE_ARGUMENT_DESCRIPTION)Bundle... bundle) throws Exception {
		if(activator.getPackageAdmin() != null) {
			ExportedPackage[] exportedPackages;
			if(bundle != null && bundle.length > 0) {
				exportedPackages = activator.getPackageAdmin().getExportedPackages(bundle[0]);
			} else {
				exportedPackages = activator.getPackageAdmin().getExportedPackages((Bundle) null);
			}
			getPackages(exportedPackages);
		} else {
			System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_NO_PACKAGE_ADMIN_MESSAGE);
		}
	}
	
	/**
	 *  Handle the packages command.  Display imported/exported packages details.
	 *
	 *  @param packageName package for which to display details
	 **/
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_COMMAND_DESCRIPTION)
	public void packages(@Descriptor(ConsoleMsg.CONSOLE_HELP_PACKAGES_PACKAGE_ARGUMENT_DESCRIPTION)String packageName) throws Exception {
		if(activator.getPackageAdmin() != null) {
			ExportedPackage[] exportedPackages = activator.getPackageAdmin().getExportedPackages(packageName);
			getPackages(exportedPackages);
		} else {
			System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_NO_PACKAGE_ADMIN_MESSAGE);
		}
	}
	
	@SuppressWarnings("deprecation")
	private void getPackages(ExportedPackage[] packages) throws Exception {
		if (packages == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_MESSAGE);
			return;
		}
		for (int i = 0; i < packages.length; i++) {
			org.osgi.service.packageadmin.ExportedPackage pkg = packages[i];
			System.out.print(pkg);

			boolean removalPending = pkg.isRemovalPending();
			if (removalPending) {
				System.out.print("("); //$NON-NLS-1$
				System.out.print(ConsoleMsg.CONSOLE_REMOVAL_PENDING_MESSAGE);
				System.out.println(")"); //$NON-NLS-1$
			}

			org.osgi.framework.Bundle exporter = pkg.getExportingBundle();
			if (exporter != null) {
				System.out.print("<"); //$NON-NLS-1$
				System.out.print(exporter);
				System.out.println(">"); //$NON-NLS-1$

				org.osgi.framework.Bundle[] importers = pkg.getImportingBundles();
				for (int j = 0; j < importers.length; j++) {
					System.out.print("  "); //$NON-NLS-1$
					System.out.print(importers[j]);
					System.out.print(" "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_IMPORTS_MESSAGE);
				}
			} else {
				System.out.print("<"); //$NON-NLS-1$
				System.out.print(ConsoleMsg.CONSOLE_STALE_MESSAGE);
				System.out.println(">"); //$NON-NLS-1$
			}
		}
	}

	/**
	 *  Handle the bundles command.  Display details for all installed bundles.
	 *
	 *  @param arguments
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_BUNDLES_COMMAND_DESCRIPTION)
	public void bundles(@Descriptor(ConsoleMsg.CONSOLE_HELP_STATUS_ARGUMENT_DESCRIPTION) String... arguments) throws Exception {
		String states = "";
		String[] bsnSegments = null;
		
		if(arguments != null && arguments.length > 0) {
			if(arguments[0].equals("-s")) {
				if (arguments.length > 1) {
					states = arguments[1];
					if(arguments.length > 2) {
						bsnSegments = new String[arguments.length - 2];
						System.arraycopy(arguments, 2, bsnSegments, 0, bsnSegments.length);
					}
				}
			} else {
				bsnSegments = arguments;
			}
		}
		int stateFilter;
		try {
			stateFilter = getStatesFromConstants(states);
		} catch (IllegalArgumentException e) {
			return;
		}

		Bundle[] bundles = context.getBundles();
		int size = bundles.length;

		if (size == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_INSTALLED_BUNDLES_ERROR);
			return;
		}

		for (int i = 0; i < size; i++) {
			Bundle bundle = bundles[i];
			if (!match(bundle, bsnSegments, stateFilter))
				continue;
			long id = bundle.getBundleId();
			System.out.println(bundle);
			System.out.print("  "); //$NON-NLS-1$
			System.out.print(NLS.bind(ConsoleMsg.CONSOLE_ID_MESSAGE, String.valueOf(id)));
			System.out.print(", "); //$NON-NLS-1$
			System.out.print(NLS.bind(ConsoleMsg.CONSOLE_STATUS_MESSAGE, getStateName(bundle)));
			if (id != 0) {
				File dataRoot = bundle.getDataFile(""); //$NON-NLS-1$
				String root = (dataRoot == null) ? null : dataRoot.getAbsolutePath();
				System.out.print(NLS.bind(ConsoleMsg.CONSOLE_DATA_ROOT_MESSAGE, root));
			} else {
				System.out.println();
			}

			ServiceReference<?>[] services = bundle.getRegisteredServices();
			if (services != null) {
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(ConsoleMsg.CONSOLE_REGISTERED_SERVICES_MESSAGE);
				for (int j = 0; j < services.length; j++) {
					System.out.print("    "); //$NON-NLS-1$
					System.out.println(services[j]);
				}
			} else {
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(ConsoleMsg.CONSOLE_NO_REGISTERED_SERVICES_MESSAGE);
			}

			services = bundle.getServicesInUse();
			if (services != null) {
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(ConsoleMsg.CONSOLE_SERVICES_IN_USE_MESSAGE);
				for (int j = 0; j < services.length; j++) {
					System.out.print("    "); //$NON-NLS-1$
					System.out.println(services[j]);
				}
			} else {
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(ConsoleMsg.CONSOLE_NO_SERVICES_IN_USE_MESSAGE);
			}
		}
	}

	/**
	 *  Handle the bundle command's abbreviation.  Invoke bundle()
	 *
	 *  @param bundles bundle(s) to display details for
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_BUNDLE_COMMAND_DESCRIPTION)
	public void b(@Descriptor(ConsoleMsg.CONSOLE_HELP_IDLOCATION_ARGUMENT_DESCRIPTION)Bundle[] bundles) throws Exception {
		bundle(bundles);
	}

	/**
	 *  Handle the bundle command.  Display details for the specified bundle(s).
	 *
	 *  @param bundles bundle(s) to display details for
	 */
	@SuppressWarnings({ "deprecation" })
	@Descriptor(ConsoleMsg.CONSOLE_HELP_BUNDLE_COMMAND_DESCRIPTION)
	public void bundle(@Descriptor(ConsoleMsg.CONSOLE_HELP_IDLOCATION_ARGUMENT_DESCRIPTION)Bundle[] bundles) throws Exception {
		if (bundles.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		for (Bundle bundle : bundles) {
				long id = bundle.getBundleId();
				System.out.println(bundle);
				System.out.print("  "); //$NON-NLS-1$
				System.out.print(NLS.bind(ConsoleMsg.CONSOLE_ID_MESSAGE, String.valueOf(id)));
				System.out.print(", "); //$NON-NLS-1$
				System.out.print(NLS.bind(ConsoleMsg.CONSOLE_STATUS_MESSAGE, getStateName(bundle)));
				if (id != 0) {
					File dataRoot = bundle.getDataFile(""); //$NON-NLS-1$
					String root = (dataRoot == null) ? null : dataRoot.getAbsolutePath();
					System.out.print(NLS.bind(ConsoleMsg.CONSOLE_DATA_ROOT_MESSAGE, root));
					System.out.println();
				} else {
					System.out.println();
				}

				ServiceReference<?>[] services = bundle.getRegisteredServices();
				if (services != null) {
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_REGISTERED_SERVICES_MESSAGE);
					for (int j = 0; j < services.length; j++) {
						System.out.print("    "); //$NON-NLS-1$
						System.out.println(services[j]);
					}
				} else {
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_NO_REGISTERED_SERVICES_MESSAGE);
				}

				services = bundle.getServicesInUse();
				if (services != null) {
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_SERVICES_IN_USE_MESSAGE);
					for (int j = 0; j < services.length; j++) {
						System.out.print("    "); //$NON-NLS-1$
						System.out.println(services[j]);
					}
				} else {
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_NO_SERVICES_IN_USE_MESSAGE);
				}

				PackageAdmin packageAdmin = activator.getPackageAdmin();
				if (packageAdmin == null) {
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_NO_PACKAGE_ADMIN_MESSAGE);
					continue;
				}
				
				PlatformAdmin platAdmin = activator.getPlatformAdmin();
				
				if (platAdmin != null) {
					BundleDescription desc = platAdmin.getState(false).getBundle(bundle.getBundleId());
					if (desc != null) {
						boolean title = true;
						
							ExportPackageDescription[] exports = desc.getExportPackages();
							if (exports == null || exports.length == 0) {
								System.out.print("  "); //$NON-NLS-1$
								System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_MESSAGE);
							} else {
								title = true;

								for (int i = 0; i < exports.length; i++) {
									if (title) {
										System.out.print("  "); //$NON-NLS-1$
										System.out.println(ConsoleMsg.CONSOLE_EXPORTED_PACKAGES_MESSAGE);
										title = false;
									}
									System.out.print("    "); //$NON-NLS-1$
									System.out.print(exports[i].getName());
									System.out.print("; version=\""); //$NON-NLS-1$
									System.out.print(exports[i].getVersion());
									System.out.print("\""); //$NON-NLS-1$
									if (desc.isRemovalPending()) {
										System.out.println(ConsoleMsg.CONSOLE_EXPORTED_REMOVAL_PENDING_MESSAGE);
									} else {
										System.out.println(ConsoleMsg.CONSOLE_EXPORTED_MESSAGE);
									}
								}

								if (title) {
									System.out.print("  "); //$NON-NLS-1$
									System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_MESSAGE);
								}
							}
							title = true;
							if (desc != null) {
								List<ImportPackageSpecification> fragmentsImportPackages = new ArrayList<ImportPackageSpecification>();

								// Get bundle' fragments imports
								BundleDescription[] fragments = desc.getFragments();
								for (int i = 0; i < fragments.length; i++) {
									ImportPackageSpecification[] fragmentImports = fragments[i].getImportPackages();
									for (int j = 0; j < fragmentImports.length; j++) {
										fragmentsImportPackages.add(fragmentImports[j]);
									}
								}

								// Get all bundle imports
								ImportPackageSpecification[] importPackages;
								if (fragmentsImportPackages.size() > 0) {
									ImportPackageSpecification[] directImportPackages = desc.getImportPackages();
									importPackages = new ImportPackageSpecification[directImportPackages.length + fragmentsImportPackages.size()];

									for (int i = 0; i < directImportPackages.length; i++) {
										importPackages[i] = directImportPackages[i];
									}

									int offset = directImportPackages.length;
									for (int i = 0; i < fragmentsImportPackages.size(); i++) {
										importPackages[offset + i] = fragmentsImportPackages.get(i);
									}
								} else {
									importPackages = desc.getImportPackages();
								}

								// Get all resolved imports
								ExportPackageDescription[] imports = null;
								imports = desc.getContainingState().getStateHelper().getVisiblePackages(desc, StateHelper.VISIBLE_INCLUDE_EE_PACKAGES | StateHelper.VISIBLE_INCLUDE_ALL_HOST_WIRES);

								// Get the unresolved optional and dynamic imports
								List<ImportPackageSpecification> unresolvedImports = new ArrayList<ImportPackageSpecification>();

								for (int i = 0; i < importPackages.length; i++) {
									if (importPackages[i].getDirective(Constants.RESOLUTION_DIRECTIVE).equals(ImportPackageSpecification.RESOLUTION_OPTIONAL)) {
										if (importPackages[i].getSupplier() == null) {
											unresolvedImports.add(importPackages[i]);
										}
									} else if (importPackages[i].getDirective(org.osgi.framework.Constants.RESOLUTION_DIRECTIVE).equals(ImportPackageSpecification.RESOLUTION_DYNAMIC)) {
										boolean isResolvable = false;

										// Check if the dynamic import can be resolved by any of the wired imports, 
										// and if not - add it to the list of unresolved imports
										for (int j = 0; j < imports.length; j++) {
											if (importPackages[i].isSatisfiedBy(imports[j])) {
												isResolvable = true;
											}
										}

										if (isResolvable == false) {
											unresolvedImports.add(importPackages[i]);
										}
									}
								}

								title = printImportedPackages(imports, title);

								if (desc.isResolved() && (unresolvedImports.isEmpty() == false)) {
									printUnwiredDynamicImports(unresolvedImports);
									title = false;
								}
							}

							if (title) {
								System.out.print("  "); //$NON-NLS-1$
								System.out.println(ConsoleMsg.CONSOLE_NO_IMPORTED_PACKAGES_MESSAGE);
							}

							if (packageAdmin != null) {
								System.out.print("  "); //$NON-NLS-1$
								if ((packageAdmin.getBundleType(bundle) & PackageAdmin.BUNDLE_TYPE_FRAGMENT) > 0) {
									org.osgi.framework.Bundle[] hosts = packageAdmin.getHosts(bundle);
									if (hosts != null) {
										System.out.println(ConsoleMsg.CONSOLE_HOST_MESSAGE);
										for (int i = 0; i < hosts.length; i++) {
											System.out.print("    "); //$NON-NLS-1$
											System.out.println(hosts[i]);
										}
									} else {
										System.out.println(ConsoleMsg.CONSOLE_NO_HOST_MESSAGE);
									}
								} else {
									org.osgi.framework.Bundle[] fragments = packageAdmin.getFragments(bundle);
									if (fragments != null) {
										System.out.println(ConsoleMsg.CONSOLE_FRAGMENT_MESSAGE);
										for (int i = 0; i < fragments.length; i++) {
											System.out.print("    "); //$NON-NLS-1$
											System.out.println(fragments[i]);
										}
									} else {
										System.out.println(ConsoleMsg.CONSOLE_NO_FRAGMENT_MESSAGE);
									}
								}

								RequiredBundle[] requiredBundles = packageAdmin.getRequiredBundles(null);
								RequiredBundle requiredBundle = null;
								if (requiredBundles != null) {
									for (RequiredBundle rb : requiredBundles) {
										if (rb.getBundle() == bundle) {
											requiredBundle = rb;
											break;
										}
									}
								}

								if (requiredBundle == null) {
									System.out.print("  "); //$NON-NLS-1$
									System.out.println(ConsoleMsg.CONSOLE_NO_NAMED_CLASS_SPACES_MESSAGE);
								} else {
									System.out.print("  "); //$NON-NLS-1$
									System.out.println(ConsoleMsg.CONSOLE_NAMED_CLASS_SPACE_MESSAGE);
									System.out.print("    "); //$NON-NLS-1$
									System.out.print(requiredBundle);
									if (requiredBundle.isRemovalPending()) {
										System.out.println(ConsoleMsg.CONSOLE_REMOVAL_PENDING_MESSAGE);
									} else {
										System.out.println(ConsoleMsg.CONSOLE_PROVIDED_MESSAGE);
									}
								}
								title = true;
								if (requiredBundles != null) {
									for (RequiredBundle rb : requiredBundles) {
										if (rb == requiredBundle)
											continue;

										org.osgi.framework.Bundle[] depBundles = rb.getRequiringBundles();
										if (depBundles == null)
											continue;

										for (int j = 0; j < depBundles.length; j++) {
											if (depBundles[j] == bundle) {
												if (title) {
													System.out.print("  "); //$NON-NLS-1$
													System.out
															.println(ConsoleMsg.CONSOLE_REQUIRED_BUNDLES_MESSAGE);
													title = false;
												}
												System.out.print("    "); //$NON-NLS-1$
												System.out.print(rb);

												org.osgi.framework.Bundle provider = rb.getBundle();
												System.out.print("<"); //$NON-NLS-1$
												System.out.print(provider);
												System.out.println(">"); //$NON-NLS-1$
											}
										}
									}
								}
								if (title) {
									System.out.print("  "); //$NON-NLS-1$
									System.out.println(ConsoleMsg.CONSOLE_NO_REQUIRED_BUNDLES_MESSAGE);
								}

							}
						} 
					System.out.println();
					System.out.println();
				} else {
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_NO_PLATFORM_ADMIN_MESSAGE);
				}		
		}
	}

	private boolean printImportedPackages(ExportPackageDescription[] importedPkgs, boolean title) {
		for (int i = 0; i < importedPkgs.length; i++) {
			if (title) {
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(ConsoleMsg.CONSOLE_IMPORTED_PACKAGES_MESSAGE);
				title = false;
			}
			System.out.print("    "); //$NON-NLS-1$
			System.out.print(importedPkgs[i].getName());
			System.out.print("; version=\""); //$NON-NLS-1$
			System.out.print(importedPkgs[i].getVersion());
			System.out.print("\""); //$NON-NLS-1$
			Bundle exporter = context.getBundle(importedPkgs[i].getSupplier().getBundleId());
			if (exporter != null) {
				System.out.print("<"); //$NON-NLS-1$
				System.out.print(exporter);
				System.out.println(">"); //$NON-NLS-1$
			} else {
				System.out.print("<"); //$NON-NLS-1$
				System.out.print(ConsoleMsg.CONSOLE_STALE_MESSAGE);
				System.out.println(">"); //$NON-NLS-1$
			}
		}
		return title;
	}

	private void printUnwiredDynamicImports(List<ImportPackageSpecification> dynamicImports) {
		for (int i = 0; i < dynamicImports.size(); i++) {
			ImportPackageSpecification importPackage = dynamicImports.get(i);
			System.out.print("    "); //$NON-NLS-1$
			System.out.print(importPackage.getName());
			System.out.print("; version=\""); //$NON-NLS-1$
			System.out.print(importPackage.getVersionRange());
			System.out.print("\""); //$NON-NLS-1$
			System.out.print("<"); //$NON-NLS-1$
			System.out.print("unwired"); //$NON-NLS-1$
			System.out.print(">"); //$NON-NLS-1$
			System.out.print("<"); //$NON-NLS-1$
			System.out.print(importPackage.getDirective(org.osgi.framework.Constants.RESOLUTION_DIRECTIVE));
			System.out.println(">"); //$NON-NLS-1$
		}
	}

	/**
	 *  Handle the gc command.  Perform a garbage collection.
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_GC_COMMAND_DESCRIPTION)
	public void gc() throws Exception {
		long before = Runtime.getRuntime().freeMemory();

		/* Let the finilizer finish its work and remove objects from its queue */
		System.gc(); /* asyncronous garbage collector might already run */
		System.gc(); /* to make sure it does a full gc call it twice */
		System.runFinalization();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// do nothing
		}

		long after = Runtime.getRuntime().freeMemory();
		System.out.print(ConsoleMsg.CONSOLE_TOTAL_MEMORY_MESSAGE);
		System.out.println(String.valueOf(Runtime.getRuntime().totalMemory()));
		System.out.print(ConsoleMsg.CONSOLE_FREE_MEMORY_BEFORE_GARBAGE_COLLECTION_MESSAGE);
		System.out.println(String.valueOf(before));
		System.out.print(ConsoleMsg.CONSOLE_FREE_MEMORY_AFTER_GARBAGE_COLLECTION_MESSAGE);
		System.out.println(String.valueOf(after));
		System.out.print(ConsoleMsg.CONSOLE_MEMORY_GAINED_WITH_GARBAGE_COLLECTION_MESSAGE);
		System.out.println(String.valueOf(after - before));
	}

	/**
	 *  Handle the init command.  Uninstall all bundles.
	 *
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_INIT_COMMAND_DESCRIPTION)
	public void init() throws Exception {
		if (context.getBundle(0).getState() == Bundle.ACTIVE) {
			System.out.print(newline);
			System.out.println(ConsoleMsg.CONSOLE_FRAMEWORK_LAUNCHED_PLEASE_SHUTDOWN_MESSAGE);
			return;
		}

		Bundle[] bundles = context.getBundles();

		int size = bundles.length;

		if (size > 0) {
			for (int i = 0; i < size; i++) {
				Bundle bundle = bundles[i];

				if (bundle.getBundleId() != 0) {
					try {
						bundle.uninstall();
					} catch (BundleException e) {
						e.printStackTrace();
					}
				}
			}
		} else {
			System.out.println(ConsoleMsg.CONSOLE_NO_INSTALLED_BUNDLES_ERROR);
		}
		PermissionAdmin securityAdmin = activator.getPermissionAdmin();
		ConditionalPermissionAdmin condPermAdmin = activator.getConditionalPermissionAdmin();
		if (securityAdmin != null) {
			// clear the permissions from permission admin
			securityAdmin.setDefaultPermissions(null);
			String[] permLocations = securityAdmin.getLocations();
			if (permLocations != null)
				for (int i = 0; i < permLocations.length; i++)
					securityAdmin.setPermissions(permLocations[i], null);
			ConditionalPermissionUpdate update = condPermAdmin.newConditionalPermissionUpdate();
			update.getConditionalPermissionInfos().clear();
			update.commit();
		}
		// clear the permissions from conditional permission admin
		if (securityAdmin != null)
			for (Enumeration<ConditionalPermissionInfo> infos = condPermAdmin.getConditionalPermissionInfos(); infos.hasMoreElements();)
				infos.nextElement().delete();
	}

	/**
	 *  Handle the close command.  Shutdown and exit.
	
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_CLOSE_COMMAND_DESCRIPTION)
	public void close() throws Exception {
		context.getBundle(0).stop();
		System.exit(0);
	}

	/**
	 *  Handle the refresh command's abbreviation.  Invoke refresh()
	 *
	 *  @param bundles bundle(s) to be refreshed
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_REFRESH_COMMAND_DESCRIPTION)
	public void r(@Descriptor(ConsoleMsg.CONSOLE_HELP_REFRESH_COMMAND_ARGUMENT_DESCRIPTION) Bundle... bundles) throws Exception {
		refresh(bundles);
	}

	/**
	 *  Handle the refresh command.  Refresh the packages of the specified bundles.
	 *
	 *  @param bundles bundle(s) to be refreshed
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_REFRESH_COMMAND_DESCRIPTION)
	public void refresh(@Descriptor(ConsoleMsg.CONSOLE_HELP_REFRESH_COMMAND_ARGUMENT_DESCRIPTION) Bundle... bundles) throws Exception {
		PackageAdmin packageAdmin = activator.getPackageAdmin();
		if (packageAdmin != null) {
			if(bundles != null && bundles.length > 0) {
				packageAdmin.refreshPackages(bundles);
			} else {
				packageAdmin.refreshPackages(null);
			}
		} else {
			System.out.println(ConsoleMsg.CONSOLE_CAN_NOT_REFRESH_NO_PACKAGE_ADMIN_ERROR);
		}
	}

	/**
	 * Executes the given system command in a separate system process
	 * and waits for it to finish.
	 *
	 * @param command command to be executed
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_EXEC_COMMAND_DESCRIPTION)
	public void exec(@Descriptor(ConsoleMsg.CONSOLE_HELP_EXEC_COMMAND_ARGUMENT_DESCRIPTION) String command) throws Exception {
		if (command == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_COMMAND_SPECIFIED_ERROR);
			return;
		}

		Process p = Runtime.getRuntime().exec(command);

		System.out.println(NLS.bind(ConsoleMsg.CONSOLE_STARTED_IN_MESSAGE, command, String.valueOf(p)));
		int result = p.waitFor();
		System.out.println(NLS.bind(ConsoleMsg.CONSOLE_EXECUTED_RESULT_CODE_MESSAGE, command, String.valueOf(result)));
	}

	/**
	 * Executes the given system command in a separate system process.  It does
	 * not wait for a result.
	 *
	 * @param command command to be executed
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_FORK_COMMAND_DESCRIPTION)
	public void fork(@Descriptor(ConsoleMsg.CONSOLE_HELP_FORK_COMMAND_ARGUMENT_DESCRIPTION) String command) throws Exception {
		if (command == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_COMMAND_SPECIFIED_ERROR);
			return;
		}

		Process p = Runtime.getRuntime().exec(command);
		System.out.println(NLS.bind(ConsoleMsg.CONSOLE_STARTED_IN_MESSAGE, command, String.valueOf(p)));
	}

	/**
	 * Handle the headers command's abbreviation.  Invoke headers()
	 *
	 * @param bundles bundle(s) whose headers to display
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_HEADERS_COMMAND_DESCRIPTION)
	public List<Dictionary<String, String>> h(@Descriptor(ConsoleMsg.CONSOLE_HELP_HEADERS_COMMAND_ARGUMENT_DESCRIPTION) Bundle... bundles) throws Exception {
		return headers(bundles);
	}

	/**
	 * Handle the headers command.  Display headers for the specified bundle(s).
	 *
	 * @param bundles bundle(s) whose headers to display
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_HEADERS_COMMAND_DESCRIPTION)
	public List<Dictionary<String, String>> headers(@Descriptor(ConsoleMsg.CONSOLE_HELP_HEADERS_COMMAND_ARGUMENT_DESCRIPTION) Bundle... bundles) throws Exception {
		ArrayList<Dictionary<String, String>> headers = new ArrayList<Dictionary<String,String>>();
		
		if (bundles == null || bundles.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return headers;
		}
		
		
		for (Bundle bundle : bundles) {
			headers.add(bundle.getHeaders());
		}
		return headers;
	}
	
	/**
	 * Handles the props command's abbreviation.  Invokes props()
	 *
	 */
	@Descriptor(ConsoleMsg.CONSOLE_PROPS_COMMAND_DESCRIPTION)
	public Dictionary<?, ?> pr() throws Exception {
		 return props();
	}

	/**
	 * Handles the _props command.  Prints the system properties sorted.
	 *
	 */
	@Descriptor(ConsoleMsg.CONSOLE_PROPS_COMMAND_DESCRIPTION)
	public Dictionary<?, ?> props() throws Exception {
		System.out.println(ConsoleMsg.CONSOLE_SYSTEM_PROPERTIES_TITLE);
		return System.getProperties();
	}

	/**
	 * Handles the setprop command's abbreviation.  Invokes setprop()
	 *
	 * @param arguments key=value pairs for the new properties
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SETPROP_COMMAND_DESCRIPTION)
	public void setp(@Descriptor(ConsoleMsg.CONSOLE_HELP_SETPROP_COMMAND_ARGUMENTS_DESCRIPTION) String[] arguments) throws Exception {
		setprop(arguments);
	}

	/**
	 * Handles the setprop command.  Sets the CDS property in the given argument.
	 *
	 * @param arguments key=value pairs for the new properties
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SETPROP_COMMAND_DESCRIPTION)
	public void setprop(@Descriptor(ConsoleMsg.CONSOLE_HELP_SETPROP_COMMAND_ARGUMENTS_DESCRIPTION) String[] arguments) throws Exception {
		if (arguments == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_PARAMETERS_SPECIFIED_TITLE);
			props();
		} else {
			ServiceReference<EnvironmentInfo> envInfoRef = context.getServiceReference(EnvironmentInfo.class);
			if (envInfoRef != null) {
				// EnvironmentInfo is used because FrameworkProperties cannot be directly accessed outside of the system bundle
				EnvironmentInfo envInfo = context.getService(envInfoRef);
				if (envInfo != null) {
					System.out.println(ConsoleMsg.CONSOLE_SETTING_PROPERTIES_TITLE);
					for(String argument : arguments) {
						int index = argument.indexOf("=");
						if(index > -1) {
							String key = argument.substring(0, index);
							String value = argument.substring(index + 1, argument.length());
							envInfo.setProperty(key, value);
							System.out.println(tab + key + " = " + value); //$NON-NLS-1$
						}
					}
				} else {
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_CANNOT_ACCESS_SYSTEM_PROPERTIES);
				}
			}
		}
	}

	/**
	 * Prints the short version of the status.
	 * For the long version use "status".
	 *
	 * @param arguments
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SS_COMMAND_DESCRIPTION)
	public void ss(@Descriptor(ConsoleMsg.CONSOLE_HELP_STATUS_ARGUMENT_DESCRIPTION) String... arguments) throws Exception {
		if (context.getBundle(0).getState() == Bundle.ACTIVE) {
			System.out.println(ConsoleMsg.CONSOLE_FRAMEWORK_IS_LAUNCHED_MESSAGE);
		} else {
			System.out.println(ConsoleMsg.CONSOLE_FRAMEWORK_IS_SHUTDOWN_MESSAGE);
		}
		System.out.println();
		
		String states = "";
		String[] bsnSegments = null;
		
		if(arguments != null && arguments.length > 0) {
			if(arguments[0].equals("-s")) {
				if (arguments.length > 1) {
					states = arguments[1];
					if(arguments.length > 2) {
						bsnSegments = new String[arguments.length - 2];
						System.arraycopy(arguments, 2, bsnSegments, 0, bsnSegments.length);
					}
				}
			} else {
				bsnSegments = arguments;
			}
		}

		int stateFilter;
		
		try {
			stateFilter = getStatesFromConstants(states);
		} catch (IllegalArgumentException e) {
			return;
		}
		
		Bundle[] bundles = context.getBundles();
		int size = bundles.length;

		if (size == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_INSTALLED_BUNDLES_ERROR);
			return;
		} else {
			System.out.print(newline);
			System.out.print(ConsoleMsg.CONSOLE_ID);
			System.out.print(tab);
			System.out.println(ConsoleMsg.CONSOLE_STATE_BUNDLE_TITLE);
			for (Bundle b : bundles) {
				
				if (!match(b, bsnSegments, stateFilter))
					continue;
				String label = b.getSymbolicName();
				if (label == null || label.length() == 0)
					label = b.toString();
				else
					label = label + "_" + b.getVersion(); //$NON-NLS-1$
				System.out.println(b.getBundleId() + "\t" + getStateName(b) + label); //$NON-NLS-1$ 
				PackageAdmin packageAdmin = activator.getPackageAdmin();
				if ((packageAdmin.getBundleType(b) & PackageAdmin.BUNDLE_TYPE_FRAGMENT) != 0) {
					Bundle[] hosts = packageAdmin.getHosts(b);
					if (hosts != null)
						for (int j = 0; j < hosts.length; j++)
							System.out.println("\t            Master=" + hosts[j].getBundleId()); //$NON-NLS-1$
				} else {
					Bundle[] fragments = packageAdmin.getFragments(b);
					if (fragments != null) {
						System.out.print("\t            Fragments="); //$NON-NLS-1$
						for (int f = 0; f < fragments.length; f++) {
							Bundle fragment = fragments[f];
							System.out.print((f > 0 ? ", " : "") + fragment.getBundleId()); //$NON-NLS-1$ //$NON-NLS-2$
						}
						System.out.println();
					}
				}
			}
		}
	}

	private boolean match(Bundle toFilter, String[] searchedName, int searchedState) {
		if ((toFilter.getState() & searchedState) == 0) {
			return false;
		}
		if (searchedName != null && searchedName.length > 0 && toFilter.getSymbolicName() != null && toFilter.getSymbolicName().indexOf(searchedName[0]) == -1) {
			return false;
		}
		return true;
	}

	/**
	 * Handles the threads command abbreviation.  Invokes threads().
	 *
	 */
	@Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_DESCRIPTION)
	public void t() throws Exception {
		threads();
	}

	/**
	 * Prints the information about the currently running threads
	 * in the embedded system.
	 *
	 */
	@Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_DESCRIPTION)
	public void threads() throws Exception {

		ThreadGroup[] threadGroups = getThreadGroups();
		Util.sortByString(threadGroups);

		ThreadGroup tg = getTopThreadGroup();
		Thread[] threads = new Thread[tg.activeCount()];
		int count = tg.enumerate(threads, true);
		Util.sortByString(threads);

		StringBuffer sb = new StringBuffer(120);
		System.out.println();
		System.out.println(ConsoleMsg.CONSOLE_THREADGROUP_TITLE);
		for (int i = 0; i < threadGroups.length; i++) {
			tg = threadGroups[i];
			int all = tg.activeCount(); //tg.allThreadsCount();
			int local = tg.enumerate(new Thread[all], false); //tg.threadsCount();
			ThreadGroup p = tg.getParent();
			String parent = (p == null) ? "-none-" : p.getName(); //$NON-NLS-1$
			sb.setLength(0);
			sb.append(Util.toString(simpleClassName(tg), 18)).append(" ").append(Util.toString(tg.getName(), 21)).append(" ").append(Util.toString(parent, 16)).append(Util.toString(Integer.valueOf(tg.getMaxPriority()), 3)).append(Util.toString(Integer.valueOf(local), 4)).append("/").append(Util.toString(String.valueOf(all), 6)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			System.out.println(sb.toString());
		}
		System.out.print(newline);
		System.out.println(ConsoleMsg.CONSOLE_THREADTYPE_TITLE);
		for (int j = 0; j < count; j++) {
			Thread t = threads[j];
			if (t != null) {
				sb.setLength(0);
				sb.append(Util.toString(simpleClassName(t), 18)).append(" ").append(Util.toString(t.getName(), 21)).append(" ").append(Util.toString(t.getThreadGroup().getName(), 16)).append(Util.toString(Integer.valueOf(t.getPriority()), 3)); //$NON-NLS-1$ //$NON-NLS-2$
				if (t.isDaemon())
					sb.append(" [daemon]"); //$NON-NLS-1$
				System.out.println(sb.toString());
			}
		}
	}

	/**
	 * Handles the sl (startlevel) command. 
	 *
	 * @param bundle bundle to display startlevel for; if no bundle is specified, the framework startlevel is displayed
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SL_COMMAND_DESCRIPTION)
	public void sl(@Descriptor(ConsoleMsg.CONSOLE_HELP_SL_COMMAND_ARGUMENT_DESCRIPTION) Bundle... bundle) throws Exception {
		StartLevel startLevel = activator.getStartLevel();
		if (startLevel != null) {
			int value = 0;
			if (bundle == null || bundle.length == 0) { // must want framework startlevel
				value = startLevel.getStartLevel();
				System.out.println(NLS.bind(ConsoleMsg.STARTLEVEL_FRAMEWORK_ACTIVE_STARTLEVEL, String.valueOf(value)));
			} else { // must want bundle startlevel
				value = startLevel.getBundleStartLevel(bundle[0]);
				System.out.println(NLS.bind(ConsoleMsg.STARTLEVEL_BUNDLE_STARTLEVEL, Long.valueOf(bundle[0].getBundleId()), Integer.valueOf(value)));
			}
		}
	}

	/**
	 * Handles the setfwsl (set framework startlevel) command. 
	 *
	 * @param newSL new value for the framewrok start level
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SETFWSL_COMMAND_DESCRIPTION)
	public void setfwsl(@Descriptor(ConsoleMsg.CONSOLE_HELP_SETFWSL_COMMAND_ARGUMENT_DESCRIPTION) int newSL) throws Exception {
		StartLevel startLevel = activator.getStartLevel();
		if (startLevel != null) {
			try {
				startLevel.setStartLevel(newSL);
				System.out.println(NLS.bind(ConsoleMsg.STARTLEVEL_FRAMEWORK_ACTIVE_STARTLEVEL, String.valueOf(newSL)));
			} catch (IllegalArgumentException e) {
				System.out.println(e.getMessage());
			}
		}
	}

	/**
	 * Handles the setbsl (set bundle startlevel) command. 
	 *
	 * @param newSL new value for bundle start level
	 * @param bundles bundles whose start value will be changed
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SETBSL_COMMAND_DESCRIPTION)
	public void setbsl(
			@Descriptor(ConsoleMsg.CONSOLE_HELP_SETFWSL_COMMAND_ARGUMENT_DESCRIPTION)int newSL, 
			@Descriptor(ConsoleMsg.CONSOLE_HELP_SETBSL_COMMAND_ARGUMENT_DESCRIPTION) Bundle... bundles) throws Exception {
		StartLevel startLevel = activator.getStartLevel();
		if (startLevel != null) {
			if (bundles == null) {
				System.out.println(ConsoleMsg.STARTLEVEL_NO_STARTLEVEL_OR_BUNDLE_GIVEN);
				return;
			}
			for (Bundle bundle : bundles) {	
				try {
					startLevel.setBundleStartLevel(bundle, newSL);
					System.out.println(NLS.bind(ConsoleMsg.STARTLEVEL_BUNDLE_STARTLEVEL, Long.valueOf(bundle.getBundleId()), Integer.valueOf(newSL)));
				} catch (IllegalArgumentException e) {
					System.out.println(e.getMessage());
				}
			}
		}
	}

	/**
	 * Handles the setibsl (set initial bundle startlevel) command. 
	 *
	 * @param newInitialSL new value for initial start level
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_SETIBSL_COMMAND_DESCRIPTION)
	public void setibsl(@Descriptor(ConsoleMsg.CONSOLE_HELP_SETFWSL_COMMAND_ARGUMENT_DESCRIPTION) int newInitialSL) throws Exception {
		StartLevel startLevel = activator.getStartLevel();
		if (startLevel != null) {
			try {
				startLevel.setInitialBundleStartLevel(newInitialSL);
				System.out.println(NLS.bind(ConsoleMsg.STARTLEVEL_INITIAL_BUNDLE_STARTLEVEL, String.valueOf(newInitialSL)));
			} catch (IllegalArgumentException e) {
				System.out.println(e.getMessage());
			}
		}
	}

	/**
	 * Lists required bundles having the specified symbolic name or all if no bsn is specified
	 * 
	 * @param symbolicName
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_REQUIRED_BUNDLES_COMMAND_DESCRIPTION)
	public void requiredBundles(@Descriptor(ConsoleMsg.CONSOLE_HELP_REQUIRED_BUNDLES_COMMAND_ARGUMENT_DESCRIPTION) String... symbolicName) {
		classSpaces(symbolicName);
	}

	/**
	 * Lists required bundles having the specified symbolic name or all if no bsn is specified
	 * 
	 * @param symbolicName
	 */
	@SuppressWarnings("deprecation")
	@Descriptor(ConsoleMsg.CONSOLE_HELP_REQUIRED_BUNDLES_COMMAND_DESCRIPTION)
	public void classSpaces(@Descriptor(ConsoleMsg.CONSOLE_HELP_REQUIRED_BUNDLES_COMMAND_ARGUMENT_DESCRIPTION) String... symbolicName) {
		PackageAdmin packageAdmin = activator.getPackageAdmin();
		if (packageAdmin != null) {
			RequiredBundle[] symBundles = null;
			String name;
			if(symbolicName == null || symbolicName.length == 0) {
				name = null;
			} else {
				name = symbolicName[0];
			}
			symBundles = packageAdmin.getRequiredBundles(name);

			if (symBundles == null) {
				System.out.println(ConsoleMsg.CONSOLE_NO_NAMED_CLASS_SPACES_MESSAGE);
			} else {
				for (RequiredBundle symBundle : symBundles) {

					System.out.print(symBundle);

					boolean removalPending = symBundle.isRemovalPending();
					if (removalPending) {
						System.out.print("("); //$NON-NLS-1$
						System.out.print(ConsoleMsg.CONSOLE_REMOVAL_PENDING_MESSAGE);
						System.out.println(")"); //$NON-NLS-1$
					}

					Bundle provider = symBundle.getBundle();
					if (provider != null) {
						System.out.print("<"); //$NON-NLS-1$
						System.out.print(provider);
						System.out.println(">"); //$NON-NLS-1$

						Bundle[] requiring = symBundle.getRequiringBundles();
						if (requiring != null)
							for (int j = 0; j < requiring.length; j++) {
								System.out.print("  "); //$NON-NLS-1$
								System.out.print(requiring[j]);
								System.out.print(" "); //$NON-NLS-1$
								System.out.println(ConsoleMsg.CONSOLE_REQUIRES_MESSAGE);
							}
					} else {
						System.out.print("<"); //$NON-NLS-1$
						System.out.print(ConsoleMsg.CONSOLE_STALE_MESSAGE);
						System.out.println(">"); //$NON-NLS-1$
					}

				}
			}
		} else {
			System.out.println(ConsoleMsg.CONSOLE_NO_EXPORTED_PACKAGES_NO_PACKAGE_ADMIN_MESSAGE);
		}
	}

	/**
	 * Handles the profilelog command. 
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_PROFILELOG_COMMAND_DESCRIPTION)
	public void profilelog() throws Exception {
		Class<?> profileClass = BundleContext.class.getClassLoader().loadClass("org.eclipse.osgi.internal.profile.Profile");
		Method getProfileLog = profileClass.getMethod("getProfileLog", (Class<?>[]) null);
		System.out.println(getProfileLog.invoke(null, (Object[]) null));
	}

	/**
	 * Lists all packages visible from the specified bundle
	 * @param bundle bundle to list visible packages
	 */
	@Descriptor(ConsoleMsg.CONSOLE_HELP_VISIBLE_PACKAGES_COMMAND_DESCRIPTION)
	public void getPackages(@Descriptor(ConsoleMsg.CONSOLE_HELP_VISIBLE_PACKAGES_COMMAND_ARGUMENTS_DESCRIPTION) Bundle bundle) {
		PlatformAdmin platformAdmin = activator.getPlatformAdmin();
		if (platformAdmin == null)
			return;
			BundleDescription bundleDescription = platformAdmin.getState(false).getBundle(bundle.getBundleId());
			ExportPackageDescription[] exports = platformAdmin.getStateHelper().getVisiblePackages(bundleDescription, StateHelper.VISIBLE_INCLUDE_EE_PACKAGES | StateHelper.VISIBLE_INCLUDE_ALL_HOST_WIRES);
			for (int i = 0; i < exports.length; i++) {
				System.out.println(exports[i] + ": " + platformAdmin.getStateHelper().getAccessCode(bundleDescription, exports[i])); //$NON-NLS-1$
			}
	}

	/**
	 *  Given a string containing a startlevel value, validate it and convert it to an int
	 * 
	 *  @param intp A CommandInterpreter object used for printing out error messages
	 *  @param value A string containing a potential startlevel
	 *  @return The start level or an int <0 if it was invalid
	 */
	protected int getStartLevelFromToken(String value) {
		int retval = -1;
		try {
			retval = Integer.parseInt(value);
			if (Integer.parseInt(value) <= 0) {
				System.out.println(ConsoleMsg.STARTLEVEL_POSITIVE_INTEGER);
			}
		} catch (NumberFormatException nfe) {
			System.out.println(ConsoleMsg.STARTLEVEL_POSITIVE_INTEGER);
		}
		return retval;
	}

	/**
	 *  Given a bundle, return the string describing that bundle's state.
	 *
	 *  @param bundle A bundle to return the state of
	 *  @return A String describing the state
	 */
	protected String getStateName(Bundle bundle) {
		int state = bundle.getState();
		switch (state) {
			case Bundle.UNINSTALLED :
				return "UNINSTALLED "; //$NON-NLS-1$

			case Bundle.INSTALLED :
				if (isDisabled(bundle)) {
					return "<DISABLED>  "; //$NON-NLS-1$	
				}
				return "INSTALLED   "; //$NON-NLS-1$

			case Bundle.RESOLVED :
				return "RESOLVED    "; //$NON-NLS-1$

			case Bundle.STARTING :
				synchronized (lazyActivation) {
					if (lazyActivation.contains(bundle)) {
						return "<<LAZY>>    "; //$NON-NLS-1$
					}
					return "STARTING    "; //$NON-NLS-1$
				}

			case Bundle.STOPPING :
				return "STOPPING    "; //$NON-NLS-1$

			case Bundle.ACTIVE :
				return "ACTIVE      "; //$NON-NLS-1$

			default :
				return Integer.toHexString(state);
		}
	}

	private boolean isDisabled(Bundle bundle) {
		boolean disabled = false;
		ServiceReference<?> platformAdminRef = null;
		try {
			platformAdminRef = context.getServiceReference(PlatformAdmin.class.getName());
			if (platformAdminRef != null) {
				PlatformAdmin platAdmin = (PlatformAdmin) context.getService(platformAdminRef);
				if (platAdmin != null) {
					State state = platAdmin.getState(false);
					BundleDescription bundleDesc = state.getBundle(bundle.getBundleId());
					DisabledInfo[] disabledInfos = state.getDisabledInfos(bundleDesc);
					if ((disabledInfos != null) && (disabledInfos.length != 0)) {
						disabled = true;
					}
				}
			}
		} finally {
			if (platformAdminRef != null)
				context.ungetService(platformAdminRef);
		}
		return disabled;
	}

	/**
	 * Answers all thread groups in the system.
	 *
	 * @return	An array of all thread groups.
	 */
	protected ThreadGroup[] getThreadGroups() {
		ThreadGroup tg = getTopThreadGroup();
		ThreadGroup[] groups = new ThreadGroup[tg.activeGroupCount()];
		int count = tg.enumerate(groups, true);
		if (count == groups.length) {
			return groups;
		}
		// get rid of null entries
		ThreadGroup[] ngroups = new ThreadGroup[count];
		System.arraycopy(groups, 0, ngroups, 0, count);
		return ngroups;
	}

	/**
	 * Answers the top level group of the current thread.
	 * <p>
	 * It is the 'system' or 'main' thread group under
	 * which all 'user' thread groups are allocated.
	 *
	 * @return	The parent of all user thread groups.
	 */
	protected ThreadGroup getTopThreadGroup() {
		ThreadGroup topGroup = Thread.currentThread().getThreadGroup();
		if (topGroup != null) {
			while (topGroup.getParent() != null) {
				topGroup = topGroup.getParent();
			}
		}
		return topGroup;
	}

	/**
	 * Returns the simple class name of an object.
	 *
	 * @param o The object for which a class name is requested
	 * @return	The simple class name.
	 */
	public String simpleClassName(Object o) {
		java.util.StringTokenizer t = new java.util.StringTokenizer(o.getClass().getName(), "."); //$NON-NLS-1$
		int ct = t.countTokens();
		for (int i = 1; i < ct; i++) {
			t.nextToken();
		}
		return t.nextToken();
	}

	@Descriptor(ConsoleMsg.CONSOLE_HELP_GETPROP_COMMAND_DESCRIPTION)
	public void getprop(@Descriptor(ConsoleMsg.CONSOLE_HELP_GETPROP_COMMAND_ARGUMENT_DESCRIPTION) String... propName) throws Exception {
		Properties allProperties = System.getProperties();
		Iterator<?> propertyNames = new TreeSet<Object>(allProperties.keySet()).iterator();
		while (propertyNames.hasNext()) {
			String prop = (String) propertyNames.next();
			if (propName == null || propName.length == 0 || prop.startsWith(propName[0])) {
				System.out.println(prop + '=' + allProperties.getProperty(prop));
			}
		}
	}
	
	@Descriptor(ConsoleMsg.CONSOLE_HELP_DIAG_COMMAND_DESCRIPTION)
	public void diag(@Descriptor(ConsoleMsg.CONSOLE_HELP_DIAG_COMMAND_ARGUMENT_DESCRIPTION) long[] bundleIds) throws Exception {
		if (bundleIds.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		PlatformAdmin platformAdmin = activator.getPlatformAdmin();
		if (platformAdmin == null) {
			System.out.println(ConsoleMsg.CONSOLE_NO_CONSTRAINTS_NO_PLATFORM_ADMIN_MESSAGE);
			return;
		}

		State systemState = platformAdmin.getState(false);
		for (long bundleId : bundleIds) {
			BundleDescription bundle = systemState.getBundle(bundleId);
			if (bundle == null) {
				System.out.println(NLS.bind(ConsoleMsg.CONSOLE_CANNOT_FIND_BUNDLE_ERROR, bundleId));
				continue;
			}
			System.out.println(bundle.getLocation() + " [" + bundle.getBundleId() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
			VersionConstraint[] unsatisfied = platformAdmin.getStateHelper().getUnsatisfiedConstraints(bundle);
			ResolverError[] resolverErrors = platformAdmin.getState(false).getResolverErrors(bundle);
			for (int i = 0; i < resolverErrors.length; i++) {
				if ((resolverErrors[i].getType() & (ResolverError.MISSING_FRAGMENT_HOST | ResolverError.MISSING_GENERIC_CAPABILITY | ResolverError.MISSING_IMPORT_PACKAGE | ResolverError.MISSING_REQUIRE_BUNDLE)) != 0)
					continue;
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(resolverErrors[i].toString());
			}

			if (unsatisfied.length == 0 && resolverErrors.length == 0) {
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(ConsoleMsg.CONSOLE_NO_CONSTRAINTS);
			}
			if (unsatisfied.length > 0) {
				System.out.print("  "); //$NON-NLS-1$
				System.out.println(ConsoleMsg.CONSOLE_DIRECT_CONSTRAINTS);
			}
			for (int i = 0; i < unsatisfied.length; i++) {
				System.out.print("    "); //$NON-NLS-1$
				System.out.println(getResolutionFailureMessage(unsatisfied[i]));
			}
			VersionConstraint[] unsatisfiedLeaves = platformAdmin.getStateHelper().getUnsatisfiedLeaves(new BundleDescription[] {bundle});
			boolean foundLeaf = false;
			for (int i = 0; i < unsatisfiedLeaves.length; i++) {
				if (unsatisfiedLeaves[i].getBundle() == bundle)
					continue;
				if (!foundLeaf) {
					foundLeaf = true;
					System.out.print("  "); //$NON-NLS-1$
					System.out.println(ConsoleMsg.CONSOLE_LEAF_CONSTRAINTS);
				}
				System.out.print("    "); //$NON-NLS-1$
				System.out.println(unsatisfiedLeaves[i].getBundle().getLocation() + " [" + unsatisfiedLeaves[i].getBundle().getBundleId() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
				System.out.print("      "); //$NON-NLS-1$
				System.out.println(getResolutionFailureMessage(unsatisfiedLeaves[i]));
			}
		}
	}
	
	@Descriptor(ConsoleMsg.CONSOLE_HELP_ENABLE_COMMAND_DESCRIPTION)
	public void enableBundle(@Descriptor(ConsoleMsg.CONSOLE_HELP_ENABLE_COMMAND_ARGUMENT_DESCRIPTION) long[] bundleIds) throws Exception {
		if (bundleIds.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		PlatformAdmin platformAdmin = activator.getPlatformAdmin();
		if (platformAdmin == null) {
			System.out.println(ConsoleMsg.CONSOLE_CANNOT_ENABLE_NO_PLATFORM_ADMIN_MESSAGE);
			return;
		}


		State systemState = platformAdmin.getState(false);
		for (long bundleId : bundleIds) {
			BundleDescription bundle = systemState.getBundle(bundleId);
			if (bundle == null) {
				System.out.println(NLS.bind(ConsoleMsg.CONSOLE_CANNOT_FIND_BUNDLE_ERROR, bundleId));
				continue;
			}

			DisabledInfo[] infos = systemState.getDisabledInfos(bundle);
			for (int i = 0; i < infos.length; i++) {
				platformAdmin.removeDisabledInfo(infos[i]);
			}
		}

	}
	
	@Descriptor(ConsoleMsg.CONSOLE_HELP_DISABLE_COMMAND_DESCRIPTION)
	public void disableBundle(@Descriptor(ConsoleMsg.CONSOLE_HELP_DISABLE_COMMAND_ARGUMENT_DESCRIPTION) long[] bundleIds) throws Exception {
		if (bundleIds.length == 0) {
			System.out.println(ConsoleMsg.CONSOLE_NO_BUNDLE_SPECIFIED_ERROR);
			return;
		}
		
		PlatformAdmin platformAdmin = activator.getPlatformAdmin();
		if (platformAdmin == null) {
			System.out.println(ConsoleMsg.CONSOLE_CANNOT_DISABLE_NO_PLATFORM_ADMIN_MESSAGE);
			return;
		}


		State systemState = platformAdmin.getState(false);
		for (long bundleId : bundleIds) {
			BundleDescription bundle = systemState.getBundle(bundleId);
			if (bundle == null) {
				System.out.println(NLS.bind(ConsoleMsg.CONSOLE_CANNOT_FIND_BUNDLE_ERROR, bundleId));
				continue;
			}
				DisabledInfo info = new DisabledInfo(POLICY_CONSOLE, ConsoleMsg.CONSOLE_CONSOLE_BUNDLE_DISABLED_MESSAGE, bundle);
				platformAdmin.addDisabledInfo(info);
			}
	}
	
	@Descriptor(ConsoleMsg.CONSOLE_HELP_LD_COMMAND_DESCRIPTION)
	public void disabledBundles() throws Exception {
		
		PlatformAdmin platformAdmin = activator.getPlatformAdmin();
		if (platformAdmin == null) {
			System.out.println(ConsoleMsg.CONSOLE_CANNOT_LIST_DISABLED_NO_PLATFORM_ADMIN_MESSAGE);
			return;
		}

		State systemState = platformAdmin.getState(false);
		BundleDescription[] disabledBundles = systemState.getDisabledBundles();

		System.out.println(NLS.bind(ConsoleMsg.CONSOLE_DISABLED_COUNT_MESSAGE, String.valueOf(disabledBundles.length)));

		if (disabledBundles.length > 0) {
			System.out.println();
		}
		for (int i = 0; i < disabledBundles.length; i++) {
			DisabledInfo[] disabledInfos = systemState.getDisabledInfos(disabledBundles[i]);

			System.out.println(NLS.bind(ConsoleMsg.CONSOLE_DISABLED_BUNDLE_HEADER, formatBundleName(disabledBundles[i]), String.valueOf(disabledBundles[i].getBundleId())));
			System.out.print(NLS.bind(ConsoleMsg.CONSOLE_DISABLED_BUNDLE_REASON, disabledInfos[0].getMessage(), disabledInfos[0].getPolicyName()));

			for (int j = 1; j < disabledInfos.length; j++) {
				System.out.print(NLS.bind(ConsoleMsg.CONSOLE_DISABLED_BUNDLE_REASON, disabledInfos[j].getMessage(), String.valueOf(disabledInfos[j].getPolicyName())));
			}

			System.out.println();
		}
	}
	
	private String formatBundleName(BundleDescription b) {
		String label = b.getSymbolicName();
		if (label == null || label.length() == 0)
			label = b.toString();
		else
			label = label + "_" + b.getVersion(); //$NON-NLS-1$

		return label;
	}
	
	private String getResolutionFailureMessage(VersionConstraint unsatisfied) {
		if (unsatisfied.isResolved())
			throw new IllegalArgumentException();
		if (unsatisfied instanceof ImportPackageSpecification) {
			if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(((ImportPackageSpecification) unsatisfied).getDirective(Constants.RESOLUTION_DIRECTIVE)))
				return NLS.bind(ConsoleMsg.CONSOLE_MISSING_OPTIONAL_IMPORTED_PACKAGE, versionToString(unsatisfied));
			if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(((ImportPackageSpecification) unsatisfied).getDirective(Constants.RESOLUTION_DIRECTIVE)))
				return NLS.bind(ConsoleMsg.CONSOLE_MISSING_DYNAMIC_IMPORTED_PACKAGE, versionToString(unsatisfied));
			return NLS.bind(ConsoleMsg.CONSOLE_MISSING_IMPORTED_PACKAGE, versionToString(unsatisfied));
		} else if (unsatisfied instanceof BundleSpecification) {
			if (((BundleSpecification) unsatisfied).isOptional())
				return NLS.bind(ConsoleMsg.CONSOLE_MISSING_OPTIONAL_REQUIRED_BUNDLE, versionToString(unsatisfied));
			return NLS.bind(ConsoleMsg.CONSOLE_MISSING_REQUIRED_BUNDLE, versionToString(unsatisfied));
		} else if (unsatisfied instanceof HostSpecification) {
			return NLS.bind(ConsoleMsg.CONSOLE_MISSING_HOST, versionToString(unsatisfied));
		} else if (unsatisfied instanceof NativeCodeSpecification) {
			return NLS.bind(ConsoleMsg.CONSOLE_MISSING_NATIVECODE, unsatisfied.toString());
		} else if (unsatisfied instanceof GenericSpecification) {
			return NLS.bind(ConsoleMsg.CONSOLE_MISSING_REQUIRED_CAPABILITY, unsatisfied.toString());
		}
		return NLS.bind(ConsoleMsg.CONSOLE_MISSING_REQUIREMENT, unsatisfied.toString());
	}
	
	private static String versionToString(VersionConstraint constraint) {
		org.eclipse.osgi.service.resolver.VersionRange versionRange = constraint.getVersionRange();
		if (versionRange == null)
			return constraint.getName();
		return constraint.getName() + '_' + versionRange;
	}

	/**
	 * This is used to track lazily activated bundles.
	 */
	public void bundleChanged(BundleEvent event) {
		int type = event.getType();
		Bundle bundle = event.getBundle();
		synchronized (lazyActivation) {
			switch (type) {
				case BundleEvent.LAZY_ACTIVATION :
					if (!lazyActivation.contains(bundle)) {
						lazyActivation.add(bundle);
					}
					break;

				default :
					lazyActivation.remove(bundle);
					break;
			}
		}

	}
}

