FELIX-946: Apply Derek Baum patch on gogo
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@787270 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/src/aQute/shell/console/Console.java b/gogo/src/aQute/shell/console/Console.java
index a74ff8e..1c85493 100644
--- a/gogo/src/aQute/shell/console/Console.java
+++ b/gogo/src/aQute/shell/console/Console.java
@@ -40,7 +40,7 @@
try {
while (!quit) {
try {
- CharSequence line = getLine(session.getKeybord());
+ CharSequence line = getLine(session.getKeyboard());
if (line != null) {
history.add(line);
if (history.size() > 40)
diff --git a/gogo/src/aQute/shell/osgi/OSGiCommands.java b/gogo/src/aQute/shell/osgi/OSGiCommands.java
index f715a89..7f3e9a3 100644
--- a/gogo/src/aQute/shell/osgi/OSGiCommands.java
+++ b/gogo/src/aQute/shell/osgi/OSGiCommands.java
@@ -16,6 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
+// DWB1: osgi:each too verbose (formats reults to System.out)
+// DWB2: ClassNotFoundException should be caught in convert() method
package aQute.shell.osgi;
import java.io.*;
@@ -152,8 +154,10 @@
args.add(null);
for (Object x : list) {
args.set(0, x);
- Object result = closure.execute(session, args);
- System.out.println(session.format(result,Converter.INSPECT));
+ //Object result = closure.execute(session, args);
+ // System.out.println(session.format(result,Converter.INSPECT));
+ // derek: this is way too noisy
+ closure.execute(session, args);
}
}
@@ -204,8 +208,14 @@
return convertBundle(in);
else if (desiredType == ServiceReference.class)
return convertServiceReference(in);
- else if (desiredType == Class.class)
- return Class.forName(in.toString());
+ else if (desiredType == Class.class) {
+ // derek.baum@paremus.com - added try/catch
+ try {
+ return Class.forName(in.toString());
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
else if (desiredType.isAssignableFrom(String.class) && in instanceof InputStream)
return read(((InputStream) in));
diff --git a/gogo/src/aQute/shell/osgi/OSGiShell.java b/gogo/src/aQute/shell/osgi/OSGiShell.java
index 3b35496..20e5ef1 100644
--- a/gogo/src/aQute/shell/osgi/OSGiShell.java
+++ b/gogo/src/aQute/shell/osgi/OSGiShell.java
@@ -16,14 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
+// DWB3: dynamically load optional framework components to reduce dependencies
+// DWB4: get() with trailing colon causes org.osgi.framework.InvalidSyntaxException
package aQute.shell.osgi;
import org.osgi.framework.*;
import org.osgi.service.command.*;
import org.osgi.service.component.*;
import org.osgi.service.packageadmin.*;
-import org.osgi.service.permissionadmin.*;
-import org.osgi.service.startlevel.*;
import org.osgi.service.threadio.*;
import aQute.shell.runtime.*;
@@ -45,14 +45,28 @@
addCommand("osgi", commands);
setConverter(commands);
if (bundle.getState() == Bundle.ACTIVE) {
- addCommand("osgi", commands.service(StartLevel.class.getName(),
- null), StartLevel.class);
addCommand("osgi", commands.service(PackageAdmin.class.getName(),
null), PackageAdmin.class);
- addCommand("osgi", commands.service(
- PermissionAdmin.class.getName(), null),
- PermissionAdmin.class);
addCommand("osgi", commands.getContext(), BundleContext.class);
+
+ try {
+ // derek - dynamically load StartLevel to avoid import dependency
+ String sl = "org.osgi.service.startlevel.StartLevel";
+ Class<?> slClass = bundle.loadClass(sl);
+ addCommand("osgi", commands.service(sl, null), slClass);
+ } catch (ClassNotFoundException e) {
+ }
+
+ try {
+ // derek - dynamically load PermissionAdmin to avoid import dependency
+ String pa = "org.osgi.service.permissionadmin.PermissionAdmin";
+ Class<?> paClass = bundle.loadClass(pa);
+ addCommand("osgi", commands.service(pa, null), paClass);
+ } catch (ClassNotFoundException e) {
+ }
+ }
+ else {
+ System.err.println("eek! bundle not active: " + bundle);
}
}
@@ -74,6 +88,10 @@
String service = name.substring(0, n);
String function = name.substring(n + 1);
+
+ // derek - fix org.osgi.framework.InvalidSyntaxException
+ if (service.length() == 0 || function.length() == 0)
+ return null;
String filter = String.format(
"(&(osgi.command.scope=%s)(osgi.command.function=%s))",
diff --git a/gogo/src/aQute/shell/runtime/Closure.java b/gogo/src/aQute/shell/runtime/Closure.java
index 00a297b..d4973cd 100644
--- a/gogo/src/aQute/shell/runtime/Closure.java
+++ b/gogo/src/aQute/shell/runtime/Closure.java
@@ -16,6 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
+// DWB5: session.err is not redirected when creating pipeline
+// DWB6: add 'set -x' trace feature if echo is set
+// DWB7: removing variable via 'execute("name=") throws OutOfBoundsException
package aQute.shell.runtime;
import java.util.*;
@@ -48,6 +51,7 @@
if (pipes.isEmpty()) {
current.setIn(session.in);
current.setOut(session.out);
+ current.setErr(session.err); // XXX: derek.baum@paremus.com
} else {
Pipe previous = pipes.get(pipes.size() - 1);
previous.connect(current);
@@ -81,9 +85,21 @@
Object executeStatement(List<CharSequence> statement) throws Exception {
Object result;
List<Object> values = new ArrayList<Object>();
- Object cmd = eval(statement.remove(0));
- for (CharSequence token : statement)
+ CharSequence statement0 = statement.remove(0);
+
+ // derek: FEATURE: add set -x facility if echo is set
+ StringBuilder buf = new StringBuilder("+ ");
+ buf.append(statement0);
+
+ Object cmd = eval(statement0);
+ for (CharSequence token : statement) {
+ buf.append(' ');
+ buf.append(token);
values.add(eval(token));
+ }
+
+ if (Boolean.TRUE.equals(session.get("echo")))
+ System.err.println(buf);
result = execute(cmd, values);
return result;
@@ -108,7 +124,8 @@
String scmd = cmd.toString();
if (values.size() > 0 && "=".equals(values.get(0))) {
- if (values.size() == 0)
+ //if (values.size() == 0)
+ if (values.size() == 1) // derek: BUGFIX
return session.variables.remove(scmd);
else {
Object value = execute(values.get(1), values.subList(2,
diff --git a/gogo/src/aQute/shell/runtime/CommandSessionImpl.java b/gogo/src/aQute/shell/runtime/CommandSessionImpl.java
index 2607554..1a73a00 100644
--- a/gogo/src/aQute/shell/runtime/CommandSessionImpl.java
+++ b/gogo/src/aQute/shell/runtime/CommandSessionImpl.java
@@ -16,6 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
+// DWB8: throw IllegatlStateException if session used after closed (as per rfc132)
+// DWB9: there is no API to list all variables: https://www.osgi.org/bugzilla/show_bug.cgi?id=49
+// DWB10: add SCOPE support: https://www.osgi.org/bugzilla/show_bug.cgi?id=51
package aQute.shell.runtime;
import java.io.*;
@@ -25,191 +28,209 @@
import org.osgi.service.command.*;
public class CommandSessionImpl implements CommandSession, Converter {
- String COLUMN = "%-20s %s\n";
- InputStream in;
- PrintStream out;
- PrintStream err;
- CommandShellImpl service;
- Map<Object, Object> variables = new HashMap<Object, Object>();
+ String COLUMN = "%-20s %s\n";
+ InputStream in;
+ PrintStream out;
+ PrintStream err;
+ CommandShellImpl service;
+ Map<Object, Object> variables = new HashMap<Object, Object>();
+ private boolean closed; // derek
- CommandSessionImpl(CommandShellImpl service, InputStream in,
- PrintStream out, PrintStream err) {
- this.service = service;
- this.in = in;
- this.out = out;
- this.err = err;
- }
+ CommandSessionImpl(CommandShellImpl service, InputStream in, PrintStream out, PrintStream err) {
+ this.service = service;
+ this.in = in;
+ this.out = out;
+ this.err = err;
+ }
- public void close() {
- }
+ public void close() {
+ this.closed = true; // derek
+ }
- public Object execute(CharSequence commandline) throws Exception {
- assert service != null;
- assert service.threadIO != null;
-
- Closure impl = new Closure(this, null, commandline);
- Object result = impl.execute(this, null);
- return result;
- }
+ public Object execute(CharSequence commandline) throws Exception {
+ assert service != null;
+ assert service.threadIO != null;
+
+ if (closed)
+ throw new IllegalStateException("session is closed"); // derek
- public InputStream getKeybord() {
- return in;
- }
+ Closure impl = new Closure(this, null, commandline);
+ Object result = impl.execute(this, null);
+ return result;
+ }
- public Object get(String name) {
- if (variables != null && variables.containsKey(name))
- return variables.get(name);
+ public InputStream getKeyboard() {
+ return in;
+ }
- return service.get(name);
- }
+ public Object get(String name) {
+ // XXX: derek.baum@paremus.com
+ // there is no API to list all variables, so overload name == null
+ if (name == null)
+ return variables.keySet();
- public void put(String name, Object value) {
- variables.put(name, value);
- }
+ if (variables != null && variables.containsKey(name))
+ return variables.get(name);
- public PrintStream getConsole() {
- return out;
- }
-
-
- @SuppressWarnings("unchecked")
- public
- CharSequence format(Object target, int level, Converter escape ) throws Exception {
- if (target == null)
- return "null";
+ // XXX: derek: add SCOPE support
+ if (name.startsWith("*:")) {
+ String path = variables.containsKey("SCOPE") ? variables.get("SCOPE").toString()
+ : "osgi:*";
+ String func = name.substring(2);
+ for (String scope : path.split(":")) {
+ Object result = service.get(scope + ":" + func);
+ if (result != null)
+ return result;
+ }
+ return null;
+ }
+ return service.get(name);
+ }
- if (target instanceof CharSequence )
- return (CharSequence) target;
-
- for (Converter c : service.converters) {
- CharSequence s = c.format(target, level, this);
- if (s != null)
- return s;
- }
+ public void put(String name, Object value) {
+ variables.put(name, value);
+ }
- if (target.getClass().isArray()) {
- if ( target.getClass().getComponentType().isPrimitive()) {
- if ( target.getClass().getComponentType() == boolean.class )
- return Arrays.toString((boolean[]) target);
- else if ( target.getClass().getComponentType() == byte.class )
- return Arrays.toString((byte[]) target);
- else if ( target.getClass().getComponentType() == short.class )
- return Arrays.toString((short[]) target);
- else if ( target.getClass().getComponentType() == int.class )
- return Arrays.toString((int[]) target);
- else if ( target.getClass().getComponentType() == long.class )
- return Arrays.toString((long[]) target);
- else if ( target.getClass().getComponentType() == float.class )
- return Arrays.toString((float[]) target);
- else if ( target.getClass().getComponentType() == double.class )
- return Arrays.toString((double[]) target);
- else if ( target.getClass().getComponentType() == char.class )
- return Arrays.toString((char[]) target);
- }
- target = Arrays.asList((Object[]) target);
- }
- if (target instanceof Collection) {
- if (level == Converter.INSPECT) {
- StringBuilder sb = new StringBuilder();
- Collection<?> c = (Collection<?>) target;
- for (Object o : c) {
- sb.append(format(o, level + 1, this));
- sb.append("\n");
- }
- return sb;
- } else if (level == Converter.LINE) {
- StringBuilder sb = new StringBuilder();
- String del = "[";
- Collection<?> c = (Collection<?>) target;
- for (Object o : c) {
- sb.append(del);
- sb.append(format(o, level + 1, this));
- del = ", ";
- }
- sb.append("]");
- return sb;
- }
- }
- if ( target instanceof Dictionary ) {
- Map<Object,Object> result = new HashMap<Object,Object>();
- for ( Enumeration e = ((Dictionary)target).keys(); e.hasMoreElements(); ) {
- Object key = e.nextElement();
- result.put(key, ((Dictionary)target).get(key));
- }
- target = result;
- }
- if (target instanceof Map) {
- if (level == Converter.INSPECT) {
- StringBuilder sb = new StringBuilder();
- Map<?,?> c = (Map<?,?>) target;
- for (Map.Entry<?,?> entry : c.entrySet()) {
- CharSequence key = format(entry.getKey(), level + 1, this);
- sb.append(key);
- for ( int i=key.length(); i<20; i++ )
- sb.append(' ');
- sb.append(format(entry.getValue(), level + 1, this));
- sb.append("\n");
- }
- return sb;
- } else if (level == Converter.LINE) {
- StringBuilder sb = new StringBuilder();
- String del = "[";
- Map<?,?> c = (Map<?,?>) target;
- for (Map.Entry<?,?> entry : c.entrySet()) {
- sb.append(del);
- sb.append(format(entry, level + 1,this));
- del = ", ";
- }
- sb.append("]");
- return sb;
- }
- }
- if (level == Converter.INSPECT)
- return inspect(target);
- else
- return target.toString();
- }
+ public PrintStream getConsole() {
+ return out;
+ }
- CharSequence inspect(Object b) {
- boolean found = false;
- Formatter f = new Formatter();
- Method methods[] = b.getClass().getMethods();
- for (Method m : methods) {
- try {
- String name = m.getName();
- if (m.getName().startsWith("get")
- && !m.getName().equals("getClass")
- && m.getParameterTypes().length == 0
- && Modifier.isPublic(m.getModifiers())) {
- found = true;
- name = name.substring(3);
- m.setAccessible(true);
- Object value = m.invoke(b, (Object[]) null);
- f.format(COLUMN, name, format(value, Converter.LINE, this));
- }
- } catch (IllegalAccessException e) {
- // Ignore
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- if (found)
- return (StringBuilder) f.out();
- else
- return b.toString();
- }
+ @SuppressWarnings("unchecked")
+ public CharSequence format(Object target, int level, Converter escape) throws Exception {
+ if (target == null)
+ return "null";
+ if (target instanceof CharSequence)
+ return (CharSequence) target;
- public Object convert(Class<?> desiredType, Object in) {
- return service.convert(desiredType, in);
- }
+ for (Converter c : service.converters) {
+ CharSequence s = c.format(target, level, this);
+ if (s != null)
+ return s;
+ }
- public CharSequence format(Object result, int inspect) {
- try {
- return format(result,inspect,this);
- } catch(Exception e ) {
- return "<can not format " + result + ":" + e;
- }
- }
+ if (target.getClass().isArray()) {
+ if (target.getClass().getComponentType().isPrimitive()) {
+ if (target.getClass().getComponentType() == boolean.class)
+ return Arrays.toString((boolean[]) target);
+ else if (target.getClass().getComponentType() == byte.class)
+ return Arrays.toString((byte[]) target);
+ else if (target.getClass().getComponentType() == short.class)
+ return Arrays.toString((short[]) target);
+ else if (target.getClass().getComponentType() == int.class)
+ return Arrays.toString((int[]) target);
+ else if (target.getClass().getComponentType() == long.class)
+ return Arrays.toString((long[]) target);
+ else if (target.getClass().getComponentType() == float.class)
+ return Arrays.toString((float[]) target);
+ else if (target.getClass().getComponentType() == double.class)
+ return Arrays.toString((double[]) target);
+ else if (target.getClass().getComponentType() == char.class)
+ return Arrays.toString((char[]) target);
+ }
+ target = Arrays.asList((Object[]) target);
+ }
+ if (target instanceof Collection) {
+ if (level == Converter.INSPECT) {
+ StringBuilder sb = new StringBuilder();
+ Collection<?> c = (Collection<?>) target;
+ for (Object o : c) {
+ sb.append(format(o, level + 1, this));
+ sb.append("\n");
+ }
+ return sb;
+ }
+ else if (level == Converter.LINE) {
+ StringBuilder sb = new StringBuilder();
+ String del = "[";
+ Collection<?> c = (Collection<?>) target;
+ for (Object o : c) {
+ sb.append(del);
+ sb.append(format(o, level + 1, this));
+ del = ", ";
+ }
+ sb.append("]");
+ return sb;
+ }
+ }
+ if (target instanceof Dictionary) {
+ Map<Object, Object> result = new HashMap<Object, Object>();
+ for (Enumeration e = ((Dictionary) target).keys(); e.hasMoreElements();) {
+ Object key = e.nextElement();
+ result.put(key, ((Dictionary) target).get(key));
+ }
+ target = result;
+ }
+ if (target instanceof Map) {
+ if (level == Converter.INSPECT) {
+ StringBuilder sb = new StringBuilder();
+ Map<?, ?> c = (Map<?, ?>) target;
+ for (Map.Entry<?, ?> entry : c.entrySet()) {
+ CharSequence key = format(entry.getKey(), level + 1, this);
+ sb.append(key);
+ for (int i = key.length(); i < 20; i++)
+ sb.append(' ');
+ sb.append(format(entry.getValue(), level + 1, this));
+ sb.append("\n");
+ }
+ return sb;
+ }
+ else if (level == Converter.LINE) {
+ StringBuilder sb = new StringBuilder();
+ String del = "[";
+ Map<?, ?> c = (Map<?, ?>) target;
+ for (Map.Entry<?, ?> entry : c.entrySet()) {
+ sb.append(del);
+ sb.append(format(entry, level + 1, this));
+ del = ", ";
+ }
+ sb.append("]");
+ return sb;
+ }
+ }
+ if (level == Converter.INSPECT)
+ return inspect(target);
+ else
+ return target.toString();
+ }
+
+ CharSequence inspect(Object b) {
+ boolean found = false;
+ Formatter f = new Formatter();
+ Method methods[] = b.getClass().getMethods();
+ for (Method m : methods) {
+ try {
+ String name = m.getName();
+ if (m.getName().startsWith("get") && !m.getName().equals("getClass")
+ && m.getParameterTypes().length == 0 && Modifier.isPublic(m.getModifiers())) {
+ found = true;
+ name = name.substring(3);
+ m.setAccessible(true);
+ Object value = m.invoke(b, (Object[]) null);
+ f.format(COLUMN, name, format(value, Converter.LINE, this));
+ }
+ } catch (IllegalAccessException e) {
+ // Ignore
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (found)
+ return (StringBuilder) f.out();
+ else
+ return b.toString();
+ }
+
+ public Object convert(Class<?> desiredType, Object in) {
+ return service.convert(desiredType, in);
+ }
+
+ public CharSequence format(Object result, int inspect) {
+ try {
+ return format(result, inspect, this);
+ } catch (Exception e) {
+ return "<can not format " + result + ":" + e;
+ }
+ }
}
diff --git a/gogo/src/aQute/shell/runtime/CommandShellImpl.java b/gogo/src/aQute/shell/runtime/CommandShellImpl.java
index 5326343..401bb00 100644
--- a/gogo/src/aQute/shell/runtime/CommandShellImpl.java
+++ b/gogo/src/aQute/shell/runtime/CommandShellImpl.java
@@ -16,7 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-
+// DWB11: add removeCommand: https://www.osgi.org/bugzilla/show_bug.cgi?id=49
+// DWB12: there is no API to list commands: https://www.osgi.org/bugzilla/show_bug.cgi?id=49
+// DWB13: addCommand() fails to add static methods (if target is Class)
package aQute.shell.runtime;
import java.io.*;
@@ -34,8 +36,9 @@
public CommandShellImpl() {
addCommand("shell", this, "addCommand" );
+ addCommand("shell", this, "removeCommand" ); // derek
}
-
+
public CommandSession createSession(InputStream in, PrintStream out,
PrintStream err) {
@@ -61,7 +64,7 @@
return null;
String function = name.substring(n);
-
+
Object cmd = null;
if (commands.containsKey(name)) {
@@ -76,7 +79,15 @@
}
}
}
+
+ // XXX: derek.baum@paremus.com
+ // there is no API to list commands
+ // so override otherwise illegal name ":"
+ if (cmd == null && name.equals(":")) {
+ return Collections.unmodifiableSet(commands.keySet());
+ }
}
+
if (cmd == null)
return null;
@@ -87,7 +98,9 @@
}
public void addCommand(String scope, Object target) {
- addCommand(scope,target,target.getClass());
+ // derek - fix target class
+ Class<?> tc = (target instanceof Class) ? (Class<?>) target : target.getClass();
+ addCommand(scope, target, tc);
}
public void addCommand(String scope, Object target, Class<?> functions) {
@@ -103,12 +116,27 @@
public void addCommand(String scope, Object target, String function) {
commands.put((scope + ":" + function).toLowerCase(), target);
}
+
+ // derek.baum@paremus.com: need removeCommand, so stopped bundles can clean up.
+ public void removeCommand(String scope, String function) {
+ String func = (scope + ":" + function).toLowerCase();
+ commands.remove(func);
+ }
+
+ public void removeCommand(Object target) {
+ for (Iterator<Object> i = commands.values().iterator(); i.hasNext();) {
+ if (i.next() == target)
+ i.remove();
+ }
+ }
- public String[] getFunctions(Class<?> target) {
+ private String[] getFunctions(Class<?> target) {
String[] functions;
Set<String> list = new TreeSet<String>();
Method methods[] = target.getMethods();
for (Method m : methods) {
+ if (m.getDeclaringClass().equals(Object.class)) // derek
+ continue;
list.add(m.getName());
if (m.getName().startsWith("get")) {
String s = m.getName().substring(3);
@@ -116,6 +144,7 @@
list.add(s.substring(0, 1).toLowerCase() + s.substring(1));
}
}
+
functions = list.toArray(new String[list.size()]);
return functions;
}
diff --git a/gogo/src/aQute/shell/runtime/Parser.java b/gogo/src/aQute/shell/runtime/Parser.java
index 8585847..10e28db 100644
--- a/gogo/src/aQute/shell/runtime/Parser.java
+++ b/gogo/src/aQute/shell/runtime/Parser.java
@@ -16,6 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
+// DWB14: parser loops if // comment at start of program
+// DWB15: allow program to have trailing ';'
package aQute.shell.runtime;
import java.util.*;
@@ -31,11 +33,16 @@
}
void ws() {
- while (!eof() && Character.isWhitespace(peek())) {
- current++;
+ // derek: BUGFIX: loop if comment at beginning of input
+ //while (!eof() && Character.isWhitespace(peek())) {
+ while (!eof() && (Character.isWhitespace(peek()) || current == 0)) {
+ if (current != 0 || Character.isWhitespace(peek()))
+ current++;
if (peek() == '/' && current < text.length()-2 && text.charAt(current + 1) == '/') {
comment();
}
+ if (current == 0)
+ break;
}
}
@@ -57,7 +64,11 @@
if (c == '\\') {
escaped = true;
- c = text.charAt(++current);
+ ++current;
+ if (eof())
+ throw new RuntimeException("Eof found after \\"); // derek
+
+ c = text.charAt(current);
switch (c) {
case 't':
@@ -117,14 +128,17 @@
statements.add(statement());
while (peek() == ';') {
current++;
- statements.add(statement());
+ // derek: BUGFIX: allow trailing ;
+ ws();
+ if (!eof())
+ statements.add(statement());
}
return statements;
}
public List<CharSequence> statement() {
List<CharSequence> statement = new ArrayList<CharSequence>();
- statement.add(value());
+ statement.add(value());
while (!eof()) {
ws();
if (peek() == '|' || peek() == ';')
@@ -192,6 +206,7 @@
break;
}
}
+
return text.subSequence(start, current);
}
diff --git a/gogo/src/aQute/shell/runtime/Pipe.java b/gogo/src/aQute/shell/runtime/Pipe.java
index c6f04e8..5ac8cdb 100644
--- a/gogo/src/aQute/shell/runtime/Pipe.java
+++ b/gogo/src/aQute/shell/runtime/Pipe.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-
+// DWB16: redirect System.err when creating pipe
package aQute.shell.runtime;
import java.io.*;
@@ -27,6 +27,7 @@
public class Pipe extends Thread {
InputStream in;
PrintStream out;
+ PrintStream err; // derek
PipedOutputStream pout;
Closure closure;
Exception exception;
@@ -47,6 +48,10 @@
this.out = out;
}
+ public void setErr(PrintStream err) {
+ this.err = err;
+ }
+
public Pipe connect(Pipe next) throws IOException {
next.setOut(out);
pout = new PipedOutputStream();
@@ -57,7 +62,8 @@
}
public void run() {
- closure.session.service.threadIO.setStreams(in, out, System.err);
+ //closure.session.service.threadIO.setStreams(in, out, System.err);
+ closure.session.service.threadIO.setStreams(in, out, err); // derek
try {
for (List<CharSequence> statement : statements) {
result = closure.executeStatement(statement);
diff --git a/gogo/src/aQute/shell/runtime/Reflective.java b/gogo/src/aQute/shell/runtime/Reflective.java
index 284191b..1b90b63 100644
--- a/gogo/src/aQute/shell/runtime/Reflective.java
+++ b/gogo/src/aQute/shell/runtime/Reflective.java
@@ -1,5 +1,5 @@
/*
- * Licensed to the Apache Software Foundation (ASF) under one
+* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
@@ -16,6 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
+// DWB16: coerce() doesn't support static methods
+// DWB17: coerce() doesn't support static void main(String[]) in rfc132
+// DWB18: coerce() doesn't extract cause from InvocationTargetException
+// DWB19: coerce() won't add empty array to satisfy Object[] argument
package aQute.shell.runtime;
import java.lang.reflect.*;
@@ -39,7 +43,10 @@
public Object method(CommandSession session, Object target, String name,
List<Object> args) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException, Exception {
- Method[] methods = target.getClass().getMethods();
+ // derek - support static methods
+ //Method[] methods = target.getClass().getMethods();
+ Class<?> tc = (target instanceof Class) ? (Class<?>)target : target.getClass();
+ Method[] methods = tc.getMethods();
name = name.toLowerCase();
String get = "get" + name;
@@ -52,26 +59,36 @@
Method bestMethod = null;
Object[] bestArgs = null;
int match = -1;
+ ArrayList<Class<?>[]> possibleTypes = new ArrayList<Class<?>[]>(); // derek
+
for (Method m : methods) {
String mname = m.getName().toLowerCase();
if (mname.equals(name) || mname.equals(get) || mname.equals(set)
- || mname.equals(is)) {
+ || mname.equals(is) || mname.equals("_main")) { // derek - added _main
Class<?>[] types = m.getParameterTypes();
+ ArrayList<Object> xargs = new ArrayList<Object>(args); // derek - BUGFIX don't modify args
// Check if the command takes a session
if (types.length > 0
&& CommandSession.class.isAssignableFrom(types[0])) {
- args.add(0, session);
+ xargs.add(0, session);
}
Object[] parms = new Object[types.length];
// if (types.length >= args.size() ) {
- int local = coerce(session, target, types, parms, args);
- if (local == types.length || local > match) {
- bestMethod = m;
- bestArgs = parms;
- match = local;
+ int local = coerce(session, target, types, parms, xargs);
+ if ((local >= xargs.size()) && (local >= types.length)) { // derek - stop no-args
+ boolean exact = (local == xargs.size() && local == types.length);
+ if (exact || local > match) {
+ bestMethod = m;
+ bestArgs = parms;
+ match = local;
+ }
+ if (exact)
+ break;
}
+ else
+ possibleTypes.add(types); // derek
// }
// if (match == -1 && types.length == 1
// && types[0] == Object[].class) {
@@ -84,10 +101,36 @@
if (bestMethod != null) {
bestMethod.setAccessible(true);
- return bestMethod.invoke(target, bestArgs);
- } else
- throw new IllegalArgumentException("Cannot find command:" + name
- + " with args:" + args);
+ // derek: BUGFIX catch InvocationTargetException
+ // return bestMethod.invoke(target, bestArgs);
+ try {
+ return bestMethod.invoke(target, bestArgs);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof Exception)
+ throw (Exception)cause;
+ throw e;
+ }
+ } else {
+ //throw new IllegalArgumentException("Cannot find command:" + name + " with args:" + args);
+ // { derek
+ ArrayList<String> list = new ArrayList<String>();
+ for (Class<?>[] types : possibleTypes) {
+ StringBuilder buf = new StringBuilder();
+ buf.append('(');
+ for (Class<?> type : types) {
+ if (buf.length() > 1)
+ buf.append(", ");
+ buf.append(type.getSimpleName());
+ }
+ buf.append(')');
+ list.add(buf.toString());
+ }
+
+ throw new IllegalArgumentException(
+ String.format("Cannot coerce %s%s to any of %s", name, args, list));
+ // } derek
+ }
}
/**
@@ -104,6 +147,7 @@
* @return
* @throws Exception
*/
+ @SuppressWarnings("unchecked")
private int coerce(CommandSession session, Object target, Class<?> types[],
Object out[], List<Object> in) throws Exception {
int i = 0;
@@ -111,11 +155,29 @@
out[i] = null;
try {
// Try to convert one argument
- out[i] = coerce(session, target, types[i], in.get(i));
+ // derek: add empty array as extra argument
+ //out[i] = coerce(session, target, types[i], in.get(i));
+ if (i == in.size())
+ out[i] = NO_MATCH;
+ else
+ out[i] = coerce(session, target, types[i], in.get(i));
+
if (out[i] == NO_MATCH) {
// Failed
// No match, check for varargs
if (types[i].isArray() && i == types.length - 1) {
+
+ // derek - expand final array arg
+ if (i < in.size()) {
+ Object arg = in.get(i);
+ if (arg instanceof List) {
+ List<Object> args = (List<Object>)arg;
+ in = new ArrayList<Object>(in);
+ in.remove(i);
+ in.addAll(args);
+ }
+ }
+
// Try to parse the remaining arguments in an array
Class<?> component = types[i].getComponentType();
Object components = Array.newInstance(component, in
@@ -132,14 +194,18 @@
}
out[n] = components;
// Is last element, so we will quite hereafter
- return n;
+ // return n;
+ if (i == in.size())
+ ++i;
+ return i; // derek - return number of args converted
}
return -1;
}
i++;
} catch (Exception e) {
- // e.printStackTrace();
- System.err.println(e);
+ System.err.println("Reflective:" + e);
+ e.printStackTrace();
+
// should get rid of those exceptions, but requires
// reg ex matching to see if it throws an exception.
// dont know what is better
@@ -175,23 +241,28 @@
return NO_MATCH;
}
}
- if (type == boolean.class)
- return new Boolean(string);
- else if (type == byte.class)
- return new Byte(string);
- else if (type == char.class) {
- if (string.length() == 1)
- return string.charAt(0);
- } else if (type == short.class)
- return new Short(string);
- else if (type == int.class)
- return new Integer(string);
- else if (type == float.class)
- return new Float(string);
- else if (type == double.class)
- return new Double(string);
- else if (type == long.class)
- return new Long(string);
+
+ try {
+ if (type == boolean.class)
+ return new Boolean(string);
+ else if (type == byte.class)
+ return new Byte(string);
+ else if (type == char.class) {
+ if (string.length() == 1)
+ return string.charAt(0);
+ } else if (type == short.class)
+ return new Short(string);
+ else if (type == int.class)
+ return new Integer(string);
+ else if (type == float.class)
+ return new Float(string);
+ else if (type == double.class)
+ return new Double(string);
+ else if (type == long.class)
+ return new Long(string);
+ }
+ catch (NumberFormatException e) {
+ }
return NO_MATCH;
}
diff --git a/gogo/src/aQute/threadio/ThreadIOImpl.java b/gogo/src/aQute/threadio/ThreadIOImpl.java
index 314671a..55b5ae3 100644
--- a/gogo/src/aQute/threadio/ThreadIOImpl.java
+++ b/gogo/src/aQute/threadio/ThreadIOImpl.java
@@ -16,14 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
+// DWB20: ThreadIO should check and reset IO if something (e.g. jetty) overrides
package aQute.threadio;
import java.io.*;
+import java.util.logging.Logger;
import org.osgi.service.component.*;
import org.osgi.service.threadio.*;
public class ThreadIOImpl implements ThreadIO {
+ static private final Logger log = Logger.getLogger(ThreadIOImpl.class.getName());
ThreadPrintStream err = new ThreadPrintStream(System.err);
ThreadPrintStream out = new ThreadPrintStream(System.out);
ThreadInputStream in = new ThreadInputStream(System.in);
@@ -51,7 +54,25 @@
System.setErr(err);
}
+ private void checkIO() { // derek
+ if (System.in != in) {
+ log.fine("ThreadIO: eek! who's set System.in=" + System.in);
+ System.setIn(in);
+ }
+
+ if (System.out != out) {
+ log.fine("ThreadIO: eek! who's set System.out=" + System.out);
+ System.setOut(out);
+ }
+
+ if (System.err != err) {
+ log.fine("ThreadIO: eek! who's set System.err=" + System.err);
+ System.setErr(err);
+ }
+ }
+
public void close() {
+ checkIO(); // derek
Marker top = this.current.get();
if ( top == null )
throw new IllegalStateException("No thread io active");
@@ -71,6 +92,7 @@
assert in != null;
assert out != null;
assert err != null;
+ checkIO(); // derek
Marker marker = new Marker(this,in,out,err, current.get());
this.current.set(marker);
marker.activate();
diff --git a/gogo/test/test/aQute/shell/runtime/TestParser.java b/gogo/test/test/aQute/shell/runtime/TestParser.java
index d957554..5f880bb 100644
--- a/gogo/test/test/aQute/shell/runtime/TestParser.java
+++ b/gogo/test/test/aQute/shell/runtime/TestParser.java
@@ -194,18 +194,18 @@
public void ls() {
beentheredonethat++;
- System.out.println("Yes!");
+ System.out.println("ls(): Yes!");
}
public int ls(int onoff) {
beentheredonethat += onoff;
- System.out.println("ls " + onoff);
+ System.out.println("ls(int) " + onoff);
return onoff;
}
public void ls(Object args[]) {
beentheredonethat = args.length;
- System.out.print("ls [");
+ System.out.print("ls(Object[]) [");
for (Object i : args)
System.out.print(i + " ");
System.out.println("]");