Patches related to FELIX-1324 create BundleForm class to encapsulate a certain bundle configuration - Client.apply(BundleForm) merges the specified form into the currently running framework configuration (i.e. applies delta to currently running bundles)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@830559 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/common/runtime/sigil.properties b/sigil/common/runtime/sigil.properties
index 6705725..23156cc 100644
--- a/sigil/common/runtime/sigil.properties
+++ b/sigil/common/runtime/sigil.properties
@@ -14,7 +14,8 @@
-imports: \
org.apache.felix.sigil.common.runtime,\
org.osgi.framework, \
- org.osgi.framework.launch;resolve=compile;version=1.0.0, \
+ org.osgi.framework.launch, \
+ org.osgi.service.packageadmin, \
header;Main-Class: org.apache.felix.sigil.common.runtime.Main
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/BundleForm.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/BundleForm.java
new file mode 100644
index 0000000..57c1ed7
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/BundleForm.java
@@ -0,0 +1,197 @@
+/*
+ * 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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+public class BundleForm
+{
+ public static class BundleStatus
+ {
+ private String location;
+ private String bundleSymbolicName;
+ private String version;
+ private long id;
+ private int status;
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+ public void setLocation(String location)
+ {
+ this.location = location;
+ }
+
+ public String getBundleSymbolicName()
+ {
+ return bundleSymbolicName;
+ }
+
+ public void setBundleSymbolicName(String bundleSymbolicName)
+ {
+ this.bundleSymbolicName = bundleSymbolicName;
+ }
+
+ public String getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion(String version)
+ {
+ this.version = version;
+ }
+
+ public long getId()
+ {
+ return id;
+ }
+
+ public void setId(long id)
+ {
+ this.id = id;
+ }
+
+ public void setStatus(int status)
+ {
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public boolean isMatch(BundleStatus n)
+ {
+ return bundleSymbolicName.equals( n.bundleSymbolicName ) && version.equals(n.version);
+ }
+ }
+
+ private String[] bundles;
+ private Set<String> startMap = new HashSet<String>();
+
+ public BundleForm() {
+ }
+
+ public static BundleForm resolve(URL formURL) throws IOException, URISyntaxException {
+ InputStream in = formURL.openStream();
+ try {
+ BundleForm f = new BundleForm();
+ BufferedReader r = new BufferedReader(new InputStreamReader(in));
+ LinkedList<String> locs = new LinkedList<String>();
+ for(;;) {
+ String l = r.readLine();
+ if ( l == null ) break;
+ URI uri = URI.create(l);
+ String status = uri.getScheme();
+ uri = URI.create(uri.getSchemeSpecificPart());
+ String loc = uri.toString();
+ locs.add( loc );
+ f.setStarted(loc, "start".equalsIgnoreCase(status) );
+ }
+ f.setBundles(locs.toArray(new String[locs.size()]));
+ return f;
+ }
+ finally {
+ try
+ {
+ in.close();
+ }
+ catch (IOException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void setBundles(String[] bundles) {
+ this.bundles = bundles;
+ }
+
+ public String[] getBundles()
+ {
+ return bundles;
+ }
+
+ public boolean isStarted(String url)
+ {
+ return startMap.contains(url);
+ }
+
+ public void setStarted(String url, boolean started) {
+ if ( started ) {
+ startMap.add(url);
+ }
+ else {
+ startMap.remove(url);
+ }
+ }
+
+ public BundleStatus[] toStatus() throws IOException {
+ ArrayList<BundleStatus> ret = new ArrayList<BundleStatus>(bundles.length);
+ for ( String loc : bundles ) {
+ URL url = new URL(loc);
+ InputStream in = url.openStream();
+ try {
+ JarInputStream jin = new JarInputStream(in);
+ Manifest mf = jin.getManifest();
+ Attributes attr = mf.getMainAttributes();
+ String bsn = attr.getValue(Constants.BUNDLE_SYMBOLICNAME);
+ String ver = attr.getValue(Constants.BUNDLE_VERSION);
+ BundleStatus st = new BundleStatus();
+ st.setBundleSymbolicName(bsn);
+ st.setVersion(ver);
+ st.setLocation(loc);
+ st.setStatus(isStarted(loc) ? Bundle.ACTIVE : Bundle.INSTALLED);
+ ret.add(st);
+ }
+ finally {
+ try
+ {
+ in.close();
+ }
+ catch (IOException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ return ret.toArray(new BundleStatus[ret.size()] );
+ }
+}
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
index 4b6c955..807b783 100644
--- 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
@@ -26,16 +26,18 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
-import java.util.Map;
import java.util.Properties;
+import org.apache.felix.sigil.common.runtime.BundleForm.BundleStatus;
import org.apache.felix.sigil.common.runtime.io.InstallAction;
+import org.apache.felix.sigil.common.runtime.io.RefreshAction;
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.Bundle;
import org.osgi.framework.BundleException;
import static org.apache.felix.sigil.common.runtime.Runtime.PORT_PROPERTY;
@@ -90,6 +92,27 @@
out = null;
}
+ public void apply(BundleForm form) throws IOException, BundleException {
+ BundleStatus[] newStatus = form.toStatus();
+
+ BundleStatus[] currentStatus = status();
+
+ stopOldBundles(currentStatus, newStatus);
+
+ boolean change = uninstallOldBundles(currentStatus, newStatus);
+ change |= installNewBundles(currentStatus, newStatus);
+
+ if ( change )
+ refresh();
+
+ startNewBundles(newStatus);
+ }
+
+ public void refresh() throws IOException, BundleException
+ {
+ if ( socket == null ) throw new IllegalStateException( "Not connected" );
+ new RefreshAction( in, out ).client();
+ }
public long install( String url ) throws IOException, BundleException
{
@@ -135,9 +158,84 @@
}
- public Map<Long, String> status() throws IOException, BundleException
+ public BundleStatus[] status() throws IOException, BundleException
{
if ( socket == null ) throw new IllegalStateException( "Not connected" );
return new StatusAction( in, out ).client();
}
+
+ private boolean installNewBundles(BundleStatus[] status, BundleStatus[] newStatus) throws IOException, BundleException
+ {
+ boolean change = false;
+ for (BundleStatus n : newStatus) {
+ boolean found = false;
+ for ( BundleStatus o : status ) {
+ if ( o.isMatch(n) ) {
+ update(o.getId(), n.getLocation());
+ found = true;
+ change = true;
+ break;
+ }
+ }
+
+ if ( !found ) {
+ install(n.getLocation());
+ change = true;
+ }
+ }
+
+ return change;
+ }
+
+ private void startNewBundles(BundleStatus[] newStatus) throws IOException, BundleException
+ {
+ BundleStatus[] status = status();
+ for (BundleStatus n : newStatus) {
+ if ( n.getStatus() == Bundle.ACTIVE ) {
+ for ( BundleStatus o : status ) {
+ if ( o.isMatch(n) ) {
+ start(o.getId());
+ }
+ }
+ }
+ }
+ }
+
+ private void stopOldBundles(BundleStatus[] status, BundleStatus[] newStatus) throws IOException, BundleException
+ {
+ for (BundleStatus n : newStatus) {
+ if ( n.getStatus() == Bundle.INSTALLED ) {
+ for ( BundleStatus o : status ) {
+ if ( o.getId() != 0 ) {
+ if ( o.isMatch(n) ) {
+ stop(o.getId());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private boolean uninstallOldBundles(BundleStatus[] status, BundleStatus[] newStatus) throws IOException, BundleException
+ {
+ boolean change = false;
+ for ( BundleStatus o : status ) {
+ if ( o.getId() != 0 ) {
+ boolean found = false;
+
+ for (BundleStatus n : newStatus) {
+ if ( o.isMatch(n) ) {
+ found = true;
+ break;
+ }
+ }
+
+ if ( !found ) {
+ change = true;
+ uninstall(o.getId());
+ }
+ }
+ }
+ return change;
+ }
}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Runtime.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Runtime.java
index 87f3bfb..7fbf762 100644
--- a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Runtime.java
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/Runtime.java
@@ -19,7 +19,7 @@
package org.apache.felix.sigil.common.runtime;
-public class Runtime
+public interface Runtime
{
public static final String PORT_PROPERTY = "port";
public static final String ADDRESS_PROPERTY = "address";
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
index 36cef3a..6d37887 100644
--- 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
@@ -35,6 +35,7 @@
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.RefreshAction;
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;
@@ -164,6 +165,9 @@
case STATUS:
task = new StatusAction( in, out );
break;
+ case REFRESH:
+ task = new RefreshAction(in, out);
+ break;
}
if ( task == null ) {
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
index 1d1e788..d3221a8 100644
--- 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
@@ -31,4 +31,5 @@
public static final int UNINSTALL = 4;
public static final int UPDATE = 5;
public static final int STATUS = 6;
+ public static final int REFRESH = 7;
}
diff --git a/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/RefreshAction.java b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/RefreshAction.java
new file mode 100644
index 0000000..9f0064d
--- /dev/null
+++ b/sigil/common/runtime/src/org/apache/felix/sigil/common/runtime/io/RefreshAction.java
@@ -0,0 +1,75 @@
+/*
+ * 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 static org.apache.felix.sigil.common.runtime.io.Constants.REFRESH;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.launch.Framework;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class RefreshAction extends Action<Void, Void>
+{
+
+ public RefreshAction(DataInputStream in, DataOutputStream out) throws IOException
+ {
+ super(in, out);
+ }
+
+ @Override
+ public Void client(Void input) throws IOException, BundleException
+ {
+ writeInt( REFRESH );
+ flush();
+ if ( checkOk() )
+ {
+ return null;
+ }
+ else
+ {
+ String msg = readString();
+ throw new BundleException( msg );
+ }
+ }
+
+ @Override
+ public void server(Framework fw) throws IOException
+ {
+ ServiceReference ref = fw.getBundleContext().getServiceReference(PackageAdmin.class.getName());
+ if ( ref != null ) {
+ PackageAdmin pa = (PackageAdmin) fw.getBundleContext().getService(ref);
+ if ( pa != null ) {
+ try {
+ pa.refreshPackages(null);
+ }
+ finally {
+ fw.getBundleContext().ungetService(ref);
+ }
+ }
+ }
+ writeOk();
+ flush();
+ }
+
+}
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
index 5b22c07..8776960 100644
--- 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
@@ -21,23 +21,25 @@
import java.io.DataInputStream;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
+import org.apache.felix.sigil.common.runtime.BundleForm.BundleStatus;
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;
+import static org.osgi.framework.Constants.BUNDLE_NAME;
/**
* @author dave
*
*/
-public class StatusAction extends Action<Void, Map<Long, String>>
+public class StatusAction extends Action<Void, BundleStatus[]>
{
public StatusAction( DataInputStream in, DataOutputStream out ) throws IOException
@@ -47,20 +49,24 @@
@Override
- public Map<Long, String> client( Void in ) throws IOException
+ public BundleStatus[] client( Void in ) throws IOException
{
writeInt(STATUS);
flush();
int num = readInt();
- HashMap<Long, String> map = new HashMap<Long, String>(num);
+ ArrayList<BundleStatus> ret = new ArrayList<BundleStatus>(num);
for (int i = 0; i < num; i++) {
- long id = readLong();
- String symbol = readString();
- map.put( id, symbol );
+ BundleStatus s = new BundleStatus();
+ s.setId(readLong());
+ s.setBundleSymbolicName(readString());
+ s.setVersion(readString());
+ s.setLocation(readString());
+ s.setStatus(readInt());
+ ret.add(s);
}
- return map;
+ return ret.toArray(new BundleStatus[num]);
}
@@ -72,25 +78,17 @@
writeInt( bundles.length );
for ( Bundle b : bundles ) {
writeLong(b.getBundleId());
- String symbol = b.getSymbolicName() + ":" + b.getHeaders().get( BUNDLE_VERSION ) + ":" + state(b);
- writeString(symbol);
+ System.out.println( "Written " + b.getBundleId());
+ String bsn = b.getSymbolicName();
+ if ( bsn == null )
+ bsn = (String) b.getHeaders().get(BUNDLE_NAME);
+
+ writeString(bsn);
+ writeString((String) b.getHeaders().get( BUNDLE_VERSION ));
+ writeString(b.getLocation());
+ writeInt(b.getState());
+ flush();
}
-
- flush();
+ flush();
}
-
-
- private String state( Bundle b )
- {
- switch ( b.getState() ) {
- case Bundle.ACTIVE: return "active";
- case Bundle.INSTALLED: return "installed";
- case Bundle.RESOLVED: return "resolved";
- case Bundle.STARTING: return "starting";
- case Bundle.STOPPING: return "stopping";
- case Bundle.UNINSTALLED: return "uninstalled";
- default: return "unknown";
- }
- }
-
}