add trivial socket based control layer for framework launcher
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@805542 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/common/runtime/.classpath b/sigil/common/runtime/.classpath
index ef51f6b..c9ffd60 100644
--- a/sigil/common/runtime/.classpath
+++ b/sigil/common/runtime/.classpath
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/Java 1.6.0"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.apache.felix.sigil.classpathContainer"/>
<classpathentry kind="output" path="build/classes"/>
</classpath>
diff --git a/sigil/common/runtime/build.xml b/sigil/common/runtime/build.xml
new file mode 100644
index 0000000..aaf48be
--- /dev/null
+++ b/sigil/common/runtime/build.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+ 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 name="common.runtime" default="build">
+ <import file="../build.xml"/>
+</project>
diff --git a/sigil/common/runtime/ivy.xml b/sigil/common/runtime/ivy.xml
new file mode 100644
index 0000000..0a697df
--- /dev/null
+++ b/sigil/common/runtime/ivy.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<ivy-module version="1.0">
+ <info
+ organisation="org.apache"
+ module="felix.sigil.common.runtime"
+ status="integration"/>
+ <publications>
+ <artifact name="org.apache.felix.sigil.common.runtime" />
+ </publications>
+</ivy-module>
diff --git a/sigil/common/runtime/sigil.properties b/sigil/common/runtime/sigil.properties
index 2488647..79def6a 100644
--- a/sigil/common/runtime/sigil.properties
+++ b/sigil/common/runtime/sigil.properties
@@ -4,12 +4,20 @@
-bundles: \
org.apache.felix.sigil.common.runtime, \
--sourcedirs: \
- src, \
+-contents: \
+ org.apache.felix.sigil.common.runtime.*, \
+ org.apache.commons.cli.*, \
+ org.apache.commons.io.*, \
+
+-exports: \
+ org.apache.felix.sigil.common.runtime, \
-imports: \
- org.apache.commons.cli;version=1.2.0, \
- org.osgi.framework, \
- org.osgi.framework.launch;version=1.0.0, \
+ org.apache.commons.cli;version=1.2.0;resolve=compile, \
+ org.apache.commons.io.input;version=1.4.0;resolve=compile, \
+ org.osgi.framework;resolve=compile, \
+ org.osgi.framework.launch;version=1.0.0;resolve=compile, \
+
+header;Main-Class: org.apache.felix.sigil.common.runtime.Main
# end
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Client.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Client.java
new file mode 100644
index 0000000..61dabd2
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Client.java
@@ -0,0 +1,118 @@
+/*
+ * 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.sigil.common.runtime;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.felix.sigil.common.runtime.io.InstallAction;
+import org.apache.felix.sigil.common.runtime.io.StartAction;
+import org.apache.felix.sigil.common.runtime.io.StatusAction;
+import org.apache.felix.sigil.common.runtime.io.StopAction;
+import org.apache.felix.sigil.common.runtime.io.UninstallAction;
+import org.apache.felix.sigil.common.runtime.io.UpdateAction;
+import org.apache.felix.sigil.common.runtime.io.UpdateAction.Update;
+import org.osgi.framework.BundleException;
+
+
+/**
+ * @author dave
+ *
+ */
+public class Client
+{
+ public static final String PORT_PROPERTY = "port";
+ public static final String ADDRESS_PROPERTY = "address";
+
+ private Socket socket;
+ private InputStream in;
+ private OutputStream out;
+
+
+ public Client()
+ {
+ }
+
+
+ public void connect(Properties props) throws IOException
+ {
+ InetAddress address = InetAddress.getByName( props.getProperty( ADDRESS_PROPERTY ) );
+ int port = Integer.parseInt( props.getProperty( PORT_PROPERTY, "0" ) );
+ socket = new Socket( address, port );
+ in = socket.getInputStream();
+ out = socket.getOutputStream();
+ }
+
+
+ public void close() throws IOException
+ {
+ socket.close();
+ }
+
+
+ public long install( String url ) throws IOException, BundleException
+ {
+ return new InstallAction( in, out ).client( url );
+ }
+
+
+ public void start( long bundle ) throws IOException, BundleException
+ {
+ new StartAction( in, out ).client();
+ }
+
+
+ public void stop( long bundle ) throws IOException, BundleException
+ {
+ new StopAction( in, out ).client();
+ }
+
+
+ public void uninstall( long bundle ) throws IOException, BundleException
+ {
+ new UninstallAction( in, out ).client();
+ }
+
+
+ public void update( long bundle ) throws IOException, BundleException
+ {
+ Update update = new UpdateAction.Update(bundle, null);
+ new UpdateAction( in, out ).client(update);
+ }
+
+
+ public void update( long bundle, String url ) throws IOException, BundleException
+ {
+ Update update = new UpdateAction.Update(bundle, url);
+ new UpdateAction( in, out ).client(update);
+ }
+
+
+ public Map<Long, String> status() throws IOException, BundleException
+ {
+ return new StatusAction( in, out ).client();
+ }
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Main.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Main.java
index c7ddab3..7409371 100644
--- a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Main.java
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Main.java
@@ -1,10 +1,14 @@
package org.apache.felix.sigil.common.runtime;
-import java.io.File;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
-import java.util.ServiceLoader;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
@@ -16,69 +20,133 @@
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
+
public class Main
{
private static final String COMMAND_LINE_SYNTAX = "java -jar org.apache.felix.sigil.common.runtime";
-
+
private static Framework framework;
private static final Options options;
-
- static {
+
+ static
+ {
options = new Options();
options.addOption( "?", "help", false, "Print help for the Sigil launcher" );
+ options.addOption( "p", "port", true, "Port to launch server on (0 implies auto allocate) [default 0]" );
+ options.addOption( "a", "address", true, "Address to bind server to [default all]");
}
- public static void main( String[] args )
+
+ public static void main( String[] args ) throws Exception
{
- try {
+ FrameworkFactory factory = getFrameworkFactory();
+
+ try
+ {
Parser parser = new PosixParser();
CommandLine cl = parser.parse( options, args );
-
- if ( cl.hasOption( '?' ) ) {
+
+ if ( cl.hasOption( '?' ) )
+ {
printHelp();
}
- else {
- ServiceLoader<FrameworkFactory> loader = ServiceLoader.load( FrameworkFactory.class );
- FrameworkFactory factory = loader.iterator().next();
-
+ else
+ {
Map<String, String> config = buildConfig( cl );
-
+
framework = factory.newFramework( config );
framework.init();
-
- launch( args );
-
+
+ Server server = launch( cl );
+
framework.waitForStop( 0 );
+
+ if ( server != null )
+ {
+ server.stop();
+ }
}
}
- catch (NoSuchElementException e) {
+ catch ( NoSuchElementException e )
+ {
System.err.println( "No " + FrameworkFactory.class.getName() + " found on classpath" );
System.exit( 1 );
}
+ catch ( InterruptedException e )
+ {
+ System.err.println( "Interrupted prior to framework stop" );
+ System.exit( 1 );
+ }
+ catch ( ParseException e )
+ {
+ printHelp();
+ System.exit( 1 );
+ }
catch ( BundleException e )
{
e.printStackTrace();
+ System.exit( 1 );
}
- catch ( InterruptedException e )
+ catch ( IOException e )
{
- System.err.println( "Interrupted prior to framework stop" );
- }
- catch ( ParseException e )
- {
- printHelp();
+ e.printStackTrace();
+ System.exit( 1 );
}
}
+ /**
+ * Simple method to parse META-INF/services file for framework factory.
+ * Currently, it assumes the first non-commented line is the class name
+ * of the framework factory implementation.
+ * @return The created <tt>FrameworkFactory</tt> instance.
+ * @throws Exception if any errors occur.
+ **/
+ private static FrameworkFactory getFrameworkFactory() throws Exception
+ {
+ URL url = Main.class.getClassLoader().getResource(
+ "META-INF/services/org.osgi.framework.launch.FrameworkFactory");
+ if (url != null)
+ {
+ BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
+ try
+ {
+ for (String s = br.readLine(); s != null; s = br.readLine())
+ {
+ s = s.trim();
+ // Try to load first non-empty, non-commented line.
+ if ((s.length() > 0) && (s.charAt(0) != '#'))
+ {
+ return (FrameworkFactory) Class.forName(s).newInstance();
+ }
+ }
+ }
+ finally
+ {
+ if (br != null) br.close();
+ }
+ }
+
+ throw new Exception("Could not find framework factory.");
+ }
+
private static Map<String, String> buildConfig( CommandLine cl )
{
HashMap<String, String> config = new HashMap<String, String>();
return config;
}
- private static void launch( String[] args ) throws ParseException
+
+ private static Server launch( CommandLine line ) throws IOException
{
+ Server server = new Server( framework );
+ String v = line.getOptionValue('a');
+ InetAddress addr = v == null ? null : InetAddress.getByName( v );
+ int port = Integer.parseInt( line.getOptionValue( 'p', "0" ) );
+ server.start( addr, port );
+ return server;
}
-
+
+
private static void printHelp()
{
HelpFormatter f = new HelpFormatter();
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Server.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Server.java
new file mode 100644
index 0000000..04724ef
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Server.java
@@ -0,0 +1,162 @@
+/*
+ * 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.sigil.common.runtime;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.felix.sigil.common.runtime.io.Action;
+import org.apache.felix.sigil.common.runtime.io.InstallAction;
+import org.apache.felix.sigil.common.runtime.io.StartAction;
+import org.apache.felix.sigil.common.runtime.io.StatusAction;
+import org.apache.felix.sigil.common.runtime.io.StopAction;
+import org.apache.felix.sigil.common.runtime.io.UninstallAction;
+import org.apache.felix.sigil.common.runtime.io.UpdateAction;
+import org.osgi.framework.launch.Framework;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.*;
+
+
+/**
+ * @author dave
+ *
+ */
+public class Server
+{
+ private final Framework fw;
+ private Thread accept;
+ private ExecutorService read = Executors.newCachedThreadPool();
+
+ private AtomicBoolean stopped = new AtomicBoolean();
+
+
+ public Server( Framework fw )
+ {
+ this.fw = fw;
+ }
+
+
+ public void start( InetAddress inetAddress, int port ) throws IOException
+ {
+ final ServerSocket socket = new ServerSocket();
+ InetSocketAddress socketAddress = new InetSocketAddress(inetAddress, port);
+
+ socket.bind( socketAddress );
+
+ System.out.println( "Started server listening on " + socket.getLocalSocketAddress() + ":" + socket.getLocalPort() );
+
+ accept = new Thread( new Runnable()
+ {
+ public void run()
+ {
+ while ( !stopped.get() )
+ {
+ try
+ {
+ read.execute( new Reader( socket.accept() ) );
+ }
+ catch ( IOException e )
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ } );
+ }
+
+
+ public void stop()
+ {
+ stopped.set( true );
+ accept.interrupt();
+ accept = null;
+ }
+
+ public class Reader implements Runnable
+ {
+
+ private final Socket socket;
+
+
+ /**
+ * @param accept
+ */
+ public Reader( Socket socket )
+ {
+ this.socket = socket;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run()
+ {
+ try
+ {
+ InputStream in = socket.getInputStream();
+ OutputStream out = socket.getOutputStream();
+ while ( !stopped.get() )
+ {
+ int action = in.read();
+ Action<?, ?> task = null;
+ switch ( action )
+ {
+ case INSTALL:
+ task = new InstallAction( in, out );
+ break;
+ case START:
+ task = new StartAction( in, out );
+ break;
+ case STOP:
+ task = new StopAction( in, out );
+ break;
+ case UNINSTALL:
+ task = new UninstallAction( in, out );
+ break;
+ case UPDATE:
+ task = new UpdateAction( in, out );
+ break;
+ case STATUS:
+ task = new StatusAction( in, out );
+ break;
+ }
+ task.server( fw );
+ }
+ }
+ catch ( IOException e )
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/Action.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/Action.java
new file mode 100644
index 0000000..0e6ceb5
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/Action.java
@@ -0,0 +1,200 @@
+/*
+ * 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.sigil.common.runtime.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+
+import org.apache.commons.io.input.CountingInputStream;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.OK;
+import static org.apache.felix.sigil.common.runtime.io.Constants.ERROR;
+
+
+/**
+ * @author dave
+ *
+ */
+public abstract class Action<I, O>
+{
+ private final ObjectInputStream in;
+ private final ObjectOutputStream out;
+
+
+ public Action( InputStream in, OutputStream out ) throws IOException
+ {
+ this.in = new ObjectInputStream( in );
+ this.out = new ObjectOutputStream( out );
+ }
+
+
+ public O client() throws IOException, BundleException
+ {
+ return client( null );
+ }
+
+
+ public abstract O client( I input ) throws IOException, BundleException;
+
+
+ public abstract void server( Framework fw ) throws IOException;
+
+
+ protected boolean checkOk() throws IOException
+ {
+ int ch = readInt();
+ switch ( ch )
+ {
+ case OK:
+ return true;
+ case ERROR:
+ return false;
+ default:
+ throw new IOException( "Unexpected return code " + ch );
+ }
+ }
+
+
+ protected void writeOk() throws IOException
+ {
+ writeInt( OK );
+ }
+
+
+ protected void writeError() throws IOException
+ {
+ writeInt( ERROR );
+ }
+
+
+ protected String readString() throws IOException
+ {
+ return in.readUTF();
+ }
+
+
+ protected void writeString( String str ) throws IOException
+ {
+ out.writeUTF( str );
+ }
+
+
+ protected void writeInt( int i ) throws IOException
+ {
+ out.writeInt( i );
+ }
+
+
+ protected int readInt() throws IOException
+ {
+ return in.readInt();
+ }
+
+
+ protected void writeLong( long l ) throws IOException
+ {
+ out.writeLong( l );
+ }
+
+
+ protected long readLong() throws IOException
+ {
+ return in.readLong();
+ }
+
+ protected void writeBoolean( boolean b ) throws IOException
+ {
+ out.writeBoolean( b );
+ }
+
+ protected boolean readBoolean() throws IOException {
+ return in.readBoolean();
+ }
+
+ protected void writeStream( String location ) throws IOException {
+ URL url = new URL( location );
+ URLConnection conn = url.openConnection();
+ conn.connect();
+
+ int l = conn.getContentLength();
+ writeInt( l );
+ InputStream uin = conn.getInputStream();
+ byte[] buf = new byte[1024*1024];
+ for (;;) {
+ int r = uin.read( buf );
+ if ( r == -1 ) break;
+ out.write( buf, 0, r );
+ }
+ }
+
+ protected InputStream readStream() throws IOException {
+ final int length = readInt();
+ return new CountingInputStream(in) {
+ @Override
+ public int read() throws IOException
+ {
+ if ( getCount() < length )
+ return super.read();
+ else
+ return -1;
+ }
+
+ @Override
+ public int read( byte[] b, int off, int len ) throws IOException
+ {
+ len = (getCount() + len) > length ? (length - getCount()) : len;
+ if ( len == 0 )
+ return -1;
+ else
+ return super.read( b, off, len );
+ }
+
+ @Override
+ public int read( byte[] b ) throws IOException
+ {
+ return read( b, 0, b.length );
+ }
+
+ @Override
+ public long skip( long len ) throws IOException
+ {
+ len = (getCount() + len) > length ? (length - getCount()) : len;
+ if ( len == 0 )
+ return -1;
+ else
+ return super.skip( len );
+ }
+ };
+ }
+
+ protected void flush() throws IOException
+ {
+ out.flush();
+ }
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/Constants.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/Constants.java
new file mode 100644
index 0000000..58a614d
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/Constants.java
@@ -0,0 +1,34 @@
+/*
+ * 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.sigil.common.runtime.io;
+
+
+public interface Constants
+{
+ public static final int OK = 0;
+ public static final int ERROR = -1;
+
+ public static final int INSTALL = 1;
+ public static final int START = 2;
+ public static final int STOP = 4;
+ public static final int UNINSTALL = 8;
+ public static final int UPDATE = 16;
+ public static final int STATUS = 32;
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/InstallAction.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/InstallAction.java
new file mode 100644
index 0000000..fd43a20
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/InstallAction.java
@@ -0,0 +1,82 @@
+/*
+ * 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.sigil.common.runtime.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.INSTALL;
+
+
+/**
+ * @author dave
+ *
+ */
+public class InstallAction extends Action<String, Long>
+{
+
+ public InstallAction( InputStream in, OutputStream out ) throws IOException
+ {
+ super( in, out );
+ }
+
+
+ @Override
+ public Long client( String url ) throws IOException, BundleException
+ {
+ writeInt( INSTALL );
+ writeString( url );
+ if ( checkOk() )
+ {
+ return readLong();
+ }
+ else
+ {
+ String msg = readString();
+ throw new BundleException( msg );
+ }
+ }
+
+
+ @Override
+ public void server( Framework fw ) throws IOException
+ {
+ String url = readString();
+ try
+ {
+ Bundle val = fw.getBundleContext().installBundle( url );
+ writeOk();
+ writeLong( val.getBundleId() );
+ }
+ catch ( BundleException e )
+ {
+ writeError();
+ writeString( e.getMessage() );
+ }
+
+ }
+
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StartAction.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StartAction.java
new file mode 100644
index 0000000..3590223
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StartAction.java
@@ -0,0 +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.
+ */
+
+package org.apache.felix.sigil.common.runtime.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.START;
+
+
+/**
+ * @author dave
+ *
+ */
+public class StartAction extends Action<Long, Void>
+{
+
+ public StartAction( InputStream in, OutputStream out ) throws IOException
+ {
+ super( in, out );
+ }
+
+
+ @Override
+ public Void client( Long bundle ) throws IOException, BundleException
+ {
+ writeInt( START );
+ writeLong( bundle );
+ if ( !checkOk() )
+ {
+ String msg = readString();
+ throw new BundleException( msg );
+ }
+ return null;
+ }
+
+
+ @Override
+ public void server( Framework fw ) throws IOException
+ {
+ long id = readLong();
+ Bundle b = fw.getBundleContext().getBundle( id );
+ if ( b == null )
+ {
+ writeError();
+ writeString( "Unknown bundle " + id );
+ }
+ else
+ {
+ try
+ {
+ b.start();
+ writeOk();
+ }
+ catch ( BundleException e )
+ {
+ writeError();
+ writeString( e.getMessage() );
+ }
+ }
+ }
+
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StatusAction.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StatusAction.java
new file mode 100644
index 0000000..f5379d1
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StatusAction.java
@@ -0,0 +1,78 @@
+/*
+ * 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.sigil.common.runtime.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.launch.Framework;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.STATUS;
+import static org.osgi.framework.Constants.BUNDLE_VERSION;
+
+
+/**
+ * @author dave
+ *
+ */
+public class StatusAction extends Action<Void, Map<Long, String>>
+{
+
+ public StatusAction( InputStream in, OutputStream out ) throws IOException
+ {
+ super( in, out );
+ }
+
+
+ @Override
+ public Map<Long, String> client( Void in ) throws IOException
+ {
+ writeInt(STATUS);
+ int num = readInt();
+ HashMap<Long, String> map = new HashMap<Long, String>(num);
+
+ for (int i = 0; i < num; i++) {
+ long id = readLong();
+ String symbol = readString();
+ map.put( id, symbol );
+ }
+
+ return map;
+ }
+
+
+ @Override
+ public void server( Framework fw ) throws IOException
+ {
+ Bundle[] bundles = fw.getBundleContext().getBundles();
+ writeInt( bundles.length );
+ for ( Bundle b : bundles ) {
+ writeLong(b.getBundleId());
+ String symbol = b.getSymbolicName() + ":" + b.getHeaders().get( BUNDLE_VERSION );
+ writeString(symbol);
+ }
+ }
+
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StopAction.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StopAction.java
new file mode 100644
index 0000000..4735eb7
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/StopAction.java
@@ -0,0 +1,85 @@
+/*
+ * 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.sigil.common.runtime.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.STOP;
+
+
+/**
+ * @author dave
+ *
+ */
+public class StopAction extends Action<Long, Void>
+{
+
+ public StopAction( InputStream in, OutputStream out ) throws IOException
+ {
+ super( in, out );
+ }
+
+
+ @Override
+ public Void client( Long bundle ) throws IOException, BundleException
+ {
+ writeInt( STOP );
+ writeLong( bundle );
+ if ( !checkOk() )
+ {
+ String msg = readString();
+ throw new BundleException( msg );
+ }
+ return null;
+ }
+
+
+ @Override
+ public void server( Framework fw ) throws IOException
+ {
+ long id = readLong();
+ Bundle b = fw.getBundleContext().getBundle( id );
+ if ( b == null )
+ {
+ writeError();
+ writeString( "Unknown bundle " + id );
+ }
+ else
+ {
+ try
+ {
+ b.stop();
+ writeOk();
+ }
+ catch ( BundleException e )
+ {
+ writeError();
+ writeString( e.getMessage() );
+ }
+ }
+ }
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/UninstallAction.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/UninstallAction.java
new file mode 100644
index 0000000..c60d1c5
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/UninstallAction.java
@@ -0,0 +1,87 @@
+/*
+ * 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.sigil.common.runtime.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.UNINSTALL;
+
+
+/**
+ * @author dave
+ *
+ */
+public class UninstallAction extends Action<Long, Void>
+{
+
+ public UninstallAction( InputStream in, OutputStream out ) throws IOException
+ {
+ super( in, out );
+ // TODO Auto-generated constructor stub
+ }
+
+
+ @Override
+ public Void client( Long bundle ) throws IOException, BundleException
+ {
+ writeInt( UNINSTALL );
+ writeLong( bundle );
+ if ( !checkOk() )
+ {
+ String msg = readString();
+ throw new BundleException( msg );
+ }
+ return null;
+ }
+
+
+ @Override
+ public void server( Framework fw ) throws IOException
+ {
+ long id = readLong();
+ Bundle b = fw.getBundleContext().getBundle( id );
+ if ( b == null )
+ {
+ writeError();
+ writeString( "Unknown bundle " + id );
+ }
+ else
+ {
+ try
+ {
+ b.uninstall();
+ writeOk();
+ }
+ catch ( BundleException e )
+ {
+ writeError();
+ writeString( e.getMessage() );
+ }
+ }
+ }
+
+}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/UpdateAction.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/UpdateAction.java
new file mode 100644
index 0000000..6d56468
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/UpdateAction.java
@@ -0,0 +1,119 @@
+/*
+ * 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.sigil.common.runtime.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+
+import static org.apache.felix.sigil.common.runtime.io.Constants.UPDATE;
+
+
+/**
+ * @author dave
+ *
+ */
+public class UpdateAction extends Action<UpdateAction.Update, Void>
+{
+ public static class Update
+ {
+ final long bundleID;
+ final String location;
+
+
+ public Update( long bundleID, String location )
+ {
+ this.bundleID = bundleID;
+ this.location = location;
+ }
+ }
+
+
+ public UpdateAction( InputStream in, OutputStream out ) throws IOException
+ {
+ super( in, out );
+ }
+
+
+ @Override
+ public Void client( Update update ) throws IOException, BundleException
+ {
+ writeInt( UPDATE );
+ writeLong( update.bundleID );
+ if ( update.location == null )
+ {
+ writeBoolean( false );
+ }
+ else
+ {
+ writeBoolean( true );
+ writeStream( update.location );
+ }
+
+ if ( !checkOk() )
+ {
+ String msg = readString();
+ throw new BundleException( msg );
+ }
+
+ return null;
+ }
+
+
+ @Override
+ public void server( Framework fw ) throws IOException
+ {
+ long id = readLong();
+ Bundle b = fw.getBundleContext().getBundle( id );
+ if ( b == null )
+ {
+ writeError();
+ writeString( "Unknown bundle " + id );
+ }
+ else
+ {
+ try
+ {
+ boolean remote = readBoolean();
+ if ( remote )
+ {
+ InputStream in = readStream();
+ b.update(in);
+ }
+ else
+ {
+ b.update();
+ writeOk();
+ }
+ }
+ catch ( BundleException e )
+ {
+ writeError();
+ writeString( e.getMessage() );
+ }
+ }
+
+ }
+}