FELIX-5077 / FELIX-3331 - more reliable shutdown
- fix some infrastructure/Maven related issues causing the build to break at
unexpected moments;
- introduced a base test case that properly created and destroys the parsing
context (prevents unexpected test failures);
- shut down the shell thread correctly;
- some other minor issues fixed.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1725510 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/gogo-parent/pom.xml b/gogo/gogo-parent/pom.xml
index 0fdf21a..c93ba1a 100644
--- a/gogo/gogo-parent/pom.xml
+++ b/gogo/gogo-parent/pom.xml
@@ -39,6 +39,12 @@
<version>4.5</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.10.19</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/gogo/runtime/pom.xml b/gogo/runtime/pom.xml
index 515095a..23a686c 100644
--- a/gogo/runtime/pom.xml
+++ b/gogo/runtime/pom.xml
@@ -1,86 +1,86 @@
-<!--
- 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
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <parent>
- <groupId>org.apache.felix</groupId>
- <artifactId>gogo-parent</artifactId>
- <version>0.6.0</version>
- <relativePath>../gogo-parent/pom.xml</relativePath>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <packaging>bundle</packaging>
- <name>Apache Felix Gogo Runtime</name>
- <artifactId>org.apache.felix.gogo.runtime</artifactId>
- <version>0.16.3-SNAPSHOT</version>
- <dependencies>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- <version>4.0.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.compendium</artifactId>
- <version>4.0.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Export-Service>
- org.apache.felix.service.threadio.ThreadIO,
- org.apache.felix.service.command.CommandProcessor
- </Export-Service>
- <Export-Package>
- org.apache.felix.service.command;
- org.apache.felix.service.threadio; version=${project.version}; status="provisional"; mandatory:="status",
- org.apache.felix.gogo.api; version=${project.version}
- </Export-Package>
- <Import-Package>
- org.osgi.service.event*; resolution:=optional,
- org.osgi.service.log*; resolution:=optional,
- org.osgi.service.packageadmin*; resolution:=optional,
- org.osgi.service.startlevel*; resolution:=optional,
- *
- </Import-Package>
- <Private-Package>org.apache.felix.gogo.runtime*</Private-Package>
- <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
- <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
- <Bundle-Activator>org.apache.felix.gogo.runtime.activator.Activator</Bundle-Activator>
- <Include-Resource>{maven-resources},META-INF/LICENSE=LICENSE,META-INF/NOTICE=NOTICE,META-INF/DEPENDENCIES=DEPENDENCIES</Include-Resource>
- <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
- <_removeheaders>Private-Package,Ignore-Package,Include-Resource</_removeheaders>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
+<!-- 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 to
+ you under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of
+ the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
+ by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ OF ANY KIND, either express or implied. See the License for the specific
+ language governing permissions and limitations under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>gogo-parent</artifactId>
+ <version>0.6.0</version>
+ <relativePath>../gogo-parent/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix Gogo Runtime</name>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ <version>0.16.3-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.10.19</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Service>
+ org.apache.felix.service.threadio.ThreadIO,
+ org.apache.felix.service.command.CommandProcessor
+ </Export-Service>
+ <Export-Package>
+ org.apache.felix.service.command;
+ org.apache.felix.service.threadio; version=${project.version}; status="provisional";
+ mandatory:="status",
+ org.apache.felix.gogo.api; version=${project.version}
+ </Export-Package>
+ <Import-Package>
+ org.osgi.service.event*; resolution:=optional,
+ org.osgi.service.log*; resolution:=optional,
+ org.osgi.service.packageadmin*; resolution:=optional,
+ org.osgi.service.startlevel*; resolution:=optional,
+ *
+ </Import-Package>
+ <Private-Package>org.apache.felix.gogo.runtime*</Private-Package>
+ <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Activator>org.apache.felix.gogo.runtime.activator.Activator</Bundle-Activator>
+ <Include-Resource>{maven-resources},META-INF/LICENSE=LICENSE,META-INF/NOTICE=NOTICE,META-INF/DEPENDENCIES=DEPENDENCIES</Include-Resource>
+ <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
+ <_removeheaders>Private-Package,Ignore-Package,Include-Resource</_removeheaders>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java
index 9edc62c..7f987dc 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java
@@ -68,7 +68,7 @@
}
}
- void closeSession(CommandSessionImpl session)
+ void removeSession(CommandSessionImpl session)
{
synchronized (sessions)
{
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java
index 30f521a..9935981 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java
@@ -21,10 +21,11 @@
// DWB10: add SCOPE support: https://www.osgi.org/bugzilla/show_bug.cgi?id=51
package org.apache.felix.gogo.runtime;
+import java.io.Closeable;
+import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -48,7 +49,7 @@
protected InputStream in;
protected PrintStream out;
- PrintStream err;
+ protected PrintStream err;
private final CommandProcessorImpl processor;
protected final Map<String, Object> variables = new HashMap<String, Object>();
@@ -71,8 +72,10 @@
{
if (!this.closed)
{
- this.processor.closeSession(this);
+ this.processor.removeSession(this);
this.closed = true;
+
+ this.in = closeSilently(in);
}
}
@@ -344,18 +347,21 @@
{
boolean found = false;
Formatter f = new Formatter();
+ f.close();
+
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()))
+ if (!name.equals("getClass") && name.startsWith("get") && m.getParameterTypes().length == 0)
{
+ m.setAccessible(true);
+ Object value = m.invoke(b);
+
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));
}
}
@@ -400,4 +406,19 @@
return processor.expr(this, expr);
}
+ private static <T extends Closeable> T closeSilently(T resource)
+ {
+ if (resource != null)
+ {
+ try
+ {
+ resource.close();
+ }
+ catch (IOException e)
+ {
+ // Ignore, nothing we can do here...
+ }
+ }
+ return resource;
+ }
}
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Parser.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Parser.java
index 23c2f65..fce18d6 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Parser.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Parser.java
@@ -38,31 +38,33 @@
public List<List<List<Token>>> program()
{
List<List<List<Token>>> program = new ArrayList<List<List<Token>>>();
-
- while (tz.next() != Type.EOT)
+
+ outer: while (tz.next() != Type.EOT)
{
program.add(pipeline());
-
+
switch (tz.type())
{
case SEMICOLON:
case NEWLINE:
continue;
+
+ default:
+ break outer;
}
-
- break;
}
if (tz.next() != Type.EOT)
+ {
throw new RuntimeException("Program has trailing text: " + tz.value());
-
+ }
return program;
}
private List<List<Token>> pipeline()
{
List<List<Token>> pipeline = new ArrayList<List<Token>>();
-
+
while (true)
{
pipeline.add(command());
@@ -89,7 +91,7 @@
while (true)
{
Token t = tz.token();
-
+
switch (t.type)
{
case WORD:
@@ -99,13 +101,13 @@
case ASSIGN:
case EXPR:
break;
-
+
default:
throw new SyntaxError(t.line, t.column, "unexpected token: " + t.type);
}
-
+
command.add(t);
-
+
switch (tz.next())
{
case PIPE:
@@ -113,10 +115,13 @@
case NEWLINE:
case EOT:
return command;
+
+ default:
+ break;
}
}
}
-
+
public void array(List<Token> list, Map<Token, Token> map) throws Exception
{
Token lt = null;
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/BaseTestCase.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/BaseTestCase.java
new file mode 100644
index 0000000..488e49b
--- /dev/null
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/BaseTestCase.java
@@ -0,0 +1,42 @@
+/*
+ * 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
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.gogo.runtime;
+
+import junit.framework.TestCase;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+abstract class BaseTestCase extends TestCase
+{
+ protected Context m_ctx;
+
+ @Override
+ protected final void setUp() throws Exception
+ {
+ m_ctx = new Context(true);
+ }
+
+ @Override
+ protected final void tearDown() throws Exception
+ {
+ m_ctx.stop();
+ }
+}
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/Context.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/Context.java
index b96a313..bd40bf2 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/Context.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/Context.java
@@ -24,7 +24,7 @@
public class Context extends CommandProcessorImpl
{
public static final String EMPTY = "";
-
+
private static final ThreadIOImpl threadio;
private final CommandSession session;
@@ -34,7 +34,7 @@
threadio.start();
}
- public Context()
+ public Context(boolean foo)
{
super(threadio);
addCommand("osgi", this, "addCommand");
@@ -43,6 +43,19 @@
session = (CommandSessionImpl) createSession(System.in, System.out, System.err);
}
+ @Override
+ public void stop()
+ {
+ try
+ {
+ super.stop();
+ }
+ finally
+ {
+ threadio.stop();
+ }
+ }
+
public Object execute(CharSequence source) throws Exception
{
Object result = new Exception();
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java
index ccd7d44..7ab32a1 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java
@@ -18,13 +18,11 @@
*/
package org.apache.felix.gogo.runtime;
-import junit.framework.TestCase;
-
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Descriptor;
import org.apache.felix.service.command.Parameter;
-public class TestCoercion extends TestCase
+public class TestCoercion extends BaseTestCase
{
public boolean fBool(boolean t)
{
@@ -59,32 +57,31 @@
public void testSimpleTypes() throws Exception
{
- Context c = new Context();
- c.addCommand("fBool", this);
- c.addCommand("fDouble", this);
- c.addCommand("fInt", this);
- c.addCommand("fLong", this);
- c.addCommand("fString", this);
+ m_ctx.addCommand("fBool", this);
+ m_ctx.addCommand("fDouble", this);
+ m_ctx.addCommand("fInt", this);
+ m_ctx.addCommand("fLong", this);
+ m_ctx.addCommand("fString", this);
- assertEquals("fBool true", true, c.execute("fBool true"));
- assertEquals("fBool 'false'", false, c.execute("fBool 'false'"));
-
- assertEquals("fDouble 11", 11.0, c.execute("fDouble 11"));
- assertEquals("fDouble '11'", 11.0, c.execute("fDouble '11'"));
-
- assertEquals("fInt 22", 22, c.execute("fInt 22"));
- assertEquals("fInt '23'", 23, c.execute("fInt '23'"));
- assertEquals("fInt 1 2", "array", c.execute("fInt 1 2"));
-
- assertEquals("fLong 33", 33L, c.execute("fLong 33"));
- assertEquals("fLong '34'", 34L, c.execute("fLong '34'"));
-
- assertEquals("fString wibble", "wibble", c.execute("fString wibble"));
- assertEquals("fString 'wibble'", "wibble", c.execute("fString 'wibble'"));
+ assertEquals("fBool true", true, m_ctx.execute("fBool true"));
+ assertEquals("fBool 'false'", false, m_ctx.execute("fBool 'false'"));
+
+ assertEquals("fDouble 11", 11.0, m_ctx.execute("fDouble 11"));
+ assertEquals("fDouble '11'", 11.0, m_ctx.execute("fDouble '11'"));
+
+ assertEquals("fInt 22", 22, m_ctx.execute("fInt 22"));
+ assertEquals("fInt '23'", 23, m_ctx.execute("fInt '23'"));
+ assertEquals("fInt 1 2", "array", m_ctx.execute("fInt 1 2"));
+
+ assertEquals("fLong 33", 33L, m_ctx.execute("fLong 33"));
+ assertEquals("fLong '34'", 34L, m_ctx.execute("fLong '34'"));
+
+ assertEquals("fString wibble", "wibble", m_ctx.execute("fString wibble"));
+ assertEquals("fString 'wibble'", "wibble", m_ctx.execute("fString 'wibble'"));
try
{
- Object r = c.execute("fString ");
+ Object r = m_ctx.execute("fString ");
fail("too few args: expected IllegalArgumentException, got: " + r);
}
catch (IllegalArgumentException e)
@@ -93,7 +90,7 @@
try
{
- Object r = c.execute("fString a b");
+ Object r = m_ctx.execute("fString a b");
fail("too many args: expected IllegalArgumentException, got: " + r);
}
catch (IllegalArgumentException e)
@@ -102,7 +99,7 @@
try
{
- Object r = c.execute("fLong string");
+ Object r = m_ctx.execute("fLong string");
fail("wrong arg type: expected IllegalArgumentException, got: " + r);
}
catch (IllegalArgumentException e)
@@ -122,12 +119,11 @@
public void testBestCoercion() throws Exception
{
- Context c = new Context();
- c.addCommand("bundles", this);
+ m_ctx.addCommand("bundles", this);
- assertEquals("bundles myloc", "string", c.execute("bundles myloc"));
- assertEquals("bundles 1", "long", c.execute("bundles 1"));
- assertEquals("bundles '1'", "string", c.execute("bundles '1'"));
+ assertEquals("bundles myloc", "string", m_ctx.execute("bundles myloc"));
+ assertEquals("bundles 1", "long", m_ctx.execute("bundles 1"));
+ assertEquals("bundles '1'", "string", m_ctx.execute("bundles '1'"));
}
@Descriptor("list all installed bundles")
@@ -149,24 +145,23 @@
public void testParameter0() throws Exception
{
- Context c = new Context();
- c.addCommand("p0", this);
- c.addCommand("p01", this);
+ m_ctx.addCommand("p0", this);
+ m_ctx.addCommand("p01", this);
- assertEquals("p0", "false:false", c.execute("p0"));
- assertEquals("p0 -l", "true:false", c.execute("p0 -l"));
- assertEquals("p0 --location", "true:false", c.execute("p0 --location"));
- assertEquals("p0 -l -s", "true:true", c.execute("p0 -l -s"));
- assertEquals("p0 -s -l", "true:true", c.execute("p0 -s -l"));
+ assertEquals("p0", "false:false", m_ctx.execute("p0"));
+ assertEquals("p0 -l", "true:false", m_ctx.execute("p0 -l"));
+ assertEquals("p0 --location", "true:false", m_ctx.execute("p0 --location"));
+ assertEquals("p0 -l -s", "true:true", m_ctx.execute("p0 -l -s"));
+ assertEquals("p0 -s -l", "true:true", m_ctx.execute("p0 -s -l"));
try
{
- Object r = c.execute("p0 wibble");
+ Object r = m_ctx.execute("p0 wibble");
fail("too many args: expected IllegalArgumentException, got: " + r);
}
catch (IllegalArgumentException e)
{
}
- assertEquals("p01 -f", true, c.execute("p01 -f"));
+ assertEquals("p01 -f", true, m_ctx.execute("p01 -f"));
}
public String p1(
@@ -177,17 +172,16 @@
public void testParameter1() throws Exception
{
- Context c = new Context();
- c.addCommand("p1", this);
+ m_ctx.addCommand("p1", this);
- assertEquals("no parameter", "absent", c.execute("p1"));
+ assertEquals("no parameter", "absent", m_ctx.execute("p1"));
// FELIX-2894
- assertEquals("correct parameter", "wibble", c.execute("p1 -p wibble"));
+ assertEquals("correct parameter", "wibble", m_ctx.execute("p1 -p wibble"));
try
{
- Object r = c.execute("p1 -p");
+ Object r = m_ctx.execute("p1 -p");
fail("missing parameter: expected IllegalArgumentException, got: " + r);
}
catch (IllegalArgumentException e)
@@ -196,12 +190,11 @@
try
{
- Object r = c.execute("p1 -X");
+ Object r = m_ctx.execute("p1 -X");
fail("wrong parameter: expected IllegalArgumentException, got: " + r);
}
catch (IllegalArgumentException e)
{
}
}
-
}
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java
index 13c52f1..7250b0a 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java
@@ -18,13 +18,6 @@
*/
package org.apache.felix.gogo.runtime;
-import junit.framework.TestCase;
-
-import org.apache.felix.gogo.runtime.Parser;
-import org.apache.felix.gogo.runtime.Token;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Function;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -34,27 +27,28 @@
import java.util.List;
import java.util.regex.Pattern;
-public class TestParser extends TestCase
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Function;
+
+public class TestParser extends BaseTestCase
{
int beentheredonethat = 0;
public void testEvaluatation() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- c.addCommand("capture", this);
+ m_ctx.addCommand("echo", this);
+ m_ctx.addCommand("capture", this);
- assertEquals("a", c.execute("echo a | capture"));
- assertEquals("a", c.execute("(echo a) | capture"));
- assertEquals("a", c.execute("((echo a)) | capture"));
+ assertEquals("a", m_ctx.execute("echo a | capture"));
+ assertEquals("a", m_ctx.execute("(echo a) | capture"));
+ assertEquals("a", m_ctx.execute("((echo a)) | capture"));
}
public void testUnknownCommand() throws Exception
{
- Context c = new Context();
try
{
- c.execute("echo");
+ m_ctx.execute("echo");
fail("Execution should have failed due to missing command");
}
catch (IllegalArgumentException e)
@@ -65,111 +59,103 @@
public void testSpecialValues() throws Exception
{
- Context c = new Context();
- assertEquals(false, c.execute("false"));
- assertEquals(true, c.execute("true"));
- assertEquals(null, c.execute("null"));
+ assertEquals(false, m_ctx.execute("false"));
+ assertEquals(true, m_ctx.execute("true"));
+ assertEquals(null, m_ctx.execute("null"));
}
public void testQuotes() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- c.set("c", "a");
+ m_ctx.addCommand("echo", this);
+ m_ctx.set("c", "a");
- assertEquals("a b", c.execute("echo a b"));
- assertEquals("a b", c.execute("echo 'a b'"));
- assertEquals("a b", c.execute("echo \"a b\""));
- assertEquals("a b", c.execute("echo a b"));
- assertEquals("a b", c.execute("echo 'a b'"));
- assertEquals("a b", c.execute("echo \"a b\""));
- assertEquals("a b", c.execute("echo $c b"));
- assertEquals("$c b", c.execute("echo '$c b'"));
- assertEquals("a b", c.execute("echo \"$c b\""));
- assertEquals("a b", c.execute("echo ${c} b"));
- assertEquals("${c} b", c.execute("echo '${c} b'"));
- assertEquals("a b", c.execute("echo \"${c} b\""));
- assertEquals("aa", c.execute("echo $c$c"));
- assertEquals("a ;a", c.execute("echo a\\ \\;a"));
- assertEquals("baabab", c.execute("echo b${c}${c}b${c}b"));
+ assertEquals("a b", m_ctx.execute("echo a b"));
+ assertEquals("a b", m_ctx.execute("echo 'a b'"));
+ assertEquals("a b", m_ctx.execute("echo \"a b\""));
+ assertEquals("a b", m_ctx.execute("echo a b"));
+ assertEquals("a b", m_ctx.execute("echo 'a b'"));
+ assertEquals("a b", m_ctx.execute("echo \"a b\""));
+ assertEquals("a b", m_ctx.execute("echo $c b"));
+ assertEquals("$c b", m_ctx.execute("echo '$c b'"));
+ assertEquals("a b", m_ctx.execute("echo \"$c b\""));
+ assertEquals("a b", m_ctx.execute("echo ${c} b"));
+ assertEquals("${c} b", m_ctx.execute("echo '${c} b'"));
+ assertEquals("a b", m_ctx.execute("echo \"${c} b\""));
+ assertEquals("aa", m_ctx.execute("echo $c$c"));
+ assertEquals("a ;a", m_ctx.execute("echo a\\ \\;a"));
+ assertEquals("baabab", m_ctx.execute("echo b${c}${c}b${c}b"));
- c.set("d", "a b ");
- assertEquals("a b ", c.execute("echo \"$d\""));
+ m_ctx.set("d", "a b ");
+ assertEquals("a b ", m_ctx.execute("echo \"$d\""));
}
public void testScope() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- assertEquals("$a", c.execute("test:echo \\$a"));
- assertEquals("file://poo", c.execute("test:echo file://poo"));
+ m_ctx.addCommand("echo", this);
+ assertEquals("$a", m_ctx.execute("test:echo \\$a"));
+ assertEquals("file://poo", m_ctx.execute("test:echo file://poo"));
}
public void testPipe() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- c.addCommand("capture", this);
- c.addCommand("grep", this);
- c.addCommand("echoout", this);
- c.execute("myecho = { echoout $args }");
- assertEquals("def", c.execute("echo def|grep d.*|capture"));
- assertEquals("def", c.execute("echoout def|grep d.*|capture"));
- assertEquals("def", c.execute("myecho def|grep d.*|capture"));
+ m_ctx.addCommand("echo", this);
+ m_ctx.addCommand("capture", this);
+ m_ctx.addCommand("grep", this);
+ m_ctx.addCommand("echoout", this);
+ m_ctx.execute("myecho = { echoout $args }");
+ assertEquals("def", m_ctx.execute("echo def|grep d.*|capture"));
+ assertEquals("def", m_ctx.execute("echoout def|grep d.*|capture"));
+ assertEquals("def", m_ctx.execute("myecho def|grep d.*|capture"));
assertEquals("def",
- c.execute("(echoout abc; echoout def; echoout ghi)|grep d.*|capture"));
- assertEquals("", c.execute("echoout def; echoout ghi | grep d.* | capture"));
- assertEquals("hello world", c.execute("echo hello world|capture"));
+ m_ctx.execute("(echoout abc; echoout def; echoout ghi)|grep d.*|capture"));
+ assertEquals("", m_ctx.execute("echoout def; echoout ghi | grep d.* | capture"));
+ assertEquals("hello world", m_ctx.execute("echo hello world|capture"));
assertEquals("defghi",
- c.execute("(echoout abc; echoout def; echoout ghi)|grep 'def|ghi'|capture"));
+ m_ctx.execute("(echoout abc; echoout def; echoout ghi)|grep 'def|ghi'|capture"));
}
public void testAssignment() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- c.addCommand("grep", this);
- assertEquals("a", c.execute("a = a; echo ${$a}"));
+ m_ctx.addCommand("echo", this);
+ m_ctx.addCommand("grep", this);
+ assertEquals("a", m_ctx.execute("a = a; echo ${$a}"));
- assertEquals("hello", c.execute("echo hello"));
- assertEquals("hello", c.execute("a = (echo hello)"));
- //assertEquals("a", c.execute("a = a; echo $(echo a)")); // #p2 - no eval in var expansion
- assertEquals("3", c.execute("a=3; echo $a"));
- assertEquals("3", c.execute("a = 3; echo $a"));
- assertEquals("a", c.execute("a = a; echo ${$a}"));
+ assertEquals("hello", m_ctx.execute("echo hello"));
+ assertEquals("hello", m_ctx.execute("a = (echo hello)"));
+ //assertEquals("a", m_ctx.execute("a = a; echo $(echo a)")); // #p2 - no eval in var expansion
+ assertEquals("3", m_ctx.execute("a=3; echo $a"));
+ assertEquals("3", m_ctx.execute("a = 3; echo $a"));
+ assertEquals("a", m_ctx.execute("a = a; echo ${$a}"));
}
public void testComment() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- assertEquals("1", c.execute("echo 1 // hello"));
+ m_ctx.addCommand("echo", this);
+ assertEquals("1", m_ctx.execute("echo 1 // hello"));
}
public void testClosure() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- c.addCommand("capture", this);
+ m_ctx.addCommand("echo", this);
+ m_ctx.addCommand("capture", this);
- assertEquals("a", c.execute("e = { echo $1 } ; e a b"));
- assertEquals("b", c.execute("e = { echo $2 } ; e a b"));
- assertEquals("b", c.execute("e = { eval $args } ; e echo b"));
- assertEquals("ca b", c.execute("e = { echo c$args } ; e a b"));
- assertEquals("c a b", c.execute("e = { echo c $args } ; e a b"));
- assertEquals("ca b", c.execute("e = { echo c$args } ; e 'a b'"));
+ assertEquals("a", m_ctx.execute("e = { echo $1 } ; e a b"));
+ assertEquals("b", m_ctx.execute("e = { echo $2 } ; e a b"));
+ assertEquals("b", m_ctx.execute("e = { eval $args } ; e echo b"));
+ assertEquals("ca b", m_ctx.execute("e = { echo c$args } ; e a b"));
+ assertEquals("c a b", m_ctx.execute("e = { echo c $args } ; e a b"));
+ assertEquals("ca b", m_ctx.execute("e = { echo c$args } ; e 'a b'"));
}
public void testArray() throws Exception
{
- Context c = new Context();
- c.set("echo", true);
+ m_ctx.set("echo", this);
assertEquals("http://www.aqute.biz?com=2&biz=1",
- c.execute("['http://www.aqute.biz?com=2&biz=1'] get 0"));
- assertEquals("{a=2, b=3}", c.execute("[a=2 b=3]").toString());
- assertEquals(3L, c.execute("[a=2 b=3] get b"));
- assertEquals("[3, 4]", c.execute("[1 2 [3 4] 5 6] get 2").toString());
- assertEquals(5, c.execute("[1 2 [3 4] 5 6] size"));
+ m_ctx.execute("['http://www.aqute.biz?com=2&biz=1'] get 0"));
+ assertEquals("{a=2, b=3}", m_ctx.execute("[a=2 b=3]").toString());
+ assertEquals(3L, m_ctx.execute("[a=2 b=3] get b"));
+ assertEquals("[3, 4]", m_ctx.execute("[1 2 [3 4] 5 6] get 2").toString());
+ assertEquals(5, m_ctx.execute("[1 2 [3 4] 5 6] size"));
}
public void testParentheses()
@@ -185,9 +171,8 @@
public void testEcho() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- c.execute("echo peter");
+ m_ctx.addCommand("echo", this);
+ m_ctx.execute("echo peter");
}
public void grep(String match) throws IOException
@@ -220,22 +205,20 @@
public void testVars() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
+ m_ctx.addCommand("echo", this);
- assertEquals("", c.execute("echo ${very.likely.that.this.does.not.exist}"));
- assertNotNull(c.execute("echo ${java.shell.name}"));
- assertEquals("a", c.execute("a = a; echo ${a}"));
+ assertEquals("", m_ctx.execute("echo ${very.likely.that.this.does.not.exist}"));
+ assertNotNull(m_ctx.execute("echo ${java.shell.name}"));
+ assertEquals("a", m_ctx.execute("a = a; echo ${a}"));
}
public void testFunny() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- assertEquals("a", c.execute("echo a") + "");
- assertEquals("a", c.execute("eval (echo echo) a") + "");
- //assertEquals("a", c.execute("((echo echo) echo) (echo a)") + "");
- assertEquals("3", c.execute("[a=2 (echo b)=(echo 3)] get b").toString());
+ m_ctx.addCommand("echo", this);
+ assertEquals("a", m_ctx.execute("echo a") + "");
+ assertEquals("a", m_ctx.execute("eval (echo echo) a") + "");
+ //assertEquals("a", m_ctx.execute("((echo echo) echo) (echo a)") + "");
+ assertEquals("3", m_ctx.execute("[a=2 (echo b)=(echo 3)] get b").toString());
}
public CharSequence echo(Object args[])
@@ -265,22 +248,21 @@
public void testContext() throws Exception
{
- Context c = new Context();
- c.addCommand("ls", this);
+ m_ctx.addCommand("ls", this);
beentheredonethat = 0;
- c.execute("ls");
+ m_ctx.execute("ls");
assertEquals(1, beentheredonethat);
beentheredonethat = 0;
- c.execute("ls 10");
+ m_ctx.execute("ls 10");
assertEquals(10, beentheredonethat);
beentheredonethat = 0;
- c.execute("ls a b c d e f g h i j");
+ m_ctx.execute("ls a b c d e f g h i j");
assertEquals(10, beentheredonethat);
beentheredonethat = 0;
- Integer result = (Integer) c.execute("ls (ls 5)");
+ Integer result = (Integer) m_ctx.execute("ls (ls 5)");
assertEquals(10, beentheredonethat);
assertEquals((Integer) 5, result);
}
@@ -336,8 +318,7 @@
public void testSimpleValue()
{
List<Token> x = new Parser(
- "abc def.ghi http://www.osgi.org?abc=&x=1 [1,2,3] {{{{{{{xyz}}}}}}} (immediate) {'{{{{{'} {\\{} 'abc{}'")
- .program().get(0).get(0);
+ "abc def.ghi http://www.osgi.org?abc=&x=1 [1,2,3] {{{{{{{xyz}}}}}}} (immediate) {'{{{{{'} {\\{} 'abc{}'").program().get(0).get(0);
assertEquals("abc", x.get(0).toString());
assertEquals("def.ghi", x.get(1).toString());
assertEquals("http://www.osgi.org?abc=&x=1", x.get(2).toString());
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser2.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser2.java
index 350f9f6..4df5dab 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser2.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser2.java
@@ -20,26 +20,23 @@
import java.io.EOFException;
-import junit.framework.TestCase;
-
/*
* Test features of the new parser/tokenizer, many of which are not supported
* by the original parser.
*/
-public class TestParser2 extends TestCase
+public class TestParser2 extends BaseTestCase
{
public void testComment() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
+ m_ctx.addCommand("echo", this);
- assertEquals("file://wibble#tag", c.execute("echo file://wibble#tag"));
- assertEquals("file:", c.execute("echo file: //wibble#tag"));
+ assertEquals("file://wibble#tag", m_ctx.execute("echo file://wibble#tag"));
+ assertEquals("file:", m_ctx.execute("echo file: //wibble#tag"));
- assertEquals("PWD/*.java", c.execute("echo PWD/*.java"));
+ assertEquals("PWD/*.java", m_ctx.execute("echo PWD/*.java"));
try
{
- c.execute("echo PWD /*.java");
+ m_ctx.execute("echo PWD /*.java");
fail("expected EOFException");
}
catch (EOFException e)
@@ -47,44 +44,42 @@
// expected
}
- assertEquals("ok", c.execute("// can't quote\necho ok\n"));
+ assertEquals("ok", m_ctx.execute("// can't quote\necho ok\n"));
// quote in comment in closure
- assertEquals("ok", c.execute("x = { // can't quote\necho ok\n}; x"));
- assertEquals("ok", c.execute("x = {\n// can't quote\necho ok\n}; x"));
- assertEquals("ok", c.execute("x = {// can't quote\necho ok\n}; x"));
+ assertEquals("ok", m_ctx.execute("x = { // can't quote\necho ok\n}; x"));
+ assertEquals("ok", m_ctx.execute("x = {\n// can't quote\necho ok\n}; x"));
+ assertEquals("ok", m_ctx.execute("x = {// can't quote\necho ok\n}; x"));
}
public void testCoercion() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
+ m_ctx.addCommand("echo", this);
// FELIX-2432
- assertEquals("null x", c.execute("echo $expandsToNull x"));
+ assertEquals("null x", m_ctx.execute("echo $expandsToNull x"));
}
public void testStringExecution() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
- c.addCommand("new", this);
+ m_ctx.addCommand("echo", this);
+ m_ctx.addCommand("new", this);
// FELIX-2433
- assertEquals("helloworld", c.execute("echo \"$(echo hello)world\""));
+ assertEquals("helloworld", m_ctx.execute("echo \"$(echo hello)world\""));
// FELIX-1473 - allow method calls on String objects
- assertEquals("hello", c.execute("cmd = echo; eval $cmd hello"));
- assertEquals(4, c.execute("'four' length"));
+ assertEquals("hello", m_ctx.execute("cmd = echo; eval $cmd hello"));
+ assertEquals(4, m_ctx.execute("'four' length"));
try {
- c.execute("four length");
+ m_ctx.execute("four length");
fail("expected: command not found: four");
} catch (IllegalArgumentException e) {
}
// check CharSequence types are preserved
- Object b = c.execute("b = new java.lang.StringBuilder");
+ Object b = m_ctx.execute("b = new java.lang.StringBuilder");
assertTrue(b instanceof StringBuilder);
- assertEquals(b, c.execute("c = $b"));
+ assertEquals(b, m_ctx.execute("c = $b"));
}
public CharSequence echo(Object args[])
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser3.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser3.java
index 3ffd2bc..2bfdbf8 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser3.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser3.java
@@ -18,27 +18,29 @@
*/
package org.apache.felix.gogo.runtime;
-import junit.framework.TestCase;
-
-import java.io.EOFException;
-
/*
* Test features of the new parser/tokenizer, many of which are not supported
* by the original parser.
*/
-public class TestParser3 extends TestCase
+public class TestParser3 extends BaseTestCase
{
public void testArithmetic() throws Exception
{
- Context c = new Context();
- c.addCommand("echo", this);
+ m_ctx.addCommand("echo", this);
- assertEquals("10d", c.execute("echo %(2*(3+2))d"));
- assertEquals(3l, c.execute("%(1+2)"));
+ try
+ {
+ assertEquals("10d", m_ctx.execute("echo %(2*(3+2))d"));
+ assertEquals(3l, m_ctx.execute("%(1+2)"));
- c.set("a", 2l);
- assertEquals(3l, c.execute("%(a+=1)"));
- assertEquals(3l, c.get("a"));
+ m_ctx.set("a", 2l);
+ assertEquals(3l, m_ctx.execute("%(a+=1)"));
+ assertEquals(3l, m_ctx.get("a"));
+ }
+ finally
+ {
+ m_ctx.stop();
+ }
}
public CharSequence echo(Object args[])
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java
index da1f959..434d280 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java
@@ -28,15 +28,11 @@
import java.util.HashMap;
import java.util.Map;
-import junit.framework.TestCase;
-
import org.apache.felix.gogo.runtime.Tokenizer.Type;
-import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
-import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-public class TestTokenizer extends TestCase
+public class TestTokenizer extends BaseTestCase
{
private final Map<String, Object> vars = new HashMap<String, Object>();
private final Evaluate evaluate;
@@ -62,7 +58,6 @@
};
}
- @Test
public void testHello() throws Exception
{
testHello("hello world\n");
@@ -103,8 +98,7 @@
assertEquals(Type.NEWLINE, t.next());
assertEquals(Type.EOT, t.next());
}
-
- @Test
+
public void testString() throws Exception
{
testString("'single $quote' \"double $quote\"\n");
@@ -122,7 +116,6 @@
assertEquals(Type.EOT, t.next());
}
- @Test
public void testClosure() throws Exception
{
testClosure2("x = { echo '}' $args //comment's\n}\n");
@@ -134,7 +127,6 @@
/*
* x = {echo $args};
*/
- @Test
private void testClosure2(CharSequence text) throws Exception
{
Tokenizer t = new Tokenizer(text);
@@ -155,7 +147,6 @@
return type;
}
- @Test
public void testExpand() throws Exception
{
final URI home = new URI("/home/derek");
@@ -278,7 +269,6 @@
return Tokenizer.expand(word, evaluate);
}
- @Test
public void testParser() throws Exception
{
new Parser("// comment\n" + "a=\"who's there?\"; ps -ef;\n" + "ls | \n grep y\n").program();
@@ -290,31 +280,19 @@
/**
* FELIX-4679 / FELIX-4671.
*/
- @Test
public void testScriptFelix4679() throws Exception
{
String script = "addcommand system (((${.context} bundles) 0) loadclass java.lang.System)";
- ThreadIOImpl tio = new ThreadIOImpl();
- tio.start();
+ BundleContext bc = createMockContext();
- try
- {
- BundleContext bc = createMockContext();
+ m_ctx.addCommand("gogo", m_ctx, "addcommand");
+ m_ctx.addConstant(".context", bc);
- CommandProcessorImpl processor = new CommandProcessorImpl(tio);
- processor.addCommand("gogo", processor, "addcommand");
- processor.addConstant(".context", bc);
+ CommandSessionImpl session = new CommandSessionImpl(m_ctx, new ByteArrayInputStream(script.getBytes()), System.out, System.err);
- CommandSessionImpl session = new CommandSessionImpl(processor, new ByteArrayInputStream(script.getBytes()), System.out, System.err);
-
- Closure c = new Closure(session, null, script);
- assertNull(c.execute(session, null));
- }
- finally
- {
- tio.stop();
- }
+ Closure c = new Closure(session, null, script);
+ assertNull(c.execute(session, null));
}
private BundleContext createMockContext() throws ClassNotFoundException
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java
index 32ea917..2cc60df 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/threadio/TestThreadIO.java
@@ -38,6 +38,7 @@
{
ThreadIOImpl tio = new ThreadIOImpl();
tio.start();
+
List<ByteArrayOutputStream> list = new ArrayList<ByteArrayOutputStream>();
for (int i = 0; i < 10; i++)
{
@@ -66,6 +67,7 @@
{
ThreadIOImpl tio = new ThreadIOImpl();
tio.start();
+
System.out.println("Hello World");
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
diff --git a/gogo/shell/pom.xml b/gogo/shell/pom.xml
index 74e1097..da017c8 100644
--- a/gogo/shell/pom.xml
+++ b/gogo/shell/pom.xml
@@ -1,101 +1,94 @@
-<!--
- 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
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <parent>
- <groupId>org.apache.felix</groupId>
- <artifactId>gogo-parent</artifactId>
- <version>0.6.0</version>
- <relativePath>../gogo-parent/pom.xml</relativePath>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <packaging>bundle</packaging>
- <name>Apache Felix Gogo Shell</name>
- <artifactId>org.apache.felix.gogo.shell</artifactId>
- <version>0.13.0-SNAPSHOT</version>
- <dependencies>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- <version>4.2.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.compendium</artifactId>
- <version>4.0.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.gogo.runtime</artifactId>
- <version>0.10.0</version>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Export-Package>
- </Export-Package>
- <Import-Package>
- org.apache.felix.service.command; status="provisional",
- *
- </Import-Package>
- <Private-Package>
- org.apache.felix.gogo.shell,
- org.apache.felix.gogo.options
- </Private-Package>
- <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
- <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
- <Bundle-Activator>org.apache.felix.gogo.shell.Activator</Bundle-Activator>
- <Include-Resource>{maven-resources},META-INF/LICENSE=LICENSE,META-INF/NOTICE=NOTICE,META-INF/DEPENDENCIES=DEPENDENCIES</Include-Resource>
- <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
- <_removeheaders>Private-Package,Ignore-Package,Include-Resource</_removeheaders>
- </instructions>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>rat-maven-plugin</artifactId>
- <configuration>
- <excludeSubProjects>false</excludeSubProjects>
- <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
- <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
- <excludes>
- <param>doc/*</param>
- <param>maven-eclipse.xml</param>
- <param>.checkstyle</param>
- <param>.externalToolBuilders/*</param>
- </excludes>
- </configuration>
- </plugin>
- <plugin>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
+<!-- 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 to
+ you under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of
+ the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
+ by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ OF ANY KIND, either express or implied. See the License for the specific
+ language governing permissions and limitations under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>gogo-parent</artifactId>
+ <version>0.6.0</version>
+ <relativePath>../gogo-parent/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix Gogo Shell</name>
+ <artifactId>org.apache.felix.gogo.shell</artifactId>
+ <version>0.13.0-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ <version>0.16.2</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ </Export-Package>
+ <Import-Package>
+ org.apache.felix.service.command; status="provisional",
+ *
+ </Import-Package>
+ <Private-Package>
+ org.apache.felix.gogo.shell,
+ org.apache.felix.gogo.options
+ </Private-Package>
+ <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Activator>org.apache.felix.gogo.shell.Activator</Bundle-Activator>
+ <Include-Resource>{maven-resources},META-INF/LICENSE=LICENSE,META-INF/NOTICE=NOTICE,META-INF/DEPENDENCIES=DEPENDENCIES</Include-Resource>
+ <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
+ <_removeheaders>Private-Package,Ignore-Package,Include-Resource</_removeheaders>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/gogo/shell/src/main/java/org/apache/felix/gogo/options/Options.java b/gogo/shell/src/main/java/org/apache/felix/gogo/options/Options.java
index 570b067..194c32a 100644
--- a/gogo/shell/src/main/java/org/apache/felix/gogo/options/Options.java
+++ b/gogo/shell/src/main/java/org/apache/felix/gogo/options/Options.java
@@ -32,41 +32,47 @@
/**
* Yet another GNU long options parser. This one is configured by parsing its Usage string.
*/
-public class Options implements Option {
- public static void main(String[] args) {
+public class Options implements Option
+{
+ public static void main(String[] args)
+ {
final String[] usage = {
- "test - test Options usage",
- " text before Usage: is displayed when usage() is called and no error has occurred.",
- " so can be used as a simple help message.",
- "",
- "Usage: testOptions [OPTION]... PATTERN [FILES]...",
- " Output control: arbitary non-option text can be included.",
- " -? --help show help",
- " -c --count=COUNT show COUNT lines",
- " -h --no-filename suppress the prefixing filename on output",
- " -q --quiet, --silent suppress all normal output",
- " --binary-files=TYPE assume that binary files are TYPE",
- " TYPE is 'binary', 'text', or 'without-match'",
- " -I equivalent to --binary-files=without-match",
- " -d --directories=ACTION how to handle directories (default=skip)",
- " ACTION is 'read', 'recurse', or 'skip'",
- " -D --devices=ACTION how to handle devices, FIFOs and sockets",
- " ACTION is 'read' or 'skip'",
- " -R, -r --recursive equivalent to --directories=recurse" };
+ "test - test Options usage",
+ " text before Usage: is displayed when usage() is called and no error has occurred.",
+ " so can be used as a simple help message.",
+ "",
+ "Usage: testOptions [OPTION]... PATTERN [FILES]...",
+ " Output control: arbitary non-option text can be included.",
+ " -? --help show help",
+ " -c --count=COUNT show COUNT lines",
+ " -h --no-filename suppress the prefixing filename on output",
+ " -q --quiet, --silent suppress all normal output",
+ " --binary-files=TYPE assume that binary files are TYPE",
+ " TYPE is 'binary', 'text', or 'without-match'",
+ " -I equivalent to --binary-files=without-match",
+ " -d --directories=ACTION how to handle directories (default=skip)",
+ " ACTION is 'read', 'recurse', or 'skip'",
+ " -D --devices=ACTION how to handle devices, FIFOs and sockets",
+ " ACTION is 'read' or 'skip'",
+ " -R, -r --recursive equivalent to --directories=recurse" };
Option opt = Options.compile(usage).parse(args);
- if (opt.isSet("help")) {
+ if (opt.isSet("help"))
+ {
opt.usage(); // includes text before Usage:
return;
}
- if (opt.args().size() == 0)
+ if (opt.args().isEmpty())
+ {
throw opt.usageError("PATTERN not specified");
-
+ }
System.out.println(opt);
if (opt.isSet("count"))
+ {
System.out.println("count = " + opt.getNumber("count"));
+ }
System.out.println("--directories specified: " + opt.isSet("directories"));
System.out.println("directories=" + opt.get("directories"));
}
@@ -75,10 +81,10 @@
// Note: need to double \ within ""
private static final String regex = "(?x)\\s*" + "(?:-([^-]))?" + // 1: short-opt-1
- "(?:,?\\s*-(\\w))?" + // 2: short-opt-2
- "(?:,?\\s*--(\\w[\\w-]*)(=\\w+)?)?" + // 3: long-opt-1 and 4:arg-1
- "(?:,?\\s*--(\\w[\\w-]*))?" + // 5: long-opt-2
- ".*?(?:\\(default=(.*)\\))?\\s*"; // 6: default
+ "(?:,?\\s*-(\\w))?" + // 2: short-opt-2
+ "(?:,?\\s*--(\\w[\\w-]*)(=\\w+)?)?" + // 3: long-opt-1 and 4:arg-1
+ "(?:,?\\s*--(\\w[\\w-]*))?" + // 5: long-opt-2
+ ".*?(?:\\(default=(.*)\\))?\\s*"; // 6: default
private static final int GROUP_SHORT_OPT_1 = 1;
private static final int GROUP_SHORT_OPT_2 = 2;
@@ -114,75 +120,96 @@
private boolean optionsFirst = false;
private boolean stopOnBadOption = false;
- public static Option compile(String[] optSpec) {
+ public static Option compile(String[] optSpec)
+ {
return new Options(optSpec, null, null);
}
- public static Option compile(String optSpec) {
+ public static Option compile(String optSpec)
+ {
return compile(optSpec.split("\\n"));
}
- public static Option compile(String[] optSpec, Option gopt) {
+ public static Option compile(String[] optSpec, Option gopt)
+ {
return new Options(optSpec, null, gopt);
}
- public static Option compile(String[] optSpec, String[] gspec) {
+ public static Option compile(String[] optSpec, String[] gspec)
+ {
return new Options(optSpec, gspec, null);
}
- public Option setStopOnBadOption(boolean stopOnBadOption) {
+ public Option setStopOnBadOption(boolean stopOnBadOption)
+ {
this.stopOnBadOption = stopOnBadOption;
return this;
}
- public Option setOptionsFirst(boolean optionsFirst) {
+ public Option setOptionsFirst(boolean optionsFirst)
+ {
this.optionsFirst = optionsFirst;
return this;
}
- public boolean isSet(String name) {
+ public boolean isSet(String name)
+ {
if (!optSet.containsKey(name))
+ {
throw new IllegalArgumentException("option not defined in spec: " + name);
-
+ }
return optSet.get(name);
}
- public Object getObject(String name) {
+ public Object getObject(String name)
+ {
if (!optArg.containsKey(name))
+ {
throw new IllegalArgumentException("option not defined with argument: " + name);
-
+ }
List<Object> list = getObjectList(name);
return list.isEmpty() ? "" : list.get(list.size() - 1);
}
@SuppressWarnings("unchecked")
- public List<Object> getObjectList(String name) {
+ public List<Object> getObjectList(String name)
+ {
List<Object> list;
Object arg = optArg.get(name);
- if ( arg == null ) {
+ if (arg == null)
+ {
throw new IllegalArgumentException("option not defined with argument: " + name);
}
-
- if (arg instanceof String) { // default value
+
+ if (arg instanceof String)
+ { // default value
list = new ArrayList<Object>();
if (!"".equals(arg))
+ {
list.add(arg);
+ }
}
- else {
+ else
+ {
list = (List<Object>) arg;
}
return list;
}
- public List<String> getList(String name) {
+ public List<String> getList(String name)
+ {
ArrayList<String> list = new ArrayList<String>();
- for (Object o : getObjectList(name)) {
- try {
+ for (Object o : getObjectList(name))
+ {
+ try
+ {
list.add((String) o);
- } catch (ClassCastException e) {
+ }
+ catch (ClassCastException e)
+ {
throw new IllegalArgumentException("option not String: " + name);
}
}
@@ -190,72 +217,93 @@
}
@SuppressWarnings("unchecked")
- private void addArg(String name, Object value) {
+ private void addArg(String name, Object value)
+ {
List<Object> list;
Object arg = optArg.get(name);
- if (arg instanceof String) { // default value
+ if (arg instanceof String)
+ { // default value
list = new ArrayList<Object>();
optArg.put(name, list);
}
- else {
+ else
+ {
list = (List<Object>) arg;
}
list.add(value);
}
- public String get(String name) {
- try {
+ public String get(String name)
+ {
+ try
+ {
return (String) getObject(name);
- } catch (ClassCastException e) {
+ }
+ catch (ClassCastException e)
+ {
throw new IllegalArgumentException("option not String: " + name);
}
}
- public int getNumber(String name) {
+ public int getNumber(String name)
+ {
String number = get(name);
- try {
+ try
+ {
if (number != null)
+ {
return Integer.parseInt(number);
+ }
return 0;
- } catch (NumberFormatException e) {
+ }
+ catch (NumberFormatException e)
+ {
throw new IllegalArgumentException("option '" + name + "' not Number: " + number);
}
}
- public List<Object> argObjects() {
+ public List<Object> argObjects()
+ {
return xargs;
}
- public List<String> args() {
- if (args == null) {
+ public List<String> args()
+ {
+ if (args == null)
+ {
args = new ArrayList<String>();
- for (Object arg : xargs) {
+ for (Object arg : xargs)
+ {
args.add(arg == null ? "null" : arg.toString());
}
}
return args;
}
- public void usage() {
+ public void usage()
+ {
StringBuilder buf = new StringBuilder();
int index = 0;
- if (error != null) {
+ if (error != null)
+ {
buf.append(error);
buf.append(NL);
index = usageIndex;
}
- for (int i = index; i < spec.length; ++i) {
+ for (int i = index; i < spec.length; ++i)
+ {
buf.append(spec[i]);
buf.append(NL);
}
String msg = buf.toString();
- if (errStream != null) {
+ if (errStream != null)
+ {
errStream.print(msg);
}
}
@@ -263,21 +311,25 @@
/**
* prints usage message and returns IllegalArgumentException, for you to throw.
*/
- public IllegalArgumentException usageError(String s) {
+ public IllegalArgumentException usageError(String s)
+ {
error = usageName + ": " + s;
usage();
return new IllegalArgumentException(error);
}
// internal constructor
- private Options(String[] spec, String[] gspec, Option opt) {
+ private Options(String[] spec, String[] gspec, Option opt)
+ {
this.gspec = gspec;
Options gopt = (Options) opt;
- if (gspec == null && gopt == null) {
+ if (gspec == null && gopt == null)
+ {
this.spec = spec;
}
- else {
+ else
+ {
ArrayList<String> list = new ArrayList<String>();
list.addAll(Arrays.asList(spec));
list.addAll(Arrays.asList(gspec != null ? gspec : gopt.gspec));
@@ -289,15 +341,22 @@
parseSpec(myOptSet, myOptArg);
- if (gopt != null) {
- for (Entry<String, Boolean> e : gopt.optSet.entrySet()) {
+ if (gopt != null)
+ {
+ for (Entry<String, Boolean> e : gopt.optSet.entrySet())
+ {
if (e.getValue())
+ {
myOptSet.put(e.getKey(), true);
+ }
}
- for (Entry<String, Object> e : gopt.optArg.entrySet()) {
- if (!e.getValue().equals(""))
+ for (Entry<String, Object> e : gopt.optArg.entrySet())
+ {
+ if (!"".equals(e.getValue()))
+ {
myOptArg.put(e.getKey(), e.getValue());
+ }
}
gopt.reset();
@@ -313,18 +372,24 @@
/**
* parse option spec.
*/
- private void parseSpec(Map<String, Boolean> myOptSet, Map<String, Object> myOptArg) {
+ private void parseSpec(Map<String, Boolean> myOptSet, Map<String, Object> myOptArg)
+ {
int index = 0;
- for (String line : spec) {
+ for (String line : spec)
+ {
Matcher m = parser.matcher(line);
- if (m.matches()) {
+ if (m.matches())
+ {
final String opt = m.group(GROUP_LONG_OPT_1);
final String name = (opt != null) ? opt : m.group(GROUP_SHORT_OPT_1);
- if (name != null) {
+ if (name != null)
+ {
if (myOptSet.containsKey(name))
+ {
throw new IllegalArgumentException("duplicate option in spec: --" + name);
+ }
myOptSet.put(name, false);
}
@@ -333,26 +398,35 @@
myOptArg.put(opt, dflt);
String opt2 = m.group(GROUP_LONG_OPT_2);
- if (opt2 != null) {
+ if (opt2 != null)
+ {
optAlias.put(opt2, opt);
myOptSet.put(opt2, false);
if (m.group(GROUP_ARG_1) != null)
+ {
myOptArg.put(opt2, "");
+ }
}
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; ++i)
+ {
String sopt = m.group(i == 0 ? GROUP_SHORT_OPT_1 : GROUP_SHORT_OPT_2);
- if (sopt != null) {
+ if (sopt != null)
+ {
if (optName.containsKey(sopt))
+ {
throw new IllegalArgumentException("duplicate option in spec: -" + sopt);
+ }
optName.put(sopt, name);
}
}
}
- if (usageName == UNKNOWN) {
+ if (usageName == UNKNOWN)
+ {
Matcher u = uname.matcher(line);
- if (u.find()) {
+ if (u.find())
+ {
usageName = u.group(1);
usageIndex = index;
}
@@ -362,7 +436,8 @@
}
}
- private void reset() {
+ private void reset()
+ {
optSet.clear();
optSet.putAll(unmodifiableOptSet);
optArg.clear();
@@ -372,32 +447,40 @@
error = null;
}
- public Option parse(Object[] argv) {
+ public Option parse(Object[] argv)
+ {
return parse(argv, false);
}
- public Option parse(List<? extends Object> argv) {
+ public Option parse(List<? extends Object> argv)
+ {
return parse(argv, false);
}
- public Option parse(Object[] argv, boolean skipArg0) {
+ public Option parse(Object[] argv, boolean skipArg0)
+ {
if (null == argv)
+ {
throw new IllegalArgumentException("argv is null");
-
+ }
return parse(Arrays.asList(argv), skipArg0);
}
- public Option parse(List<? extends Object> argv, boolean skipArg0) {
+ public Option parse(List<? extends Object> argv, boolean skipArg0)
+ {
reset();
List<Object> args = new ArrayList<Object>();
args.addAll(Arrays.asList(defArgs));
- for (Object arg : argv) {
- if (skipArg0) {
+ for (Object arg : argv)
+ {
+ if (skipArg0)
+ {
skipArg0 = false;
usageName = arg.toString();
}
- else {
+ else
+ {
args.add(arg);
}
}
@@ -406,89 +489,114 @@
String needOpt = null;
boolean endOpt = false;
- for (Object oarg : args) {
+ for (Object oarg : args)
+ {
String arg = oarg == null ? "null" : oarg.toString();
- if (endOpt) {
+ if (endOpt)
+ {
xargs.add(oarg);
}
- else if (needArg != null) {
+ else if (needArg != null)
+ {
addArg(needArg, oarg);
needArg = null;
needOpt = null;
}
- else if (!arg.startsWith("-") || "-".equals(oarg)) {
+ else if (!arg.startsWith("-") || "-".equals(oarg))
+ {
if (optionsFirst)
+ {
endOpt = true;
+ }
xargs.add(oarg);
}
- else {
+ else
+ {
if (arg.equals("--"))
+ {
endOpt = true;
- else if (arg.startsWith("--")) {
+ }
+ else if (arg.startsWith("--"))
+ {
int eq = arg.indexOf("=");
String value = (eq == -1) ? null : arg.substring(eq + 1);
String name = arg.substring(2, ((eq == -1) ? arg.length() : eq));
List<String> names = new ArrayList<String>();
- if (optSet.containsKey(name)) {
+ if (optSet.containsKey(name))
+ {
names.add(name);
}
- else {
- for (String k : optSet.keySet()) {
+ else
+ {
+ for (String k : optSet.keySet())
+ {
if (k.startsWith(name))
names.add(k);
}
}
- switch (names.size()) {
- case 1:
- name = names.get(0);
- optSet.put(name, true);
- if (optArg.containsKey(name)) {
- if (value != null)
- addArg(name, value);
- else
- needArg = name;
- }
- else if (value != null) {
- throw usageError("option '--" + name + "' doesn't allow an argument");
- }
- break;
-
- case 0:
- if (stopOnBadOption) {
- endOpt = true;
- xargs.add(oarg);
+ switch (names.size())
+ {
+ case 1:
+ name = names.get(0);
+ optSet.put(name, true);
+ if (optArg.containsKey(name))
+ {
+ if (value != null)
+ addArg(name, value);
+ else
+ needArg = name;
+ }
+ else if (value != null)
+ {
+ throw usageError("option '--" + name + "' doesn't allow an argument");
+ }
break;
- }
- else
- throw usageError("invalid option '--" + name + "'");
- default:
- throw usageError("option '--" + name + "' is ambiguous: " + names);
+ case 0:
+ if (stopOnBadOption)
+ {
+ endOpt = true;
+ xargs.add(oarg);
+ break;
+ }
+ else
+ throw usageError("invalid option '--" + name + "'");
+
+ default:
+ throw usageError("option '--" + name + "' is ambiguous: " + names);
}
}
- else {
- for (int i = 1; i < arg.length(); i++) {
+ else
+ {
+ for (int i = 1; i < arg.length(); i++)
+ {
String c = String.valueOf(arg.charAt(i));
- if (optName.containsKey(c)) {
+ if (optName.containsKey(c))
+ {
String name = optName.get(c);
optSet.put(name, true);
- if (optArg.containsKey(name)) {
+ if (optArg.containsKey(name))
+ {
int k = i + 1;
- if (k < arg.length()) {
+ if (k < arg.length())
+ {
addArg(name, arg.substring(k));
}
- else {
+ else
+ {
needOpt = c;
needArg = name;
}
break;
}
}
- else {
- if (stopOnBadOption) {
+ else
+ {
+ if (stopOnBadOption)
+ {
xargs.add("-" + c);
endOpt = true;
}
@@ -500,14 +608,17 @@
}
}
- if (needArg != null) {
+ if (needArg != null)
+ {
String name = (needOpt != null) ? needOpt : "--" + needArg;
throw usageError("option '" + name + "' requires an argument");
}
// remove long option aliases
- for (Entry<String, String> alias : optAlias.entrySet()) {
- if (optSet.get(alias.getKey())) {
+ for (Entry<String, String> alias : optAlias.entrySet())
+ {
+ if (optSet.get(alias.getKey()))
+ {
optSet.put(alias.getValue(), true);
if (optArg.containsKey(alias.getKey()))
optArg.put(alias.getValue(), optArg.get(alias.getKey()));
@@ -520,7 +631,8 @@
}
@Override
- public String toString() {
+ public String toString()
+ {
return "isSet" + optSet + "\nArg" + optArg + "\nargs" + xargs;
}
diff --git a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java
index 666dfc1..153e7e2 100644
--- a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java
+++ b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Activator.java
@@ -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 @@
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 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 @@
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 @@
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 @@
{
private final BundleContext context;
private final CommandProcessor processor;
+ private volatile CommandSession session;
public StartShellJob(BundleContext context, CommandProcessor processor)
{
@@ -165,7 +191,7 @@
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 @@
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 @@
}
finally
{
- session.close();
+ terminate();
}
}
+
+ public void terminate()
+ {
+ if (session != null)
+ {
+ session.close();
+ session = null;
+ }
+ Thread.currentThread().interrupt();
+ }
}
}
\ No newline at end of file
diff --git a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java
index ee21598..efba820 100644
--- a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java
+++ b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Console.java
@@ -32,7 +32,7 @@
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 @@
{
try
{
- while (!quit)
+ while (!Thread.currentThread().isInterrupted() && !quit)
{
CharSequence line = getLine(getPrompt());
@@ -95,8 +95,7 @@
loc = "gogo";
}
- out.println(loc + ": " + e.getClass().getSimpleName() + ": "
- + e.getMessage());
+ out.println(loc + ": " + e.getClass().getSimpleName() + ": " + e.getMessage());
}
}
finally
@@ -146,7 +145,20 @@
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)
{
diff --git a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java
index b76440a..ad189cb 100644
--- a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java
+++ b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Converters.java
@@ -24,19 +24,19 @@
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 @@
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 @@
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)
diff --git a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java
index 895b577..a2c6602 100644
--- a/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java
+++ b/gogo/shell/src/main/java/org/apache/felix/gogo/shell/Shell.java
@@ -35,6 +35,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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()]);