Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlyn Normington2011-03-18 11:14:24 -0400
committerGlyn Normington2011-03-18 11:14:24 -0400
commit4b94e214e148f59106d35c64adf015958cf378e5 (patch)
tree5a62fe4934f5fb1ed6f81553503e6af357846f22
parent037137e6d71d7f515fadcdc40531cca3e2e12958 (diff)
parent0df420b848b33f89ceb6605171d55e9f7f6945ca (diff)
downloadorg.eclipse.virgo.kernel-4b94e214e148f59106d35c64adf015958cf378e5.tar.gz
org.eclipse.virgo.kernel-4b94e214e148f59106d35c64adf015958cf378e5.tar.xz
org.eclipse.virgo.kernel-4b94e214e148f59106d35c64adf015958cf378e5.zip
Merge remote branch 'origin/region_persistence'
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java9
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java54
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java2
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java15
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java16
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java190
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java4
-rw-r--r--org.eclipse.virgo.kernel.osgi/src/test/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java256
8 files changed, 538 insertions, 8 deletions
diff --git a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java
index 77ccc199..3bb7c266 100644
--- a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java
+++ b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraph.java
@@ -140,7 +140,7 @@ public interface RegionDigraph extends Iterable<Region> {
* @return a {@link Set} of {@link FilteredRegion FilteredRegions} of head regions and region filters
*/
Set<FilteredRegion> getEdges(Region tailRegion);
-
+
/**
* Visit the subgraph connected to the given region.
*
@@ -149,4 +149,11 @@ public interface RegionDigraph extends Iterable<Region> {
*/
void visitSubgraph(Region startingRegion, RegionDigraphVisitor visitor);
+ /**
+ * Gets a {@link RegionDigraphPersistence} object which can be used to save and load a {@link RegionDigraph} to and
+ * from persistent storage.
+ *
+ * @return a {@link RegionDigraphPersistence} object.
+ */
+ RegionDigraphPersistence getRegionDigraphPersistence();
}
diff --git a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java
new file mode 100644
index 00000000..4029f70f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionDigraphPersistence.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.osgi.region;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A region digraph persistence is used to persist the state of a {@link RegionDigraph}.
+ * <p />
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of this interface must be thread safe.
+ */
+public interface RegionDigraphPersistence {
+
+ /**
+ * Creates a new digraph and reads the content of the digraph from the provided input. The provided input must have
+ * been persisted using the {@link #save(RegionDigraph, OutputStream)} method.
+ * <p />
+ * Note that the returned digraph is disconnected from the OSGi runtime. Any modifications made to the returned
+ * digraph will not affect the OSGi runtime behavior of the bundles installed in the running framework.
+ * <p />
+ * The specified stream remains open after this method returns.
+ *
+ * @param input an input stream to read a digraph from.
+ * @return
+ * @throws IOException if error occurs reading the digraph.
+ */
+ RegionDigraph load(InputStream input) throws IOException;
+
+ /**
+ * Writes the specified {@link RegionDigraph} to the provided output in a form suitable for using the
+ * {@link #load(InputStream)} method.
+ * <p />
+ * After the digraph has been written, the output stream is flushed. The output stream remains open after this
+ * method returns.
+ *
+ * @param digraph a digraph to be written.
+ * @param output an output stream to write a digraph to.
+ * @throws IOException if error occurs writing the digraph.
+ */
+ void save(RegionDigraph digraph, OutputStream output) throws IOException;
+}
diff --git a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java
index 92152aba..6b95fea9 100644
--- a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java
+++ b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/RegionFilterBuilder.java
@@ -16,7 +16,7 @@ import org.osgi.framework.InvalidSyntaxException;
/**
* A builder for creating {@link RegionFilter} instances. A builder instance can be obtained from the
* {@link RegionDigraph#createRegionFilterBuilder()} method.
- *
+ * <p />
* <strong>Concurrent Semantics</strong><br />
*
* Implementations of this interface must be thread safe.
diff --git a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java
index 8ebb78f9..a5346a01 100644
--- a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java
+++ b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/BundleIdBasedRegion.java
@@ -112,6 +112,8 @@ final class BundleIdBasedRegion implements Region {
*/
@Override
public Bundle installBundle(String location, InputStream input) throws BundleException {
+ if (this.systemBundleContext == null)
+ throw new BundleException("This region is not connected to an OSGi Framework.", BundleException.INVALID_OPERATION);
setRegionThreadLocal();
try {
return this.systemBundleContext.installBundle(this.regionName + REGION_LOCATION_DELIMITER + location, input);
@@ -125,6 +127,8 @@ final class BundleIdBasedRegion implements Region {
*/
@Override
public Bundle installBundle(String location) throws BundleException {
+ if (this.systemBundleContext == null)
+ throw new BundleException("This region is not connected to an OSGi Framework.", BundleException.INVALID_OPERATION);
setRegionThreadLocal();
try {
return this.systemBundleContext.installBundle(this.regionName + REGION_LOCATION_DELIMITER + location, openBundleStream(location));
@@ -134,11 +138,13 @@ final class BundleIdBasedRegion implements Region {
}
private void setRegionThreadLocal() {
- this.threadLocal.set(this);
+ if (this.threadLocal != null)
+ this.threadLocal.set(this);
}
private void removeRegionThreadLocal() {
- this.threadLocal.remove();
+ if (this.threadLocal != null)
+ this.threadLocal.remove();
}
private InputStream openBundleStream(String location) throws BundleException {
@@ -170,7 +176,8 @@ final class BundleIdBasedRegion implements Region {
*/
@Override
public Bundle getBundle(@NonNull String symbolicName, @NonNull Version version) {
-
+ if (this.systemBundleContext == null)
+ return null; // this region is not connected to an OSGi framework
// The following iteration is weakly consistent and will never throw ConcurrentModificationException.
for (long bundleId : this.bundleIds) {
Bundle bundle = this.systemBundleContext.getBundle(bundleId);
@@ -276,7 +283,7 @@ final class BundleIdBasedRegion implements Region {
@Override
public void visitSubgraph(RegionDigraphVisitor visitor) {
- this.regionDigraph.visitSubgraph(this, visitor);
+ this.regionDigraph.visitSubgraph(this, visitor);
}
}
diff --git a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java
index 92adc276..ce15f2e8 100644
--- a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java
+++ b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraph.java
@@ -22,6 +22,7 @@ import java.util.Set;
import org.eclipse.virgo.kernel.osgi.region.Region;
import org.eclipse.virgo.kernel.osgi.region.RegionDigraph;
+import org.eclipse.virgo.kernel.osgi.region.RegionDigraphPersistence;
import org.eclipse.virgo.kernel.osgi.region.RegionDigraphVisitor;
import org.eclipse.virgo.kernel.osgi.region.RegionFilter;
import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder;
@@ -55,11 +56,15 @@ public final class StandardRegionDigraph implements RegionDigraph {
private final ThreadLocal<Region> threadLocal;
- private SubgraphTraverser subgraphTraverser;
+ private final SubgraphTraverser subgraphTraverser;
+
+ StandardRegionDigraph() {
+ this(null, null);
+ }
public StandardRegionDigraph(BundleContext bundleContext, ThreadLocal<Region> threadLocal) {
this.subgraphTraverser = new SubgraphTraverser();
- this.systemBundleContext = bundleContext.getBundle(0L).getBundleContext();
+ this.systemBundleContext = bundleContext == null ? null : bundleContext.getBundle(0L).getBundleContext();
this.threadLocal = threadLocal;
}
@@ -289,6 +294,8 @@ public final class StandardRegionDigraph implements RegionDigraph {
private Set<RegionLifecycleListener> getListeners() {
Set<RegionLifecycleListener> listeners = new HashSet<RegionLifecycleListener>();
+ if (this.systemBundleContext == null)
+ return listeners;
try {
Collection<ServiceReference<RegionLifecycleListener>> listenerServiceReferences = this.systemBundleContext.getServiceReferences(
RegionLifecycleListener.class, null);
@@ -326,4 +333,9 @@ public final class StandardRegionDigraph implements RegionDigraph {
}
return result;
}
+
+ @Override
+ public RegionDigraphPersistence getRegionDigraphPersistence() {
+ return new StandardRegionDigraphPersistence();
+ }
}
diff --git a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java
new file mode 100644
index 00000000..810cb0a9
--- /dev/null
+++ b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPersistence.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.osgi.region.internal;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.virgo.kernel.osgi.region.Region;
+import org.eclipse.virgo.kernel.osgi.region.RegionDigraph;
+import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion;
+import org.eclipse.virgo.kernel.osgi.region.RegionDigraphPersistence;
+import org.eclipse.virgo.kernel.osgi.region.RegionFilter;
+import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ *
+ * Class used for reading and writing a region digraph to persistent storage.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread safe.
+ */
+final class StandardRegionDigraphPersistence implements RegionDigraphPersistence {
+
+ static void writeRegionDigraph(DataOutputStream out, RegionDigraph digraph) throws IOException {
+ if (!(digraph instanceof StandardRegionDigraph))
+ throw new IllegalArgumentException("Only digraphs of type '" + StandardRegionDigraph.class.getName() + "' are allowed: "
+ + digraph.getClass().getName());
+ Map<Region, Set<FilteredRegion>> filteredRegions = ((StandardRegionDigraph) digraph).getFilteredRegions();
+
+ try {
+ // write the number of regions
+ out.writeInt(filteredRegions.size());
+ // write each region
+ for (Region region : filteredRegions.keySet()) {
+ writeRegion(out, region);
+ }
+ // write each edge
+ // write number of tail regions
+ out.writeInt(filteredRegions.size());
+ for (Map.Entry<Region, Set<FilteredRegion>> edges : filteredRegions.entrySet()) {
+ // write the number of edges for this tail
+ out.writeInt(edges.getValue().size());
+ for (FilteredRegion edge : edges.getValue()) {
+ writeEdge(out, edges.getKey(), edge.getFilter(), edge.getRegion());
+ }
+ }
+ } finally {
+ // note that the output is flushed even on exception
+ out.flush();
+ }
+ }
+
+ private static void writeRegion(DataOutputStream out, Region region) throws IOException {
+ // write region name
+ out.writeUTF(region.getName());
+
+ Set<Long> ids = region.getBundleIds();
+ // write number of bundles
+ out.writeInt(ids.size());
+ for (Long id : ids) {
+ // write each bundle id
+ out.writeLong(id);
+ }
+ }
+
+ private static void writeEdge(DataOutputStream out, Region tail, RegionFilter filter, Region head) throws IOException {
+ // write tail region name
+ out.writeUTF(tail.getName());
+ // write head region name
+ out.writeUTF(head.getName());
+ // save the sharing policy
+ Map<String, Collection<String>> policy = filter.getSharingPolicy();
+ // write the number of name spaces
+ out.writeInt(policy.size());
+ // write each name space policy
+ for (Map.Entry<String, Collection<String>> namespace : policy.entrySet()) {
+ // write the name space name
+ out.writeUTF(namespace.getKey());
+ Collection<String> filters = namespace.getValue();
+ // write the number of filters
+ out.writeInt(filters.size());
+ for (String filterSpec : filters) {
+ // write each filter
+ out.writeUTF(filterSpec);
+ }
+ }
+ }
+
+ static RegionDigraph readRegionDigraph(DataInputStream in) throws IOException, InvalidSyntaxException, BundleException {
+ RegionDigraph digraph = new StandardRegionDigraph();
+
+ // read the number of regions
+ int numRegions = in.readInt();
+ for (int i = 0; i < numRegions; i++) {
+ readRegion(in, digraph);
+ }
+ // read each edge
+ // read number of tail regions
+ int numTails = in.readInt();
+ for (int i = 0; i < numTails; i++) {
+ // read the number of edges for this tail
+ int numEdges = in.readInt();
+ for (int j = 0; j < numEdges; j++) {
+ readEdge(in, digraph);
+ }
+ }
+
+ return digraph;
+ }
+
+ private static Region readRegion(DataInputStream in, RegionDigraph digraph) throws IOException, BundleException {
+ // read region name
+ String name = in.readUTF();
+ Region region = digraph.createRegion(name);
+
+ // read number of bundles
+ int numIds = in.readInt();
+ for (int i = 0; i < numIds; i++) {
+ region.addBundle(in.readLong());
+ }
+ return region;
+ }
+
+ private static void readEdge(DataInputStream in, RegionDigraph digraph) throws IOException, InvalidSyntaxException, BundleException {
+ // read tail region name
+ String tailName = in.readUTF();
+ Region tail = digraph.getRegion(tailName);
+ if (tail == null)
+ throw new IOException("Could not find tail region: " + tailName);
+ // read head region name
+ String headName = in.readUTF();
+ Region head = digraph.getRegion(headName);
+ if (head == null)
+ throw new IOException("Could not find head region: " + headName);
+ // read the sharing policy
+ RegionFilterBuilder builder = digraph.createRegionFilterBuilder();
+ // read the number of name spaces
+ int numSpaces = in.readInt();
+ // read each name space policy
+ for (int i = 0; i < numSpaces; i++) {
+ // read the name space name
+ String namespace = in.readUTF();
+ // read the number of filters
+ int numFilters = in.readInt();
+ for (int j = 0; j < numFilters; j++) {
+ String filter = in.readUTF();
+ builder.allow(namespace, filter);
+ }
+ }
+ digraph.connect(tail, builder.build(), head);
+ }
+
+ @Override
+ public RegionDigraph load(InputStream input) throws IOException {
+ try {
+ return readRegionDigraph(new DataInputStream(input));
+ } catch (InvalidSyntaxException e) {
+ // This should never happen since the filters were valid on save
+ // propagate as IllegalStateException
+ throw new IllegalStateException("Internal error reading a filter", e);
+ } catch (BundleException e) {
+ // This should never happen since the digraph was valid on save
+ // propagate as IllegalStateException
+ throw new IllegalStateException("Internal error creating the digraph", e);
+ }
+ }
+
+ @Override
+ public void save(RegionDigraph digraph, OutputStream output) throws IOException {
+ writeRegionDigraph(new DataOutputStream(output), digraph);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java
index f81b2ff4..f251bb1a 100644
--- a/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java
+++ b/org.eclipse.virgo.kernel.osgi/src/main/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionFilter.java
@@ -142,4 +142,8 @@ final class StandardRegionFilter implements RegionFilter {
}
return result;
}
+
+ public String toString() {
+ return getSharingPolicy().toString();
+ }
}
diff --git a/org.eclipse.virgo.kernel.osgi/src/test/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java b/org.eclipse.virgo.kernel.osgi/src/test/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java
new file mode 100644
index 00000000..8e451607
--- /dev/null
+++ b/org.eclipse.virgo.kernel.osgi/src/test/java/org/eclipse/virgo/kernel/osgi/region/internal/StandardRegionDigraphPeristenceTests.java
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * This file is part of the Virgo Web Server.
+ *
+ * Copyright (c) 2011 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * SpringSource, a division of VMware - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.osgi.region.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.virgo.kernel.osgi.region.Region;
+import org.eclipse.virgo.kernel.osgi.region.RegionDigraph;
+import org.eclipse.virgo.kernel.osgi.region.RegionDigraph.FilteredRegion;
+import org.eclipse.virgo.kernel.osgi.region.RegionFilter;
+import org.eclipse.virgo.kernel.osgi.region.RegionFilterBuilder;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+
+public class StandardRegionDigraphPeristenceTests {
+
+ private RegionDigraph digraph;
+
+ private StubBundleContext systemBundleContext;
+
+ private ThreadLocal<Region> threadLocal;
+
+ private static final String BOOT_REGION = "boot";
+
+ private static final Collection<String> regionNames = Arrays.asList("r0", "r1", "r2", "r3");
+
+ @Before
+ public void setUp() throws Exception {
+ StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc");
+ systemBundleContext = (StubBundleContext) stubSystemBundle.getBundleContext();
+ systemBundleContext.addInstalledBundle(stubSystemBundle);
+ threadLocal = new ThreadLocal<Region>();
+ this.digraph = new StandardRegionDigraph(systemBundleContext, threadLocal);
+ Region boot = digraph.createRegion(BOOT_REGION);
+ boot.addBundle(stubSystemBundle);
+
+ for (String regionName : regionNames) {
+ Region region = digraph.createRegion(regionName);
+ for (int i = 0; i < 10; i++) {
+ String bsn = region.getName() + "." + i;
+ StubBundle b = (StubBundle) systemBundleContext.installBundle(bsn);
+ systemBundleContext.addInstalledBundle(b);
+ region.addBundle(b);
+ }
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+
+ }
+
+ @Test
+ public void testBasic() throws IOException, InvalidSyntaxException, BundleException {
+ doTest();
+ }
+
+ @Test
+ public void testSingleConnection() throws InvalidSyntaxException, BundleException, IOException {
+ Region tail = null;
+ // create a single connection between each region
+ for (Region head : digraph) {
+ if (tail != null) {
+ String name = head.getName();
+ tail.connectRegion(head, createFilter(name + "A", name + "B", name + "C"));
+ }
+ tail = head;
+ }
+ doTest();
+ }
+
+ @Test
+ public void testMultiConnection() throws BundleException, InvalidSyntaxException, IOException {
+ List<Region> tails = new ArrayList<Region>();
+ // create multiple connections between each region
+ for (Region head : digraph) {
+ for (Region tail : tails) {
+ String name = head.getName();
+ tail.connectRegion(head, createFilter(name + "A", name + "B", name + "C"));
+ }
+ tails.add(head);
+ }
+ doTest();
+ }
+
+ @Test
+ public void testMultiConnectionCycle() throws BundleException, InvalidSyntaxException, IOException {
+ List<Region> tails = new ArrayList<Region>();
+ for (Region region : digraph) {
+ tails.add(region);
+ }
+ // create multiple connections between each region with cycles
+ for (Region head : digraph) {
+ for (Region tail : tails) {
+ if (head == tail)
+ continue;
+ String name = head.getName();
+ tail.connectRegion(head, createFilter(name + "A", name + "B", name + "C"));
+ }
+ }
+ doTest();
+ }
+
+ @Test
+ public void testInvalidOperations() throws IOException, InvalidSyntaxException, BundleException {
+ Region boot = digraph.getRegion(BOOT_REGION);
+ Bundle b = boot.installBundle("dynamic.add.a.1", null);
+ // needed because we don't have a bundle hook to add it for us
+ boot.addBundle(b);
+ // needed because StubBundleContext.installBundle does not do this!
+ systemBundleContext.addInstalledBundle((StubBundle) b);
+ Bundle p = boot.getBundle(b.getSymbolicName(), b.getVersion());
+ Assert.assertEquals(b, p);
+ // TODO seems testing this will require a reference handler to be present
+ // b = boot.installBundle("file:dynamic.add.a.2");
+ // boot.addBundle(b); // needed because we don't have a bundle hook to add it for us
+
+ RegionDigraph copy = copy(digraph);
+ Region bootCopy = copy.getRegion(BOOT_REGION);
+ p = bootCopy.getBundle(b.getSymbolicName(), b.getVersion());
+ Assert.assertNull(p);
+ try {
+ bootCopy.installBundle("dynamic.add.b.1", null);
+ } catch (BundleException e) {
+ // expected
+ }
+ try {
+ bootCopy.installBundle("dynamic.add.b.2");
+ } catch (BundleException e) {
+ // expected
+ }
+
+ }
+
+ private void doTest() throws IOException, InvalidSyntaxException, BundleException {
+ // test a single write
+ doTest(1);
+ // test writing and reading the digraph multiple times to same stream
+ doTest(10);
+ }
+
+ private RegionDigraph copy(RegionDigraph toCopy) throws IOException, InvalidSyntaxException, BundleException {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ DataOutputStream dataOut = new DataOutputStream(output);
+ StandardRegionDigraphPersistence.writeRegionDigraph(new DataOutputStream(output), digraph);
+ dataOut.close();
+
+ DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(output.toByteArray()));
+ RegionDigraph copy = StandardRegionDigraphPersistence.readRegionDigraph(dataIn);
+ dataIn.close();
+ return copy;
+ }
+
+ private void doTest(int iterations) throws IOException, InvalidSyntaxException, BundleException {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ DataOutputStream dataOut = new DataOutputStream(output);
+ for (int i = 0; i < iterations; i++) {
+ StandardRegionDigraphPersistence.writeRegionDigraph(new DataOutputStream(output), digraph);
+ }
+ dataOut.close();
+
+ DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(output.toByteArray()));
+ for (int i = 0; i < iterations; i++) {
+ RegionDigraph copy = StandardRegionDigraphPersistence.readRegionDigraph(dataIn);
+ assertEquals(digraph, copy);
+ }
+ dataIn.close();
+ }
+
+ private RegionFilter createFilter(String... input) throws InvalidSyntaxException {
+ RegionFilterBuilder builder = digraph.createRegionFilterBuilder();
+ for (String param : input) {
+ builder.allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, "(bundle-symbolic-name=" + param + ")");
+ builder.allow(RegionFilter.VISIBLE_HOST_NAMESPACE, "(" + RegionFilter.VISIBLE_HOST_NAMESPACE + "=" + param + ")");
+ builder.allow(RegionFilter.VISIBLE_PACKAGE_NAMESPACE, "(" + RegionFilter.VISIBLE_PACKAGE_NAMESPACE + "=" + param + ")");
+ builder.allow(RegionFilter.VISIBLE_REQUIRE_NAMESPACE, "(" + RegionFilter.VISIBLE_REQUIRE_NAMESPACE + "=" + param + ")");
+ builder.allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, "(" + Constants.OBJECTCLASS + "=" + param + ")");
+ }
+ return builder.build();
+ }
+
+ static void assertEquals(RegionDigraph d1, RegionDigraph d2) {
+ int rCnt1 = countRegions(d1);
+ int rCnt2 = countRegions(d2);
+ Assert.assertEquals(rCnt1, rCnt2);
+ for (Region r1 : d1) {
+ Region r2 = d2.getRegion(r1.getName());
+ assertEquals(r1, r2);
+ }
+ }
+
+ static int countRegions(RegionDigraph digraph) {
+ int result = 0;
+ for (Region region : digraph) {
+ result++;
+ }
+ return result;
+ }
+
+ static void assertEquals(Region r1, Region r2) {
+ Assert.assertNotNull(r1);
+ Assert.assertNotNull(r2);
+ Assert.assertEquals("Wrong name", r1.getName(), r2.getName());
+ Set<Long> r1IDs = r1.getBundleIds();
+ Set<Long> r2IDs = r2.getBundleIds();
+ Assert.assertEquals(r1IDs.size(), r2IDs.size());
+ for (Long id : r1IDs) {
+ Assert.assertTrue("Missing id: " + id, r2IDs.contains(id));
+ }
+ assertEquals(r1.getEdges(), r2.getEdges());
+ }
+
+ static void assertEquals(Set<FilteredRegion> edges1, Set<FilteredRegion> edges2) {
+ Assert.assertEquals(edges1.size(), edges2.size());
+ Map<String, RegionFilter> edges2Map = new HashMap<String, RegionFilter>();
+ for (FilteredRegion edge2 : edges2) {
+ edges2Map.put(edge2.getRegion().getName(), edge2.getFilter());
+ }
+ for (FilteredRegion edge1 : edges1) {
+ RegionFilter filter2 = edges2Map.get(edge1.getRegion().getName());
+ Assert.assertNotNull("No filter found: " + edge1.getRegion().getName(), filter2);
+ Assert.assertEquals(edge1.getFilter().getSharingPolicy(), filter2.getSharingPolicy());
+ }
+ }
+}

Back to the top