Initial commit of OSGi Shell contribution. (FELIX-946)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@783826 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/src/aQute/shell/osgi/OSGiCommands.java b/gogo/src/aQute/shell/osgi/OSGiCommands.java
new file mode 100644
index 0000000..f715a89
--- /dev/null
+++ b/gogo/src/aQute/shell/osgi/OSGiCommands.java
@@ -0,0 +1,302 @@
+/*
+ * 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 aQute.shell.osgi;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import org.osgi.framework.*;
+import org.osgi.service.command.*;
+
+public class OSGiCommands implements Converter {
+ Bundle bundle;
+ String COLUMN = "%40s %s\n";
+
+ protected OSGiCommands(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+// Bundle[] getBundles() {
+// return getContext().getBundles();
+// }
+
+ public BundleContext getContext() {
+ if ( bundle.getState() != Bundle.ACTIVE )
+ throw new IllegalStateException("Framework is not started yet");
+ return bundle.getBundleContext();
+ }
+
+ CharSequence print(Bundle bundle) {
+ String version = (String) bundle.getHeaders().get("Bundle-Version");
+ if ( version == null )
+ version = "0.0.0";
+ return String.format("%06d %s %s-%s", bundle.getBundleId(),
+ getState(bundle), bundle.getSymbolicName(), version);
+ }
+
+ CharSequence print(ServiceReference ref) {
+ StringBuilder sb = new StringBuilder();
+ Formatter f = new Formatter(sb);
+
+ String spid = "";
+ Object pid = ref.getProperty("service.pid");
+ if (pid != null) {
+ spid = pid.toString();
+ }
+
+ f.format("%06d %3s %-40s %s", ref.getProperty("service.id"), ref
+ .getBundle().getBundleId(), getShortNames((String[]) ref
+ .getProperty("objectclass")), spid);
+ return sb;
+ }
+
+ CharSequence getShortNames(String[] list) {
+ StringBuilder sb = new StringBuilder();
+ String del = "";
+ for (String s : list) {
+ sb.append(del + getShortName(s));
+ del = " | ";
+ }
+ return sb;
+ }
+
+ CharSequence getShortName(String name) {
+ int n = name.lastIndexOf('.');
+ if (n < 0)
+ n = 0;
+ else
+ n++;
+ return name.subSequence(n, name.length());
+ }
+
+ private String getState(Bundle bundle) {
+ switch (bundle.getState()) {
+ case Bundle.ACTIVE:
+ return "ACT";
+
+ case Bundle.INSTALLED:
+ return "INS";
+
+ case Bundle.RESOLVED:
+ return "RES";
+
+ case Bundle.STARTING:
+ return "STA";
+
+ case Bundle.STOPPING:
+ return "STO";
+
+ case Bundle.UNINSTALLED:
+ return "UNI ";
+ }
+ return null;
+ }
+
+ public void grep(String match) throws IOException {
+ Pattern p = Pattern.compile(match);
+ BufferedReader rdr = new BufferedReader(
+ new InputStreamReader(System.in));
+ String s = rdr.readLine();
+ while (s != null) {
+ if (p.matcher(s).find()) {
+ System.out.println(s);
+ }
+ s = rdr.readLine();
+ }
+ }
+
+ public String tac() throws IOException {
+ StringWriter sw = new StringWriter();
+ BufferedReader rdr = new BufferedReader(
+ new InputStreamReader(System.in));
+ String s = rdr.readLine();
+ while (s != null) {
+ sw.write(s);
+ s = rdr.readLine();
+ }
+ return sw.toString();
+ }
+
+ public CharSequence echo(CommandSession session, Object args[]) {
+ StringBuilder sb = new StringBuilder();
+ String del = "";
+ for (Object arg : args) {
+ sb.append(del);
+ if (arg != null) {
+ sb.append(arg);
+ del = " ";
+ }
+ }
+ return sb;
+ }
+
+ public void each(CommandSession session, Collection<Object> list, Function closure) throws Exception {
+ List<Object> args = new ArrayList<Object>();
+ 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));
+ }
+ }
+
+ public Bundle bundle(Bundle i) {
+ return i;
+ }
+
+ public String[] ls(CommandSession session, File f) throws Exception{
+ File cwd = (File) session.get("_cwd");
+ if (cwd == null)
+ cwd = new File("").getAbsoluteFile();
+
+ if ( f == null )
+ f = cwd;
+ else if (!f.isAbsolute())
+ f = new File(cwd, f.getPath());
+
+ if ( f.isDirectory() )
+ return f.list();
+
+ if ( f.isFile() ) {
+ cat(session,f);
+ }
+
+ return null;
+ }
+
+ public Object cat(CommandSession session, File f ) throws Exception {
+ File cwd = (File) session.get("_cwd");
+ if (cwd == null)
+ cwd = new File("").getAbsoluteFile();
+
+ if ( !f.isAbsolute() )
+ f = new File(cwd,f.getPath());
+
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ FileInputStream in = new FileInputStream(f);
+ byte [] buffer = new byte[ (int) (f.length() % 100000) ];
+ int size = in.read(buffer);
+ while ( size > 0 ) {
+ bout.write(buffer,0,size);
+ size = in.read(buffer);
+ }
+ return new String(bout.toByteArray());
+ }
+ public Object convert(Class<?> desiredType, Object in) throws Exception {
+ if (desiredType == Bundle.class)
+ return convertBundle(in);
+ else if (desiredType == ServiceReference.class)
+ return convertServiceReference(in);
+ else if (desiredType == Class.class)
+ return Class.forName(in.toString());
+ else if (desiredType.isAssignableFrom(String.class) && in instanceof InputStream)
+ return read(((InputStream) in));
+
+ return null;
+ }
+
+ private Object convertServiceReference(Object in)
+ throws InvalidSyntaxException {
+ String s = in.toString();
+ if (s.startsWith("(") && s.endsWith(")")) {
+ ServiceReference refs[] = getContext().getServiceReferences(null, String
+ .format("(|(service.id=%s)(service.pid=%s))", in, in));
+ if (refs != null && refs.length > 0)
+ return refs[0];
+ }
+
+ ServiceReference refs[] = getContext().getServiceReferences(null, String
+ .format("(|(service.id=%s)(service.pid=%s))", in, in));
+ if (refs != null && refs.length > 0)
+ return refs[0];
+ return null;
+ }
+
+ private Object convertBundle(Object in) {
+ String s = in.toString();
+ try {
+ long id = Long.parseLong(s);
+ return getContext().getBundle(id);
+ } catch (NumberFormatException nfe) {
+ // Ignore
+ }
+
+ Bundle bundles[] = getContext().getBundles();
+ for (Bundle b : bundles) {
+ if (b.getLocation().equals(s))
+ return b;
+
+ if (b.getSymbolicName().equals(s))
+ return b;
+ }
+
+ return null;
+ }
+
+ public CharSequence format(Object target, int level, Converter converter ) throws IOException {
+ if ( level == INSPECT && target instanceof InputStream ) {
+ return read(((InputStream)target));
+ }
+ if (level == LINE && target instanceof Bundle)
+ return print((Bundle) target);
+ if (level == LINE && target instanceof ServiceReference)
+ return print((ServiceReference) target);
+ if (level == PART && target instanceof Bundle)
+ return ((Bundle) target).getSymbolicName();
+ if (level == PART && target instanceof ServiceReference)
+ return getShortNames((String[]) ((ServiceReference) target)
+ .getProperty("objectclass"));
+ return null;
+ }
+
+ public CharSequence read(InputStream in) throws IOException {
+ int c;
+ StringBuffer sb = new StringBuffer();
+ while ( (c=in.read())> 0 ) {
+ if ( c >=32 && c <= 0x7F || c=='\n' || c=='\r') {
+ sb.append( (char) c);
+ } else {
+ String s = Integer.toHexString(c).toUpperCase();
+ sb.append("\\");
+ if ( s.length() < 1)
+ sb.append(0);
+ sb.append(s);
+ }
+ }
+ return sb;
+ }
+
+ public void start(Bundle b) throws BundleException {
+ b.start();
+ }
+
+ public void stop(Bundle b) throws BundleException {
+ b.stop();
+ }
+
+ public Object service(String clazz, String filter) throws InvalidSyntaxException {
+ ServiceReference ref[] = getContext().getServiceReferences(clazz,filter);
+ if (ref == null )
+ return null;
+
+ return getContext().getService(ref[0]);
+ }
+
+}
diff --git a/gogo/src/aQute/shell/osgi/OSGiShell.java b/gogo/src/aQute/shell/osgi/OSGiShell.java
new file mode 100644
index 0000000..3b35496
--- /dev/null
+++ b/gogo/src/aQute/shell/osgi/OSGiShell.java
@@ -0,0 +1,111 @@
+/*
+ * 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 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.*;
+
+public class OSGiShell extends CommandShellImpl {
+ Bundle bundle;
+ OSGiCommands commands;
+
+ protected void activate(ComponentContext context) throws Exception {
+ this.bundle = context.getBundleContext().getBundle();
+ if (threadIO == null)
+ threadIO = (ThreadIO) context.locateService("x");
+ start();
+ }
+
+ public void start() throws Exception {
+ commands = new OSGiCommands(bundle);
+ addCommand("osgi", this.bundle);
+ 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);
+ }
+ }
+
+ protected void deactivate(ComponentContext context) {
+ System.out.println("Deactivating");
+ }
+
+ public Object get(String name) {
+ if (bundle.getBundleContext() != null) {
+ BundleContext context = bundle.getBundleContext();
+ try {
+ Object cmd = super.get(name);
+ if (cmd != null)
+ return cmd;
+
+ int n = name.indexOf(':');
+ if (n < 0)
+ return null;
+
+ String service = name.substring(0, n);
+ String function = name.substring(n + 1);
+
+ String filter = String.format(
+ "(&(osgi.command.scope=%s)(osgi.command.function=%s))",
+ service, function);
+ ServiceReference refs[] = context.getServiceReferences(null,
+ filter);
+ if (refs == null || refs.length == 0)
+ return null;
+
+ if (refs.length > 1)
+ throw new IllegalArgumentException(
+ "Command name is not unambiguous: " + name
+ + ", found multiple impls");
+
+ return new ServiceCommand(this, refs[0], function);
+ } catch (InvalidSyntaxException ise) {
+ ise.printStackTrace();
+ }
+ }
+ return super.get(name);
+ }
+
+ public void setThreadio(Object t) {
+ super.setThreadio((ThreadIO) t);
+ }
+
+ public void setBundle(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ public void setConverter(Converter c) {
+ super.setConverter(c);
+ }
+
+}
diff --git a/gogo/src/aQute/shell/osgi/ServiceCommand.java b/gogo/src/aQute/shell/osgi/ServiceCommand.java
new file mode 100644
index 0000000..61d4087
--- /dev/null
+++ b/gogo/src/aQute/shell/osgi/ServiceCommand.java
@@ -0,0 +1,51 @@
+/*
+ * 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 aQute.shell.osgi;
+
+import java.util.*;
+
+import org.osgi.framework.*;
+import org.osgi.service.command.*;
+
+import aQute.shell.runtime.*;
+
+public class ServiceCommand extends Reflective implements Function {
+ ServiceReference ref;
+ OSGiShell shell;
+ String name;
+
+ public ServiceCommand(OSGiShell shell, ServiceReference ref, String name) {
+ this.shell =shell;
+ this.ref = ref;
+ this.name = name;
+ }
+
+ public Object execute(CommandSession session, List<Object> arguments) throws Exception {
+ try {
+ Object target = shell.bundle.getBundleContext().getService(ref);
+ Object result = method(session,target, name, arguments);
+ if ( result != CommandShellImpl.NO_SUCH_COMMAND )
+ return result;
+
+ throw new IllegalArgumentException("Service does not implement promised command " + ref + " " + name );
+ } finally {
+ shell.bundle.getBundleContext().ungetService(ref);
+ }
+ }
+}