Author: gnodet
Date: Tue Dec 17 09:37:51 2013
New Revision: 1551496
URL: http://svn.apache.org/r1551496
Log:
[KARAF-2628] Fix synchronization issues in the commands completer
Modified:
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
Modified:
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
URL:
http://svn.apache.org/viewvc/karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java?rev=1551496&r1=1551495&r2=1551496&view=diff
==============================================================================
---
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
(original)
+++
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
Tue Dec 17 09:37:51 2013
@@ -83,6 +83,9 @@ public class CommandNamesCompleter imple
private class CommandTracker {
public CommandTracker() throws Exception {
BundleContext context =
FrameworkUtil.getBundle(getClass()).getBundleContext();
+ if (context == null) {
+ throw new IllegalStateException("Bundle is stopped");
+ }
ServiceListener listener = new ServiceListener() {
public void serviceChanged(ServiceEvent event) {
commands.clear();
Modified:
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
URL:
http://svn.apache.org/viewvc/karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java?rev=1551496&r1=1551495&r2=1551496&view=diff
==============================================================================
---
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
(original)
+++
karaf/branches/karaf-2.x/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
Tue Dec 17 09:37:51 2013
@@ -26,11 +26,15 @@ import java.util.List;
import java.util.Set;
import org.apache.felix.gogo.commands.basic.AbstractCommand;
+import org.apache.felix.service.command.CommandProcessor;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Function;
import org.apache.karaf.shell.console.Completer;
import org.apache.karaf.shell.console.jline.CommandSessionHolder;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,6 +59,11 @@ public class CommandsCompleter implement
public CommandsCompleter(CommandSession session) {
this.session = session;
+ try {
+ new CommandTracker();
+ } catch (Throwable t) {
+ // Ignore in case we're not in OSGi
+ }
}
@@ -68,16 +77,20 @@ public class CommandsCompleter implement
return res;
}
- protected synchronized void checkData() {
+ protected void checkData() {
// Copy the set to avoid concurrent modification exceptions
// TODO: fix that in gogo instead
- Set<String> names = new HashSet<String>((Set<String>)
session.get(COMMANDS));
- if (!names.equals(commands)) {
- commands.clear();
- completers.clear();
-
+ Set<String> names;
+ boolean update;
+ synchronized (this) {
+ names = new HashSet<String>((Set<String>) session.get(COMMANDS));
+ update = !names.equals(commands);
+ }
+ if (update) {
// get command aliases
Set<String> aliases = this.getAliases();
+ Set<String> commands = new HashSet<String>();
+ List<Completer> completers = new ArrayList<Completer>();
completers.add(new StringsCompleter(aliases));
// add argument completers for each command
@@ -93,6 +106,13 @@ public class CommandsCompleter implement
}
commands.add(command);
}
+
+ synchronized (this) {
+ this.commands.clear();
+ this.completers.clear();
+ this.commands.addAll(commands);
+ this.completers.addAll(completers);
+ }
}
}
@@ -106,7 +126,7 @@ public class CommandsCompleter implement
Set<String> aliases = new HashSet<String>();
for (String var : vars) {
Object content = session.get(var);
- if
("org.apache.felix.gogo.runtime.Closure".equals(content.getClass().getName()))
{
+ if (content != null &&
"org.apache.felix.gogo.runtime.Closure".equals(content.getClass().getName())) {
aliases.add(var);
}
}
@@ -122,13 +142,15 @@ public class CommandsCompleter implement
referenceField.setAccessible(true);
BundleContext context = (BundleContext)
contextField.get(function);
ServiceReference reference = (ServiceReference)
referenceField.get(function);
- Object target = context.getService(reference);
+ Object target = context != null ?
context.getService(reference) : null;
try {
if (target instanceof Function) {
function = (Function) target;
}
} finally {
- context.ungetService(reference);
+ if (context != null) {
+ context.ungetService(reference);
+ }
}
}
} catch (Throwable t) {
@@ -136,5 +158,24 @@ public class CommandsCompleter implement
return function;
}
+ private class CommandTracker {
+ public CommandTracker() throws Exception {
+ BundleContext context =
FrameworkUtil.getBundle(getClass()).getBundleContext();
+ if (context == null) {
+ throw new IllegalStateException("Bundle is stopped");
+ }
+ ServiceListener listener = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ synchronized (CommandsCompleter.this) {
+ commands.clear();
+ }
+ }
+ };
+ context.addServiceListener(listener,
+ String.format("(&(%s=*)(%s=*))",
+ CommandProcessor.COMMAND_SCOPE,
+ CommandProcessor.COMMAND_FUNCTION));
+ }
+ }
}