diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.framework/impl/org/eclipse/osgi/container/ModuleDataBase.java')
-rw-r--r-- | bundles/org.eclipse.equinox.framework/impl/org/eclipse/osgi/container/ModuleDataBase.java | 373 |
1 files changed, 363 insertions, 10 deletions
diff --git a/bundles/org.eclipse.equinox.framework/impl/org/eclipse/osgi/container/ModuleDataBase.java b/bundles/org.eclipse.equinox.framework/impl/org/eclipse/osgi/container/ModuleDataBase.java index 81d98b651..894b67326 100644 --- a/bundles/org.eclipse.equinox.framework/impl/org/eclipse/osgi/container/ModuleDataBase.java +++ b/bundles/org.eclipse.equinox.framework/impl/org/eclipse/osgi/container/ModuleDataBase.java @@ -11,9 +11,14 @@ package org.eclipse.osgi.container; import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; import java.util.*; import java.util.concurrent.atomic.AtomicLong; +import org.eclipse.osgi.framework.util.ObjectPool; import org.osgi.framework.Version; +import org.osgi.resource.Capability; +import org.osgi.resource.Requirement; /** * A database for storing modules, their revisions and wiring states. The @@ -54,12 +59,12 @@ public abstract class ModuleDataBase { /** * Holds the next id to be assigned to a module when it is installed */ - private final AtomicLong nextId; + final AtomicLong nextId; /** * Holds the current timestamp of this database. */ - private final AtomicLong timeStamp; + final AtomicLong timeStamp; /** * Monitors read and write access to this database @@ -88,7 +93,7 @@ public abstract class ModuleDataBase { if (this.container != null) throw new IllegalStateException("The container is already set."); //$NON-NLS-1$ if (container.moduleDataBase != this) { - throw new IllegalArgumentException("Container is already using a different database."); + throw new IllegalArgumentException("Container is already using a different database."); //$NON-NLS-1$ } this.container = container; } @@ -146,18 +151,22 @@ public abstract class ModuleDataBase { * @return the installed module */ final Module install(String location, ModuleRevisionBuilder builder) { + Module module = load(location, builder, getNextIdAndIncrement()); + incrementTimestamp(); + return module; + } + + final Module load(String location, ModuleRevisionBuilder builder, long id) { if (container == null) throw new IllegalStateException("Container is not set."); //$NON-NLS-1$ if (modulesByLocations.get(location) != null) throw new IllegalArgumentException("Location is already used."); //$NON-NLS-1$ - long id = getNextIdAndIncrement(); Module module = createModule(location, id); ModuleRevision newRevision = builder.buildRevision(id, location, module, container); modulesByLocations.put(location, module); modulesById.put(id, module); addToRevisionByName(newRevision); addCapabilities(newRevision); - incrementTimestamp(); return module; } @@ -439,27 +448,371 @@ public abstract class ModuleDataBase { protected abstract Module createModule(String location, long id); protected void write(DataOutputStream out, boolean persistWirings) throws IOException { - Persistence.write(this, out, persistWirings); + lockRead(false); + try { + Persistence.write(this, out, persistWirings); + } finally { + unlockRead(false); + } } protected void load(DataInputStream in) throws IOException { - Persistence.load(this, in); + lockWrite(); + try { + Persistence.load(this, in); + } finally { + unlockWrite(); + } } private static class Persistence { private static final int VERSION = 1; + private static final byte NULL = 0; + private static final byte OBJECT = 1; + private static final byte INDEX = 2; + private static final byte LONG_STRING = 3; + private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$ + + private static final byte VALUE_STRING = 0; + private static final byte VALUE_STRING_ARRAY = 1; + private static final byte VAlUE_BOOLEAN = 2; + private static final byte VALUE_INTEGER = 3; + private static final byte VALUE_LONG = 4; + private static final byte VALUE_DOUBLE = 5; + private static final byte VALUE_VERSION = 6; + private static final byte VALUE_URI = 7; + private static final byte VALUE_LIST = 8; public static void write(ModuleDataBase moduleDataBase, DataOutputStream out, boolean persistWirings) throws IOException { - out.write(VERSION); + out.writeInt(VERSION); + out.writeLong(moduleDataBase.getTimestamp()); out.writeLong(moduleDataBase.getNextId()); - Collection<Module> modules = moduleDataBase.getModules(); + List<Module> modules = moduleDataBase.getModules(); + out.writeInt(modules.size()); + for (Module module : modules) { + writeModule(module, out); + } } public static void load(ModuleDataBase moduleDataBase, DataInputStream in) throws IOException { int version = in.readInt(); if (version < VERSION) - throw new UnsupportedOperationException("Perstence version is not correct for loading: " + version + " expecting: " + VERSION); + throw new UnsupportedOperationException("Perstence version is not correct for loading: " + version + " expecting: " + VERSION); //$NON-NLS-1$ //$NON-NLS-2$ + moduleDataBase.timeStamp.set(in.readLong()); + moduleDataBase.nextId.set(in.readLong()); + int numModules = in.readInt(); + + for (int i = 0; i < numModules; i++) { + readModule(moduleDataBase, in); + } + } + + private static void writeModule(Module module, DataOutputStream out) throws IOException { + ModuleRevision current = module.getCurrentRevision(); + if (current == null) + return; + ModuleRevisions revisions = module.getRevisions(); + + writeString(revisions.getLocation(), out); + out.writeLong(revisions.getId()); + writeString(current.getSymbolicName(), out); + writeVersion(current.getVersion(), out); + out.writeInt(current.getTypes()); + + List<Capability> capabilities = current.getCapabilities(null); + out.writeInt(capabilities.size()); + for (Capability capability : capabilities) { + writeGenericInfo(capability.getNamespace(), capability.getAttributes(), capability.getDirectives(), out); + } + + List<Requirement> requirements = current.getRequirements(null); + out.writeInt(requirements.size()); + for (Requirement requirement : requirements) { + writeGenericInfo(requirement.getNamespace(), requirement.getAttributes(), requirement.getDirectives(), out); + } + } + + private static void readModule(ModuleDataBase moduleDataBase, DataInputStream in) throws IOException { + ModuleRevisionBuilder builder = new ModuleRevisionBuilder(); + String location = readString(in); + long id = in.readLong(); + builder.setSymbolicName(readString(in)); + builder.setVersion(readVersion(in)); + builder.setTypes(in.readInt()); + + int numCapabilities = in.readInt(); + for (int i = 0; i < numCapabilities; i++) { + readGenericInfo(true, in, builder); + } + + int numRequirements = in.readInt(); + for (int i = 0; i < numRequirements; i++) { + readGenericInfo(false, in, builder); + } + moduleDataBase.load(location, builder, id); + } + + private static void writeGenericInfo(String namespace, Map<String, ?> attributes, Map<String, String> directives, DataOutputStream out) throws IOException { + writeString(namespace, out); + writeMap(attributes, out); + writeMap(directives, out); + } + + @SuppressWarnings("unchecked") + private static void readGenericInfo(boolean isCapability, DataInputStream in, ModuleRevisionBuilder builder) throws IOException { + String namespace = readString(in); + Map<String, Object> attributes = readMap(in); + Map<String, ?> directives = readMap(in); + if (isCapability) { + builder.addCapability(namespace, (Map<String, String>) directives, attributes); + } else { + builder.addRequirement(namespace, (Map<String, String>) directives, attributes); + } + } + private static void writeMap(Map<String, ?> source, DataOutputStream out) throws IOException { + if (source == null) { + out.writeInt(0); + } else { + out.writeInt(source.size()); + Iterator<String> iter = source.keySet().iterator(); + while (iter.hasNext()) { + String key = iter.next(); + Object value = source.get(key); + writeString(key, out); + if (value instanceof String) { + out.writeByte(VALUE_STRING); + writeString((String) value, out); + } else if (value instanceof String[]) { + out.writeByte(VALUE_STRING_ARRAY); + writeStringArray(out, (String[]) value); + } else if (value instanceof Boolean) { + out.writeByte(VAlUE_BOOLEAN); + out.writeBoolean(((Boolean) value).booleanValue()); + } else if (value instanceof Integer) { + out.writeByte(VALUE_INTEGER); + out.writeInt(((Integer) value).intValue()); + } else if (value instanceof Long) { + out.writeByte(VALUE_LONG); + out.writeLong(((Long) value).longValue()); + } else if (value instanceof Double) { + out.writeByte(VALUE_DOUBLE); + out.writeDouble(((Double) value).doubleValue()); + } else if (value instanceof Version) { + out.writeByte(VALUE_VERSION); + writeVersion((Version) value, out); + } else if (value instanceof URI) { + out.writeByte(VALUE_URI); + writeString(value.toString(), out); + } else if (value instanceof List) { + out.writeByte(VALUE_LIST); + writeList(out, (List<?>) value); + } + } + } + } + + private static Map<String, Object> readMap(DataInputStream in) throws IOException { + int count = in.readInt(); + HashMap<String, Object> result = new HashMap<String, Object>(count); + for (int i = 0; i < count; i++) { + String key = readString(in); + Object value = null; + byte type = in.readByte(); + if (type == VALUE_STRING) + value = readString(in); + else if (type == VALUE_STRING_ARRAY) + value = readStringArray(in); + else if (type == VAlUE_BOOLEAN) + value = in.readBoolean() ? Boolean.TRUE : Boolean.FALSE; + else if (type == VALUE_INTEGER) + value = new Integer(in.readInt()); + else if (type == VALUE_LONG) + value = new Long(in.readLong()); + else if (type == VALUE_DOUBLE) + value = new Double(in.readDouble()); + else if (type == VALUE_VERSION) + value = readVersion(in); + else if (type == VALUE_URI) + try { + value = new URI(readString(in)); + } catch (URISyntaxException e) { + value = null; + } + else if (type == VALUE_LIST) + value = readList(in); + + result.put(key, value); + } + return result; + } + + private static void writeStringArray(DataOutputStream out, String[] value) throws IOException { + if (value == null) { + out.writeInt(0); + } else { + out.writeInt(value.length); + for (int i = 0; i < value.length; i++) + writeString(value[i], out); + } + + } + + private static String[] readStringArray(DataInputStream in) throws IOException { + int count = in.readInt(); + if (count == 0) + return null; + String[] result = new String[count]; + for (int i = 0; i < count; i++) + result[i] = readString(in); + return result; + } + + private static void writeList(DataOutputStream out, List<?> list) throws IOException { + if (list.isEmpty()) { + out.writeInt(0); + return; + } + byte type = getListType(list); + if (type < 0) { + out.writeInt(0); + return; // don't understand the list type + } + out.writeInt(list.size()); + out.writeByte(type); + for (Object value : list) { + switch (type) { + case VALUE_STRING : + writeString((String) value, out); + break; + case VALUE_INTEGER : + out.writeInt(((Integer) value).intValue()); + break; + case VALUE_LONG : + out.writeLong(((Long) value).longValue()); + break; + case VALUE_DOUBLE : + out.writeDouble(((Double) value).doubleValue()); + break; + case VALUE_VERSION : + writeVersion((Version) value, out); + break; + default : + break; + } + } + } + + private static byte getListType(List<?> list) { + if (list.size() == 0) + return -1; + Object type = list.get(0); + if (type instanceof String) + return VALUE_STRING; + if (type instanceof Integer) + return VALUE_INTEGER; + if (type instanceof Long) + return VALUE_LONG; + if (type instanceof Double) + return VALUE_DOUBLE; + if (type instanceof Version) + return VALUE_VERSION; + return -2; + } + + private static List<?> readList(DataInputStream in) throws IOException { + + int size = in.readInt(); + if (size == 0) + return new ArrayList<Object>(0); + byte listType = in.readByte(); + List<Object> list = new ArrayList<Object>(size); + for (int i = 0; i < size; i++) { + switch (listType) { + case VALUE_STRING : + list.add(readString(in)); + break; + case VALUE_INTEGER : + list.add(new Integer(in.readInt())); + break; + case VALUE_LONG : + list.add(new Long(in.readLong())); + break; + case VALUE_DOUBLE : + list.add(new Double(in.readDouble())); + break; + case VALUE_VERSION : + list.add(readVersion(in)); + break; + default : + throw new IOException("Invalid type: " + listType); //$NON-NLS-1$ + } + } + return list; + } + + private static void writeVersion(Version version, DataOutputStream out) throws IOException { + if (version == null || version.equals(Version.emptyVersion)) { + out.writeByte(NULL); + return; + } + out.writeByte(OBJECT); + out.writeInt(version.getMajor()); + out.writeInt(version.getMinor()); + out.writeInt(version.getMicro()); + writeQualifier(version.getQualifier(), out); + } + + private static void writeQualifier(String string, DataOutputStream out) throws IOException { + if (string != null && string.length() == 0) + string = null; + writeString(string, out); + } + + private static Version readVersion(DataInputStream in) throws IOException { + byte tag = in.readByte(); + if (tag == NULL) + return Version.emptyVersion; + int majorComponent = in.readInt(); + int minorComponent = in.readInt(); + int serviceComponent = in.readInt(); + String qualifierComponent = readString(in); + return (Version) ObjectPool.intern(new Version(majorComponent, minorComponent, serviceComponent, qualifierComponent)); + } + + private static void writeString(String string, DataOutputStream out) throws IOException { + if (string == null) + out.writeByte(NULL); + else { + byte[] data = string.getBytes(UTF_8); + + if (data.length > 65535) { + out.writeByte(LONG_STRING); + out.writeInt(data.length); + out.write(data); + } else { + out.writeByte(OBJECT); + out.writeUTF(string); + } + } + } + + static private String readString(DataInputStream in) throws IOException { + byte type = in.readByte(); + if (type == NULL) + return null; + + if (type == LONG_STRING) { + int length = in.readInt(); + byte[] data = new byte[length]; + in.readFully(data); + String string = new String(data, UTF_8); + + return (String) ObjectPool.intern(string); + } + + return (String) ObjectPool.intern(in.readUTF()); + } } } |