Modified: felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java URL: http://svn.apache.org/viewvc/felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java?rev=1725510&r1=1725509&r2=1725510&view=diff ============================================================================== --- felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java (original) +++ felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java Tue Jan 19 12:59:03 2016 @@ -18,10 +18,11 @@ */ package org.apache.felix.gogo.shell; +import java.util.Arrays; import java.util.Dictionary; import java.util.HashSet; import java.util.Hashtable; -import java.util.Iterator; +import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -43,7 +44,8 @@ public class Activator implements Bundle private ServiceTracker commandProcessorTracker; private Set<ServiceRegistration> regs; - private ExecutorService executor; + private volatile ExecutorService executor; + private volatile StartShellJob shellJob; public Activator() { @@ -59,17 +61,21 @@ public class Activator implements Bundle public void stop(BundleContext context) throws Exception { - Iterator<ServiceRegistration> iterator = regs.iterator(); - while (iterator.hasNext()) + Set<ServiceRegistration> currentRegs = new HashSet<ServiceRegistration>(); + synchronized (regs) { - ServiceRegistration reg = iterator.next(); - reg.unregister(); - iterator.remove(); + currentRegs.addAll(regs); + regs.clear(); } - stopShell(); + for (ServiceRegistration reg : currentRegs) + { + reg.unregister(); + } this.commandProcessorTracker.close(); + + stopShell(); } private ServiceTracker createCommandProcessorTracker() @@ -98,26 +104,34 @@ public class Activator implements Bundle Dictionary<String, Object> dict = new Hashtable<String, Object>(); dict.put(CommandProcessor.COMMAND_SCOPE, "gogo"); + Set<ServiceRegistration> currentRegs = new HashSet<ServiceRegistration>(); + // register converters - regs.add(context.registerService(Converter.class.getName(), new Converters(context.getBundle(0).getBundleContext()), null)); + currentRegs.add(context.registerService(Converter.class.getName(), new Converters(context.getBundle(0).getBundleContext()), null)); // register commands dict.put(CommandProcessor.COMMAND_FUNCTION, Builtin.functions); - regs.add(context.registerService(Builtin.class.getName(), new Builtin(), dict)); + currentRegs.add(context.registerService(Builtin.class.getName(), new Builtin(), dict)); dict.put(CommandProcessor.COMMAND_FUNCTION, Procedural.functions); - regs.add(context.registerService(Procedural.class.getName(), new Procedural(), dict)); + currentRegs.add(context.registerService(Procedural.class.getName(), new Procedural(), dict)); dict.put(CommandProcessor.COMMAND_FUNCTION, Posix.functions); - regs.add(context.registerService(Posix.class.getName(), new Posix(), dict)); + currentRegs.add(context.registerService(Posix.class.getName(), new Posix(), dict)); dict.put(CommandProcessor.COMMAND_FUNCTION, Telnet.functions); - regs.add(context.registerService(Telnet.class.getName(), new Telnet(processor), dict)); + currentRegs.add(context.registerService(Telnet.class.getName(), new Telnet(processor), dict)); Shell shell = new Shell(context, processor); dict.put(CommandProcessor.COMMAND_FUNCTION, Shell.functions); - regs.add(context.registerService(Shell.class.getName(), shell, dict)); + currentRegs.add(context.registerService(Shell.class.getName(), shell, dict)); + + synchronized (regs) + { + regs.addAll(currentRegs); + currentRegs.clear(); + } // start shell on a separate thread... executor = Executors.newSingleThreadExecutor(new ThreadFactory() @@ -127,20 +141,31 @@ public class Activator implements Bundle return new Thread(runnable, "Gogo shell"); } }); - executor.submit(new StartShellJob(context, processor)); + shellJob = new StartShellJob(context, processor); + executor.submit(shellJob); } private void stopShell() { if (executor != null && !(executor.isShutdown() || executor.isTerminated())) { - executor.shutdownNow(); + if (shellJob != null) + { + shellJob.terminate(); + } + executor.shutdown(); try { if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { System.err.println("!!! FAILED TO STOP EXECUTOR !!!"); + Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces(); + for (Map.Entry<Thread, StackTraceElement[]> entry : allStackTraces.entrySet()) + { + Thread t = entry.getKey(); + System.err.printf("Thread: %s (%s): %s\n", t.getName(), t.getState(), Arrays.toString(entry.getValue())); + } } } catch (InterruptedException e) @@ -156,6 +181,7 @@ public class Activator implements Bundle { private final BundleContext context; private final CommandProcessor processor; + private volatile CommandSession session; public StartShellJob(BundleContext context, CommandProcessor processor) { @@ -165,7 +191,7 @@ public class Activator implements Bundle public void run() { - CommandSession session = processor.createSession(System.in, System.out, System.err); + session = processor.createSession(System.in, System.out, System.err); try { // wait for gosh command to be registered @@ -178,6 +204,11 @@ public class Activator implements Bundle args = (args == null) ? "" : args; session.execute("gosh --login " + args); } + catch (InterruptedException e) + { + // Ok, back off... + Thread.currentThread().interrupt(); + } catch (Exception e) { Object loc = session.get(".location"); @@ -191,8 +222,18 @@ public class Activator implements Bundle } finally { + terminate(); + } + } + + public void terminate() + { + if (session != null) + { session.close(); + session = null; } + Thread.currentThread().interrupt(); } } } \ No newline at end of file
Modified: felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java URL: http://svn.apache.org/viewvc/felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java?rev=1725510&r1=1725509&r2=1725510&view=diff ============================================================================== --- felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java (original) +++ felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java Tue Jan 19 12:59:03 2016 @@ -32,7 +32,7 @@ public class Console implements Runnable private final InputStream in; private final PrintStream out; private final History history; - private boolean quit; + private volatile boolean quit; public Console(CommandSession session, History history) { @@ -46,7 +46,7 @@ public class Console implements Runnable { try { - while (!quit) + while (!Thread.currentThread().isInterrupted() && !quit) { CharSequence line = getLine(getPrompt()); @@ -95,8 +95,7 @@ public class Console implements Runnable loc = "gogo"; } - out.println(loc + ": " + e.getClass().getSimpleName() + ": " - + e.getMessage()); + out.println(loc + ": " + e.getClass().getSimpleName() + ": " + e.getMessage()); } } finally @@ -146,7 +145,20 @@ public class Console implements Runnable while (!quit) { out.flush(); - int c = in.read(); + + int c = 0; + try + { + c = in.read(); + } + catch (IOException e) + { + if ("Stream closed".equals(e.getMessage())) { + quit = true; + } else { + throw e; + } + } switch (c) { Modified: felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java URL: http://svn.apache.org/viewvc/felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java?rev=1725510&r1=1725509&r2=1725510&view=diff ============================================================================== --- felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java (original) +++ felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java Tue Jan 19 12:59:03 2016 @@ -24,19 +24,19 @@ import java.lang.reflect.InvocationHandl import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; -import java.util.Formatter; +import org.apache.felix.service.command.Converter; +import org.apache.felix.service.command.Function; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; -import org.apache.felix.service.command.Converter; -import org.apache.felix.service.command.Function; import org.osgi.service.startlevel.StartLevel; public class Converters implements Converter { private final BundleContext context; + public Converters(BundleContext context) { this.context = context; @@ -67,9 +67,6 @@ public class Converters implements Conve private CharSequence print(ServiceReference ref) { - StringBuilder sb = new StringBuilder(); - Formatter f = new Formatter(sb); - String spid = ""; Object pid = ref.getProperty("service.pid"); if (pid != null) @@ -77,10 +74,9 @@ public class Converters implements Conve spid = pid.toString(); } - f.format("%06d %3s %-40s %s", ref.getProperty("service.id"), + return String.format("%06d %3s %-40s %s", ref.getProperty("service.id"), ref.getBundle().getBundleId(), getShortNames((String[]) ref.getProperty("objectclass")), spid); - return sb; } private CharSequence getShortNames(String[] list) Modified: felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java URL: http://svn.apache.org/viewvc/felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java?rev=1725510&r1=1725509&r2=1725510&view=diff ============================================================================== --- felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java (original) +++ felix/trunk/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java Tue Jan 19 12:59:03 2016 @@ -35,6 +35,7 @@ import org.apache.felix.gogo.options.Opt import org.apache.felix.gogo.options.Options; import org.apache.felix.service.command.CommandProcessor; import org.apache.felix.service.command.CommandSession; +import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; @@ -49,6 +50,8 @@ public class Shell private final CommandProcessor processor; private final History history; + private volatile Bundle systemBundle; + public Shell(BundleContext context, CommandProcessor processor) { this.context = context; @@ -79,6 +82,9 @@ public class Shell boolean login = opt.isSet("login"); boolean interactive = !opt.isSet("nointeractive"); + // We grab this bundle as early as possible to avoid having to deal with invalid bundleContexts of this bundle during shutdowns... + systemBundle = context.getBundle(0); + if (opt.isSet("help")) { opt.usage(); @@ -94,8 +100,7 @@ public class Shell throw opt.usageError("option --command requires argument(s)"); } - CommandSession newSession = (login ? session : processor.createSession( - session.getKeyboard(), session.getConsole(), System.err)); + CommandSession newSession = (login ? session : processor.createSession(session.getKeyboard(), session.getConsole(), System.err)); if (opt.isSet("xtrace")) { @@ -108,7 +113,8 @@ public class Shell if (!new File(uri).exists()) { URL url = getClass().getResource("/ext/gosh_profile"); - if (url == null) { + if (url == null) + { url = getClass().getResource("/gosh_profile"); } uri = (url == null) ? null : url.toURI(); @@ -173,10 +179,17 @@ public class Shell result = newSession.execute(program); } - if (login && interactive && !opt.isSet("noshutdown")) + if (login && interactive) { - System.out.println("gosh: stopping framework"); - shutdown(); + if (opt.isSet("noshutdown")) + { + System.out.println("gosh: stopping shell"); + } + else + { + System.out.println("gosh: stopping shell and framework"); + shutdown(); + } } return result; @@ -189,7 +202,11 @@ public class Shell private void shutdown() throws BundleException { - context.getBundle(0).stop(); + if (systemBundle != null) + { + systemBundle.stop(); + systemBundle = null; + } } public Object source(CommandSession session, String script) throws Exception @@ -258,10 +275,12 @@ public class Shell } } - public String[] history() { + public String[] history() + { Iterator<String> history = this.history.getHistory(); List<String> lines = new ArrayList<String>(); - for (int i = 1; history.hasNext(); i++) { + for (int i = 1; history.hasNext(); i++) + { lines.add(String.format("%5d %s", i, history.next())); } return lines.toArray(new String[lines.size()]);
