Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2010-10-18 15:21:31 +0000
committerThomas Watson2010-10-18 15:21:31 +0000
commit212cc1fe370674e62ebce888ad3d08fe6e8eae51 (patch)
tree35a62b7a85416ba13dfc5da6a14334badf43f712
parente9bdb7ca52c12aef8196c84d760ba21975effb2a (diff)
downloadrt.equinox.framework-212cc1fe370674e62ebce888ad3d08fe6e8eae51.tar.gz
rt.equinox.framework-212cc1fe370674e62ebce888ad3d08fe6e8eae51.tar.xz
rt.equinox.framework-212cc1fe370674e62ebce888ad3d08fe6e8eae51.zip
Bug 327675 - Support framework UUID
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java62
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java1
-rwxr-xr-xbundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/UniversalUniqueIdentifier.java266
3 files changed, 328 insertions, 1 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
index 09dc0a8bb..4f5724693 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
@@ -12,7 +12,7 @@ package org.eclipse.osgi.tests.bundles;
import java.io.*;
import java.net.URL;
-import java.util.Properties;
+import java.util.*;
import java.util.jar.*;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -1092,6 +1092,66 @@ public class SystemBundleTests extends AbstractBundleTests {
assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox2.getState()); //$NON-NLS-1$
}
+ public void testUUID() {
+ File config1 = OSGiTestsActivator.getContext().getDataFile(getName() + "_1"); //$NON-NLS-1$
+ Map configuration1 = new HashMap();
+ configuration1.put(Constants.FRAMEWORK_STORAGE, config1.getAbsolutePath());
+ Equinox equinox1 = new Equinox(configuration1);
+ try {
+ equinox1.init();
+ } catch (BundleException e) {
+ fail("Failed init", e);
+ }
+ String uuid1_1 = equinox1.getBundleContext().getProperty(Constants.FRAMEWORK_UUID);
+ assertNotNull(uuid1_1);
+
+ File config2 = OSGiTestsActivator.getContext().getDataFile(getName() + "_2"); //$NON-NLS-1$
+ Map configuration2 = new HashMap();
+ configuration2.put(Constants.FRAMEWORK_STORAGE, config2.getAbsolutePath());
+ Equinox equinox2 = new Equinox(configuration1);
+ try {
+ equinox2.init();
+ } catch (BundleException e) {
+ fail("Failed init", e);
+ }
+ String uuid2_1 = equinox2.getBundleContext().getProperty(Constants.FRAMEWORK_UUID);
+ assertNotNull(uuid2_1);
+
+ assertFalse("UUIDs are the same: " + uuid1_1, uuid1_1.equals(uuid2_1));
+
+ try {
+ equinox1.stop();
+ equinox2.stop();
+ equinox1.waitForStop(1000);
+ equinox2.waitForStop(1000);
+ equinox1.init();
+ equinox2.init();
+ } catch (BundleException e) {
+ fail("Failed to re-init frameworks.", e);
+ } catch (InterruptedException e) {
+ fail("Failed to stop frameworks.", e);
+ }
+
+ String uuid1_2 = equinox1.getBundleContext().getProperty(Constants.FRAMEWORK_UUID);
+ assertNotNull(uuid1_2);
+ String uuid2_2 = equinox2.getBundleContext().getProperty(Constants.FRAMEWORK_UUID);
+ assertNotNull(uuid2_2);
+ assertFalse("UUIDs are the same: " + uuid1_1, uuid1_1.equals(uuid1_2));
+ assertFalse("UUIDs are the same: " + uuid1_2, uuid1_2.equals(uuid2_2));
+ assertFalse("UUIDs are the same: " + uuid2_1, uuid2_1.equals(uuid2_2));
+
+ try {
+ equinox1.stop();
+ equinox2.stop();
+ equinox1.waitForStop(1000);
+ equinox2.waitForStop(1000);
+ } catch (BundleException e) {
+ fail("Failed to re-init frameworks.", e);
+ } catch (InterruptedException e) {
+ fail("Failed to stop frameworks.", e);
+ }
+ }
+
private static File[] createBundles(File outputDir, int bundleCount) throws IOException {
outputDir.mkdirs();
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java
index 7cf7b1d07..f557f100b 100644
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java
@@ -375,6 +375,7 @@ public class Framework implements EventPublisher, Runnable {
// set the support properties for fragments and require-bundle (bug 173090)
properties.put(Constants.SUPPORTS_FRAMEWORK_FRAGMENT, "true"); //$NON-NLS-1$
properties.put(Constants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE, "true"); //$NON-NLS-1$
+ properties.put(Constants.FRAMEWORK_UUID, new UniversalUniqueIdentifier().toString());
}
private int parseVersionInt(String value) {
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/UniversalUniqueIdentifier.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/UniversalUniqueIdentifier.java
new file mode 100755
index 000000000..7b42f7d3f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/UniversalUniqueIdentifier.java
@@ -0,0 +1,266 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 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.osgi.framework.internal.core;
+
+import java.io.*;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.SecureRandom;
+import java.util.GregorianCalendar;
+import java.util.Random;
+
+public class UniversalUniqueIdentifier {
+
+ /* INSTANCE FIELDS =============================================== */
+
+ private byte[] fBits = new byte[BYTES_SIZE];
+
+ /* NON-FINAL PRIVATE STATIC FIELDS =============================== */
+
+ private volatile static BigInteger fgPreviousClockValue;
+ private volatile static int fgClockAdjustment = 0;
+ private volatile static int fgClockSequence = -1;
+ private final static byte[] nodeAddress;
+
+ static {
+ nodeAddress = computeNodeAddress();
+ }
+
+ /* PRIVATE STATIC FINAL FIELDS =================================== */
+
+ private final static Random fgRandomNumberGenerator = new Random();
+
+ /* PUBLIC STATIC FINAL FIELDS ==================================== */
+
+ public static final int BYTES_SIZE = 16;
+ public static final byte[] UNDEFINED_UUID_BYTES = new byte[16];
+ public static final int MAX_CLOCK_SEQUENCE = 0x4000;
+ public static final int MAX_CLOCK_ADJUSTMENT = 0x7FFF;
+ public static final int TIME_FIELD_START = 0;
+ public static final int TIME_FIELD_STOP = 6;
+ public static final int TIME_HIGH_AND_VERSION = 7;
+ public static final int CLOCK_SEQUENCE_HIGH_AND_RESERVED = 8;
+ public static final int CLOCK_SEQUENCE_LOW = 9;
+ public static final int NODE_ADDRESS_START = 10;
+ public static final int NODE_ADDRESS_BYTE_SIZE = 6;
+
+ public static final int BYTE_MASK = 0xFF;
+
+ public static final int HIGH_NIBBLE_MASK = 0xF0;
+
+ public static final int LOW_NIBBLE_MASK = 0x0F;
+
+ public static final int SHIFT_NIBBLE = 4;
+
+ public static final int ShiftByte = 8;
+
+ /**
+ UniversalUniqueIdentifier default constructor returns a
+ new instance that has been initialized to a unique value.
+ */
+ public UniversalUniqueIdentifier() {
+ this.setVersion(1);
+ this.setVariant(1);
+ this.setTimeValues();
+ this.setNode(getNodeAddress());
+ }
+
+ private void appendByteString(StringBuffer buffer, byte value) {
+ String hexString;
+
+ if (value < 0)
+ hexString = Integer.toHexString(256 + value);
+ else
+ hexString = Integer.toHexString(value);
+ if (hexString.length() == 1)
+ buffer.append("0"); //$NON-NLS-1$
+ buffer.append(hexString);
+ }
+
+ private static BigInteger clockValueNow() {
+ GregorianCalendar now = new GregorianCalendar();
+ BigInteger nowMillis = BigInteger.valueOf(now.getTime().getTime());
+ BigInteger baseMillis = BigInteger.valueOf(now.getGregorianChange().getTime());
+
+ return (nowMillis.subtract(baseMillis).multiply(BigInteger.valueOf(10000L)));
+ }
+
+ /**
+ * Answers the node address attempting to mask the IP
+ * address of this machine.
+ *
+ * @return byte[] the node address
+ */
+ private static byte[] computeNodeAddress() {
+
+ byte[] address = new byte[NODE_ADDRESS_BYTE_SIZE];
+
+ // Seed the secure randomizer with some oft-varying inputs
+ int thread = Thread.currentThread().hashCode();
+ long time = System.currentTimeMillis();
+ int objectId = System.identityHashCode(new String());
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(byteOut);
+ byte[] ipAddress = getIPAddress();
+
+ try {
+ if (ipAddress != null)
+ out.write(ipAddress);
+ out.write(thread);
+ out.writeLong(time);
+ out.write(objectId);
+ out.close();
+ } catch (IOException exc) {
+ //ignore the failure, we're just trying to come up with a random seed
+ }
+ byte[] rand = byteOut.toByteArray();
+
+ SecureRandom randomizer = new SecureRandom(rand);
+ randomizer.nextBytes(address);
+
+ // set the MSB of the first octet to 1 to distinguish from IEEE node addresses
+ address[0] = (byte) (address[0] | (byte) 0x80);
+
+ return address;
+ }
+
+ /**
+ Answers the IP address of the local machine using the
+ Java API class <code>InetAddress</code>.
+
+ @return byte[] the network address in network order
+ @see java.net.InetAddress#getLocalHost()
+ @see java.net.InetAddress#getAddress()
+ */
+ private static byte[] getIPAddress() {
+ try {
+ return InetAddress.getLocalHost().getAddress();
+ } catch (UnknownHostException e) {
+ //valid for this to be thrown be a machine with no IP connection
+ //It is VERY important NOT to throw this exception
+ return null;
+ }
+ }
+
+ private static byte[] getNodeAddress() {
+ return nodeAddress;
+ }
+
+ private static int nextClockSequence() {
+
+ if (fgClockSequence == -1)
+ fgClockSequence = (int) (fgRandomNumberGenerator.nextDouble() * MAX_CLOCK_SEQUENCE);
+
+ fgClockSequence = (fgClockSequence + 1) % MAX_CLOCK_SEQUENCE;
+
+ return fgClockSequence;
+ }
+
+ private static BigInteger nextTimestamp() {
+
+ BigInteger timestamp = clockValueNow();
+ int timestampComparison;
+
+ timestampComparison = timestamp.compareTo(fgPreviousClockValue);
+
+ if (timestampComparison == 0) {
+ if (fgClockAdjustment == MAX_CLOCK_ADJUSTMENT) {
+ while (timestamp.compareTo(fgPreviousClockValue) == 0)
+ timestamp = clockValueNow();
+ timestamp = nextTimestamp();
+ } else
+ fgClockAdjustment++;
+ } else {
+ fgClockAdjustment = 0;
+
+ if (timestampComparison < 0)
+ nextClockSequence();
+ }
+
+ return timestamp;
+ }
+
+ private void setClockSequence(int clockSeq) {
+ int clockSeqHigh = (clockSeq >>> ShiftByte) & LOW_NIBBLE_MASK;
+ int reserved = fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] & HIGH_NIBBLE_MASK;
+
+ fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] = (byte) (reserved | clockSeqHigh);
+ fBits[CLOCK_SEQUENCE_LOW] = (byte) (clockSeq & BYTE_MASK);
+ }
+
+ private void setNode(byte[] bytes) {
+
+ for (int index = 0; index < NODE_ADDRESS_BYTE_SIZE; index++)
+ fBits[index + NODE_ADDRESS_START] = bytes[index];
+ }
+
+ private void setTimestamp(BigInteger timestamp) {
+ BigInteger value = timestamp;
+ BigInteger bigByte = BigInteger.valueOf(256L);
+ BigInteger[] results;
+ int version;
+ int timeHigh;
+
+ for (int index = TIME_FIELD_START; index < TIME_FIELD_STOP; index++) {
+ results = value.divideAndRemainder(bigByte);
+ value = results[0];
+ fBits[index] = (byte) results[1].intValue();
+ }
+ version = fBits[TIME_HIGH_AND_VERSION] & HIGH_NIBBLE_MASK;
+ timeHigh = value.intValue() & LOW_NIBBLE_MASK;
+ fBits[TIME_HIGH_AND_VERSION] = (byte) (timeHigh | version);
+ }
+
+ private synchronized void setTimeValues() {
+ this.setTimestamp(timestamp());
+ this.setClockSequence(fgClockSequence);
+ }
+
+ private int setVariant(int variantIdentifier) {
+ int clockSeqHigh = fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] & LOW_NIBBLE_MASK;
+ int variant = variantIdentifier & LOW_NIBBLE_MASK;
+
+ fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] = (byte) ((variant << SHIFT_NIBBLE) | clockSeqHigh);
+ return (variant);
+ }
+
+ private void setVersion(int versionIdentifier) {
+ int timeHigh = fBits[TIME_HIGH_AND_VERSION] & LOW_NIBBLE_MASK;
+ int version = versionIdentifier & LOW_NIBBLE_MASK;
+
+ fBits[TIME_HIGH_AND_VERSION] = (byte) (timeHigh | (version << SHIFT_NIBBLE));
+ }
+
+ private static BigInteger timestamp() {
+ BigInteger timestamp;
+
+ if (fgPreviousClockValue == null) {
+ fgClockAdjustment = 0;
+ nextClockSequence();
+ timestamp = clockValueNow();
+ } else
+ timestamp = nextTimestamp();
+
+ fgPreviousClockValue = timestamp;
+ return fgClockAdjustment == 0 ? timestamp : timestamp.add(BigInteger.valueOf(fgClockAdjustment));
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < fBits.length; i++) {
+ if (i == 4 || i == 6 || i == 8 || i == 10)
+ buffer.append('-');
+ appendByteString(buffer, fBits[i]);
+ }
+ return buffer.toString();
+ }
+}

Back to the top