Bug 123133 - Add APIs to remove extensions and extension points from the registry
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/BufferedRandomInputStream.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/BufferedRandomInputStream.java
index 08c23a6..a19c861 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/BufferedRandomInputStream.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/BufferedRandomInputStream.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2006 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
@@ -29,7 +29,7 @@
 
 	public BufferedRandomInputStream(File file, int bufferSize) throws IOException {
 		filePath = file.getCanonicalPath();
-		inputFile = new RandomAccessFile(file, "r");
+		inputFile = new RandomAccessFile(file, "r"); //$NON-NLS-1$
 		buffer = new byte[bufferSize];
 		resetBuffer();
 	}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElement.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElement.java
index a6ef999..2da3d0a 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElement.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 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
@@ -42,12 +42,12 @@
 	//This happens when the configuration is obtained from a delta containing removed extension.
 	private String contributorId;
 
-	protected ConfigurationElement(ExtensionRegistry registry, boolean isDynamic) {
-		super(registry, isDynamic);
+	protected ConfigurationElement(ExtensionRegistry registry, boolean persist) {
+		super(registry, persist);
 	}
 
-	protected ConfigurationElement(int self, String contributorId, String name, String[] propertiesAndValue, int[] children, int extraDataOffset, int parent, byte parentType, ExtensionRegistry registry, boolean isDynamic) {
-		super(registry, isDynamic);
+	protected ConfigurationElement(int self, String contributorId, String name, String[] propertiesAndValue, int[] children, int extraDataOffset, int parent, byte parentType, ExtensionRegistry registry, boolean persist) {
+		super(registry, persist);
 
 		setObjectId(self);
 		this.contributorId = contributorId;
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElementHandle.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElementHandle.java
index c26e121..38320f1 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElementHandle.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ConfigurationElementHandle.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -28,8 +28,8 @@
 		return (ConfigurationElement) objectManager.getObject(getId(), RegistryObjectManager.CONFIGURATION_ELEMENT);
 	}
 
-	public boolean isDynamic() {
-		return getConfigurationElement().isDynamic();
+	protected boolean shouldPersist() {
+		return getConfigurationElement().shouldPersist();
 	}
 
 	public String getAttribute(String propertyName) {
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Contribution.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Contribution.java
index cc375ea..7dfdf32 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Contribution.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Contribution.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -11,6 +11,7 @@
 package org.eclipse.core.internal.registry;
 
 import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.InvalidRegistryObjectException;
 
 // This object is used to keep track on a contributor basis of the extension and extension points being contributed.
 // It is mainly used on removal so we can quickly  find objects to remove.
@@ -29,7 +30,7 @@
 	private String namespaceOwnerId = null;
 
 	// indicates if this contribution needs to be saved in the registry cache
-	protected boolean isDynamic;
+	protected boolean persist;
 
 	// This array stores the identifiers of both the extension points and the extensions.
 	// The array has always a minimum size of 2.
@@ -40,24 +41,24 @@
 	static final public byte EXTENSION_POINT = 0;
 	static final public byte EXTENSION = 1;
 
-	protected Contribution(String contributorId, ExtensionRegistry registry, boolean dynamic) {
+	protected Contribution(String contributorId, ExtensionRegistry registry, boolean persist) {
 		this.contributorId = contributorId;
 		this.registry = registry;
-		this.isDynamic = dynamic;
+		this.persist = persist;
 	}
 
 	void mergeContribution(Contribution addContribution) {
 		Assert.isTrue(contributorId.equals(addContribution.contributorId));
 		Assert.isTrue(registry == addContribution.registry);
 
-		// isDynamic?
+		// persist?
 		// Old New Result
-		// F   F   F
-		// F   T   F
-		// T   F   F	=> the only situation where isDynamic status needs to be adjusted 
-		// T   T   T
-		if (isDynamic() && !addContribution.isDynamic())
-			isDynamic = false;
+		//  F   F   F
+		//  F   T   T	=> needs to be adjusted
+		//  T   F   T 
+		//  T   T   T
+		if (shouldPersist() != addContribution.shouldPersist())
+			persist = true;
 
 		int[] existing = getRawChildren();
 		int[] addition = addContribution.getRawChildren();
@@ -130,7 +131,53 @@
 		return contributorId.equals(((Contribution) other).contributorId);
 	}
 
-	public boolean isDynamic() {
-		return isDynamic;
+	public boolean shouldPersist() {
+		return persist;
+	}
+
+	public void unlinkChild(int id) {
+		// find index of the child being unlinked:
+		int index = -1;
+		for (int i = 2; i < children.length; i++) {
+			if (children[i] == id) {
+				index = i;
+				break;
+			}
+		}
+		if (index == -1)
+			throw new InvalidRegistryObjectException();
+
+		// copy all array except one element at index
+		int[] result = new int[children.length - 1];
+		System.arraycopy(children, 0, result, 0, index);
+		System.arraycopy(children, index + 1, result, index, children.length - index - 1);
+
+		// fix sizes
+		if (index < children[EXTENSION_POINT] + 2)
+			result[EXTENSION_POINT]--;
+		else
+			result[EXTENSION]--;
+
+		children = result;
+	}
+
+	/**
+	 * Contribution is empty if it has no children.
+	 */
+	public boolean isEmpty() {
+		return (children[EXTENSION_POINT] == 0 || children[EXTENSION] == 0);
+	}
+
+	/**
+	 * Find if this contribution has a children with ID = id.
+	 * @param id possible ID of the child
+	 * @return true: contribution has this child
+	 */
+	public boolean hasChild(int id) {
+		for (int i = 2; i < children.length; i++) {
+			if (children[i] == id)
+				return true;
+		}
+		return false;
 	}
 }
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Extension.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Extension.java
index a8da6df..e7e385a 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Extension.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/Extension.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 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
@@ -30,12 +30,12 @@
 	private static final byte XPT_NAME = 1; // The fully qualified name of the extension point to which this extension is attached to
 	private static final int EXTRA_SIZE = 2;
 
-	protected Extension(ExtensionRegistry registry, boolean isDynamic) {
-		super(registry, isDynamic);
+	protected Extension(ExtensionRegistry registry, boolean persist) {
+		super(registry, persist);
 	}
 
-	protected Extension(int self, String simpleId, String namespace, int[] children, int extraData, ExtensionRegistry registry, boolean isDynamic) {
-		super(registry, isDynamic);
+	protected Extension(int self, String simpleId, String namespace, int[] children, int extraData, ExtensionRegistry registry, boolean persist) {
+		super(registry, persist);
 
 		setObjectId(self);
 		this.simpleId = simpleId;
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionHandle.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionHandle.java
index 7f0ee9c..403a884 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionHandle.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionHandle.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -28,8 +28,8 @@
 		return (Extension) objectManager.getObject(getId(), RegistryObjectManager.EXTENSION);
 	}
 
-	public boolean isDynamic() {
-		return getExtension().isDynamic();
+	protected boolean shouldPersist() {
+		return getExtension().shouldPersist();
 	}
 
 	public String getNamespace() {
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPoint.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPoint.java
index 6f9b583..c883e01 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPoint.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 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
@@ -31,12 +31,12 @@
 	private static final byte CONTRIBUTOR_ID = 4; //The namespace owner contributing the extension point
 	private static final int EXTRA_SIZE = 5;
 
-	protected ExtensionPoint(ExtensionRegistry registry, boolean isDynamic) {
-		super(registry, isDynamic);
+	protected ExtensionPoint(ExtensionRegistry registry, boolean persist) {
+		super(registry, persist);
 	}
 
-	protected ExtensionPoint(int self, int[] children, int dataOffset, ExtensionRegistry registry, boolean isDynamic) {
-		super(registry, isDynamic);
+	protected ExtensionPoint(int self, int[] children, int dataOffset, ExtensionRegistry registry, boolean persist) {
+		super(registry, persist);
 
 		setObjectId(self);
 		setRawChildren(children);
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPointHandle.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPointHandle.java
index 4160692..d3b8496 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPointHandle.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionPointHandle.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -33,8 +33,8 @@
 		return getExtensionPoint().getNamespace();
 	}
 
-	public boolean isDynamic() {
-		return getExtensionPoint().isDynamic();
+	protected boolean shouldPersist() {
+		return getExtensionPoint().shouldPersist();
 	}
 
 	public IExtension getExtension(String extensionId) {
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java
index 14d7bbe..3fda664 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 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
@@ -14,8 +14,8 @@
 import java.lang.reflect.Array;
 import java.util.*;
 import javax.xml.parsers.ParserConfigurationException;
-import org.eclipse.core.internal.registry.spi.ExtensionDescription;
-import org.eclipse.core.internal.registry.spi.ExtensionProperty;
+import org.eclipse.core.internal.registry.spi.ConfigurationElementDescription;
+import org.eclipse.core.internal.registry.spi.ConfigurationElementAttribute;
 import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.adaptor.FileManager;
 import org.eclipse.equinox.registry.*;
@@ -68,7 +68,7 @@
 	protected TableReader theTableReader = new TableReader(this);
 
 	private Object masterToken; // use to get full control of the registry; objects created as "static" 
-	private Object userToken; // use to add dynamic contributions
+	private Object userToken; // use to modify non-persisted registry elements
 
 	/////////////////////////////////////////////////////////////////////////////////////////
 	// Registry strategies
@@ -108,7 +108,7 @@
 	 * interested on changes in the given plug-in.
 	 * </p>
 	 */
-	public void add(Contribution element) {
+	private void add(Contribution element) {
 		access.enterWrite();
 		try {
 			basicAdd(element, true);
@@ -118,17 +118,6 @@
 		}
 	}
 
-	public void add(Contribution[] elements) {
-		access.enterWrite();
-		try {
-			for (int i = 0; i < elements.length; i++)
-				basicAdd(elements[i], true);
-			fireRegistryChangeEvent();
-		} finally {
-			access.exitWrite();
-		}
-	}
-
 	/* Utility method to help with array concatenations */
 	static Object concatArrays(Object a, Object b) {
 		Object[] result = (Object[]) Array.newInstance(a.getClass().getComponentType(), Array.getLength(a) + Array.getLength(b));
@@ -902,29 +891,36 @@
 		}
 	}
 
-	//////////////////////////////////////////////////////////////////////////////////////
-	// Modifiable portion
-
-	public boolean addContribution(InputStream is, String contributorId, String contributionName, ResourceBundle b, Object key) {
-		// check access
-		if (!strategy.isModifiable() && masterToken != key && userToken != key)
-			throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.addXMLContribution() method. Check if proper access token is supplied."); //$NON-NLS-1$
-		//  determine contribution nature
-		boolean isDynamic;
+	/**
+	 * Access check for add/remove operations:
+	 * a) for modifiable registry key is not required (null is fine)
+	 * b) for non-modifiable registry master key allows all operations 
+	 * c) for non-modifiable registry user key allows modifications of non-persisted elements
+	 * 
+	 * @param key key to the registry supplied by the user
+	 * @param persist true if operation affects persisted elements 
+	 * @return true is the key grants read/write access to the registry
+	 */
+	private boolean checkReadWriteAccess(Object key, boolean persist) {
+		if (strategy.isModifiable())
+			return true;
 		if (masterToken == key)
-			isDynamic = false;
-		else if (userToken == key)
-			isDynamic = true;
-		else
-			isDynamic = false; // default: for modifiable registry contributions are static
+			return true;
+		if (userToken == key && !persist)
+			return true;
+		return false;
+	}
 
+	public boolean addContribution(InputStream is, String contributorId, boolean persist, String contributionName, ResourceBundle b, Object key) {
+		if (!checkReadWriteAccess(key, persist))
+			throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.addXMLContribution() method. Check if proper access token is supplied."); //$NON-NLS-1$
 		if (contributionName == null)
 			contributionName = ""; //$NON-NLS-1$
 		String ownerName = getNamespace(contributorId);
 		String message = NLS.bind(RegistryMessages.parse_problems, ownerName);
 		MultiStatus problems = new MultiStatus(RegistryMessages.OWNER_NAME, ExtensionsParser.PARSE_PROBLEM, message, null);
 		ExtensionsParser parser = new ExtensionsParser(problems, this);
-		Contribution contribution = getElementFactory().createContribution(contributorId, isDynamic);
+		Contribution contribution = getElementFactory().createContribution(contributorId, persist);
 
 		try {
 			parser.parseManifest(strategy.getXMLParser(), new InputSource(is), contributionName, getObjectManager(), contribution, b);
@@ -948,10 +944,7 @@
 				// nothing to do
 			}
 		}
-
-		// Do not synchronize on registry here because the registry handles
-		// the synchronization for us in registry.add		
-		add(contribution);
+		add(contribution); // the add() method does synchronization
 		return true;
 	}
 
@@ -961,35 +954,51 @@
 	}
 
 	/**
-	 * Creates an extension point.
+	 * Adds an extension point to the extension registry.
+	 * <p>
+	 * If the registry is not modifiable, this method is an access controlled method. 
+	 * Proper token should be passed as an argument for non-modifiable registries.
+	 * </p>
+	 * @see org.eclipse.equinox.registry.spi.RegistryStrategy#isModifiable()
 	 * 
-	 * @param contributorId - Id of the supplier of this extension point
-	 * @param extensionPointId - Id of the extension point. If non-qualified names is supplied,
-	 * it will be converted internally into a fully qualified name.
-	 * @param extensionPointLabel- display string for the extension point
-	 * @param schemaLocation - points to the location of the XML schema file
+	 * @param identifier Id of the extension point. If non-qualified names is supplied,
+	 * it will be converted internally into a fully qualified name
+	 * @param contributorId ID of the supplier of this contribution
+	 * @param persist indicates if contribution should be stored in the registry cache. If false,
+	 * contribution is not persisted in the registry cache and is lost on Eclipse restart
+	 * @param label display string for the extension point
+	 * @param schemaReference reference to the extension point schema. The schema reference 
+	 * is a URL path relative to the plug-in installation URL. May be null
+	 * @param token the key used to check permissions. Two registry keys are set in the registry
+	 * constructor {@link RegistryFactory#createRegistry(org.eclipse.equinox.registry.spi.RegistryStrategy, Object, Object)}: 
+	 * master token and a user token. Master token allows all operations; user token 
+	 * allows non-persisted registry elements to be modified.
+	 * @throws IllegalArgumentException if incorrect token is passed in
 	 */
-	public void createExtensionPoint(String contributorId, String extensionPointId, String extensionPointLabel, String schemaLocation) {
-
+	public void addExtensionPoint(String identifier, String contributorId, boolean persist, String label, String schemaReference, Object token) throws IllegalArgumentException {
+		if (!checkReadWriteAccess(token, persist))
+			throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.addExtensionPoint() method. Check if proper access token is supplied."); //$NON-NLS-1$
 		// Extension point Id might not be null
-		if (extensionPointId == null) {
-			String message = NLS.bind(RegistryMessages.create_failedExtensionPoint, extensionPointLabel);
+		if (identifier == null) {
+			String message = NLS.bind(RegistryMessages.create_failedExtensionPoint, label);
 			log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, message, null));
 		}
+		if (schemaReference == null)
+			schemaReference = ""; //$NON-NLS-1$
 
 		// prepare namespace information
 		String namespaceName = getNamespace(contributorId);
 		String namespaceOwnerId = getNamespaceOwnerId(contributorId);
 
 		// addition wraps in a contribution
-		Contribution contribution = getElementFactory().createContribution(contributorId, true);
+		Contribution contribution = getElementFactory().createContribution(contributorId, persist);
 
-		ExtensionPoint currentExtPoint = getElementFactory().createExtensionPoint(true);
-		String uniqueId = namespaceName + '.' + extensionPointId;
+		ExtensionPoint currentExtPoint = getElementFactory().createExtensionPoint(persist);
+		String uniqueId = namespaceName + '.' + identifier;
 		currentExtPoint.setUniqueIdentifier(uniqueId);
-		String labelNLS = translate(extensionPointLabel, null);
+		String labelNLS = translate(label, null);
 		currentExtPoint.setLabel(labelNLS);
-		currentExtPoint.setSchema(schemaLocation);
+		currentExtPoint.setSchema(schemaReference);
 
 		getObjectManager().addExtensionPoint(currentExtPoint, true);
 
@@ -1009,29 +1018,42 @@
 	}
 
 	/**
-	 * Creates an extension.
+	 * Adds an extension to the extension registry.
+	 * <p>
+	 * If the registry is not modifiable, this method is an access controlled method. 
+	 * Proper token should be passed as an argument for non-modifiable registries.
+	 * </p>
+	 * @see org.eclipse.equinox.registry.spi.RegistryStrategy#isModifiable()
+	 * @see org.eclipse.core.internal.registry.spi.ConfigurationElementDescription
 	 * 
-	 * @see ExtensionDescription
-	 * 
-	 * @param contributorId - Id of the supplier of this extension
-	 * @param extensionId - Id of the extension. If non-qualified name is supplied,
+	 * @param identifier Id of the extension. If non-qualified name is supplied,
 	 * it will be converted internally into a fully qualified name
-	 * @param extensionLabel - display string for this extension
-	 * @param extensionPointId - Id of the point being extended. If non-qualified
+	 * @param contributorId ID of the supplier of this contribution
+	 * @param persist indicates if contribution should be stored in the registry cache. If false,
+	 * contribution is not persisted in the registry cache and is lost on Eclipse restart
+	 * @param label display string for this extension
+	 * @param extensionPointId Id of the point being extended. If non-qualified
 	 * name is supplied, it is assumed to have the same contributorId as this extension
-	 * @param description - contents of the extension
+	 * @param configurationElements contents of the extension
+	 * @param token the key used to check permissions. Two registry keys are set in the registry
+	 * constructor {@link RegistryFactory#createRegistry(org.eclipse.equinox.registry.spi.RegistryStrategy, Object, Object)}: 
+	 * master token and a user token. Master token allows all operations; user token 
+	 * allows non-persisted registry elements to be modified.
+	 * @throws IllegalArgumentException if incorrect token is passed in
 	 */
-	public void createExtension(String contributorId, String extensionId, String extensionLabel, String extensionPointId, ExtensionDescription description) {
+	public void addExtension(String identifier, String contributorId, boolean persist, String label, String extensionPointId, ConfigurationElementDescription configurationElements, Object token) throws IllegalArgumentException {
+		if (!checkReadWriteAccess(token, persist))
+			throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.addExtensionPoint() method. Check if proper access token is supplied."); //$NON-NLS-1$
 		// prepare namespace information
 		String namespaceName = getNamespace(contributorId);
 		String namespaceOwnerId = getNamespaceOwnerId(contributorId);
 
 		// addition wraps in a contribution
-		Contribution contribution = getElementFactory().createContribution(contributorId, true);
+		Contribution contribution = getElementFactory().createContribution(contributorId, persist);
 
-		Extension currentExtension = getElementFactory().createExtension(true);
-		currentExtension.setSimpleIdentifier(extensionId);
-		String extensionLabelNLS = translate(extensionLabel, null);
+		Extension currentExtension = getElementFactory().createExtension(persist);
+		currentExtension.setSimpleIdentifier(identifier);
+		String extensionLabelNLS = translate(label, null);
 		currentExtension.setLabel(extensionLabelNLS);
 
 		String targetExtensionPointId;
@@ -1043,7 +1065,7 @@
 
 		getObjectManager().add(currentExtension, true);
 
-		createExtensionData(namespaceOwnerId, description, currentExtension);
+		createExtensionData(namespaceOwnerId, configurationElements, currentExtension, persist);
 
 		currentExtension.setNamespaceName(namespaceName);
 
@@ -1058,15 +1080,15 @@
 	}
 
 	// Fill in the actual content of this extension
-	private void createExtensionData(String namespaceOwnerId, ExtensionDescription description, RegistryObject parent) {
-		ConfigurationElement currentConfigurationElement = getElementFactory().createConfigurationElement(true);
+	private void createExtensionData(String namespaceOwnerId, ConfigurationElementDescription description, RegistryObject parent, boolean persist) {
+		ConfigurationElement currentConfigurationElement = getElementFactory().createConfigurationElement(persist);
 		currentConfigurationElement.setNamespaceOwnerId(namespaceOwnerId);
-		currentConfigurationElement.setName(description.getElementName());
+		currentConfigurationElement.setName(description.getName());
 
-		if (description.hasProperties()) {
-			ExtensionProperty[] descriptionProperties = description.getProperties();
+		ConfigurationElementAttribute[] descriptionProperties = description.getAttributes();
+
+		if (descriptionProperties != null && descriptionProperties.length != 0) {
 			int len = descriptionProperties.length;
-
 			String[] properties = new String[len * 2];
 			for (int i = 0; i < len; i++) {
 				properties[i * 2] = descriptionProperties[i].getName();
@@ -1083,10 +1105,10 @@
 		getObjectManager().add(currentConfigurationElement, true);
 
 		// process children
-		ExtensionDescription[] children = description.getChildren();
+		ConfigurationElementDescription[] children = description.getChildren();
 		if (children != null) {
 			for (int i = 0; i < children.length; i++) {
-				createExtensionData(namespaceOwnerId, children[i], currentConfigurationElement);
+				createExtensionData(namespaceOwnerId, children[i], currentConfigurationElement, persist);
 			}
 		}
 
@@ -1102,6 +1124,55 @@
 		currentConfigurationElement.setParentType(parent instanceof ConfigurationElement ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.EXTENSION);
 	}
 
+	public boolean removeExtension(IExtension extension, Object token) throws IllegalArgumentException {
+		if (!(extension instanceof ExtensionHandle))
+			return false;
+		return removeObject(((ExtensionHandle) extension).getObject(), false, token);
+	}
+
+	public boolean removeExtensionPoint(IExtensionPoint extensionPoint, Object token) throws IllegalArgumentException {
+		if (!(extensionPoint instanceof ExtensionPointHandle))
+			return false;
+		return removeObject(((ExtensionPointHandle) extensionPoint).getObject(), true, token);
+	}
+
+	private boolean removeObject(RegistryObject registryObject, boolean isExtensionPoint, Object token) {
+		if (!checkReadWriteAccess(token, registryObject.shouldPersist()))
+			throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.removeExtension() method. Check if proper access token is supplied."); //$NON-NLS-1$
+		int id = registryObject.getObjectId();
+
+		access.enterWrite();
+		try {
+			String namespace;
+			if (isExtensionPoint)
+				namespace = removeExtensionPoint(id);
+			else
+				namespace = removeExtension(id);
+
+			Map removed = new HashMap(1);
+			removed.put(new Integer(id), registryObject);
+			registryObjects.removeObjects(removed);
+			registryObjects.addNavigableObjects(removed);
+			getDelta(namespace).setObjectManager(registryObjects.createDelegatingObjectManager(removed));
+
+			String[] possibleContributors = strategy.getNamespaceContributors(namespace);
+			for (int i = 0; i < possibleContributors.length; i++) {
+				Contribution contribution = registryObjects.getContribution(possibleContributors[i]);
+				if (contribution.hasChild(id)) {
+					contribution.unlinkChild(id);
+					if (contribution.isEmpty())
+						registryObjects.removeContribution(possibleContributors[i]);
+					break;
+				}
+			}
+
+			fireRegistryChangeEvent();
+		} finally {
+			access.exitWrite();
+		}
+		return true;
+	}
+
 	public void setCompatibilityStrategy(ICompatibilityStrategy strategy) {
 		compatibilityStrategy = strategy;
 	}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionsParser.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionsParser.java
index 81061c8..5d540d2 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionsParser.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionsParser.java
@@ -278,7 +278,7 @@
 		configurationElementValue = null;
 
 		// create a new Configuration Element and push it onto the object stack
-		ConfigurationElement currentConfigurationElement = registry.getElementFactory().createConfigurationElement(namespace.isDynamic());
+		ConfigurationElement currentConfigurationElement = registry.getElementFactory().createConfigurationElement(namespace.shouldPersist());
 		currentConfigurationElement.setNamespaceOwnerId(namespace.getNamespaceOwnerId());
 		objectStack.push(currentConfigurationElement);
 		currentConfigurationElement.setName(elementName);
@@ -387,7 +387,7 @@
 	}
 
 	private void parseExtensionAttributes(Attributes attributes) {
-		Extension currentExtension = registry.getElementFactory().createExtension(namespace.isDynamic());
+		Extension currentExtension = registry.getElementFactory().createExtension(namespace.shouldPersist());
 		objectStack.push(currentExtension);
 
 		// Process Attributes
@@ -446,7 +446,7 @@
 	}
 
 	private void parseExtensionPointAttributes(Attributes attributes) {
-		ExtensionPoint currentExtPoint = registry.getElementFactory().createExtensionPoint(namespace.isDynamic());
+		ExtensionPoint currentExtPoint = registry.getElementFactory().createExtensionPoint(namespace.shouldPersist());
 
 		// Process Attributes
 		int len = (attributes != null) ? attributes.getLength() : 0;
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/HashtableOfStringAndInt.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/HashtableOfStringAndInt.java
index 711ce11..78ff58c 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/HashtableOfStringAndInt.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/HashtableOfStringAndInt.java
@@ -166,11 +166,11 @@
 	/**
 	 * Filtered save: outputs only elements with values not in the excluded list.
 	 */
-	public void save(DataOutputStream out, TableWriter writer) throws IOException {
+	public void save(DataOutputStream out, RegistryObjectManager objectManager) throws IOException {
 		HashtableOfStringAndInt filteredHashtable = new HashtableOfStringAndInt((int) (elementSize * GROWTH_FACTOR));
 		String currentKey;
 		for (int i = keyTable.length; --i >= 0;)
-			if ((currentKey = keyTable[i]) != null && writer.shouldCache(valueTable[i]))
+			if ((currentKey = keyTable[i]) != null && objectManager.shouldPersist(valueTable[i]))
 				filteredHashtable.put(currentKey, valueTable[i]);
 		filteredHashtable.save(out);
 	}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObject.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObject.java
index f3fa8e8..65fac92 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObject.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObject.java
@@ -20,24 +20,24 @@
 	//The children of the element
 	protected int[] children = RegistryObjectManager.EMPTY_INT_ARRAY;
 
-	// The field combines offset, dynamic flag, and no offset flag
+	// The field combines offset, persistence flag, and no offset flag
 	private int extraDataOffset = EMPTY_MASK;
 
 	// it is assumed that int has 32 bits (bits #0 to #31);
 	// bits #0 - #29 are the offset (limited to about 1Gb)
-	// bit #30 - registry object is dynamic if set
+	// bit #30 - persistance flag
 	// bit #31 - registry object has no extra data offset
 	// the bit#31 is a sign bit; bit#30 is the highest mantissa bit
 	static final int EMPTY_MASK = 0x80000000; // only taking bit #31
-	static final int DYNAMIC_MASK = 0x40000000; // only taking bit #30
+	static final int PERSIST_MASK = 0x40000000; // only taking bit #30
 	static final int OFFSET_MASK = 0x3FFFFFFF; // all bits but #30, #31
 
 	//The registry that owns this object
 	protected ExtensionRegistry registry;
 
-	protected RegistryObject(ExtensionRegistry registry, boolean isDynamic) {
+	protected RegistryObject(ExtensionRegistry registry, boolean persist) {
 		this.registry = registry;
-		setDynamic(isDynamic);
+		setPersist(persist);
 	}
 
 	void setRawChildren(int[] values) {
@@ -70,15 +70,15 @@
 		return objectId == ((RegistryObject) other).objectId;
 	}
 
-	protected boolean isDynamic() {
-		return (extraDataOffset & DYNAMIC_MASK) == DYNAMIC_MASK;
+	protected boolean shouldPersist() {
+		return (extraDataOffset & PERSIST_MASK) == PERSIST_MASK;
 	}
 
-	private void setDynamic(boolean dynamic) {
-		if (dynamic)
-			extraDataOffset |= DYNAMIC_MASK;
+	private void setPersist(boolean persist) {
+		if (persist)
+			extraDataOffset |= PERSIST_MASK;
 		else
-			extraDataOffset &= ~DYNAMIC_MASK;
+			extraDataOffset &= ~PERSIST_MASK;
 	}
 
 	protected boolean noExtraData() {
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectFactory.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectFactory.java
index 603bb50..3b078b2 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectFactory.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectFactory.java
@@ -24,37 +24,37 @@
 
 	////////////////////////////////////////////////////////////////////////////
 	// Contribution
-	public Contribution createContribution(String contributorId, boolean isDynamic) {
-		return new Contribution(contributorId, registry, isDynamic);
+	public Contribution createContribution(String contributorId, boolean persist) {
+		return new Contribution(contributorId, registry, persist);
 	}
 
 	////////////////////////////////////////////////////////////////////////////
 	// Extension point
-	public ExtensionPoint createExtensionPoint(boolean isDynamic) {
-		return new ExtensionPoint(registry, isDynamic);
+	public ExtensionPoint createExtensionPoint(boolean persist) {
+		return new ExtensionPoint(registry, persist);
 	}
 
-	public ExtensionPoint createExtensionPoint(int self, int[] children, int dataOffset, boolean isDynamic) {
-		return new ExtensionPoint(self, children, dataOffset, registry, isDynamic);
+	public ExtensionPoint createExtensionPoint(int self, int[] children, int dataOffset, boolean persist) {
+		return new ExtensionPoint(self, children, dataOffset, registry, persist);
 	}
 
 	////////////////////////////////////////////////////////////////////////////
 	// Extension
-	public Extension createExtension(boolean isDynamic) {
-		return new Extension(registry, isDynamic);
+	public Extension createExtension(boolean persist) {
+		return new Extension(registry, persist);
 	}
 
-	public Extension createExtension(int self, String simpleId, String namespace, int[] children, int extraData, boolean isDynamic) {
-		return new Extension(self, simpleId, namespace, children, extraData, registry, isDynamic);
+	public Extension createExtension(int self, String simpleId, String namespace, int[] children, int extraData, boolean persist) {
+		return new Extension(self, simpleId, namespace, children, extraData, registry, persist);
 	}
 
 	////////////////////////////////////////////////////////////////////////////
 	// Configuration element
-	public ConfigurationElement createConfigurationElement(boolean isDynamic) {
-		return new ConfigurationElement(registry, isDynamic);
+	public ConfigurationElement createConfigurationElement(boolean persist) {
+		return new ConfigurationElement(registry, persist);
 	}
 
-	public ConfigurationElement createConfigurationElement(int self, String contributorId, String name, String[] propertiesAndValue, int[] children, int extraDataOffset, int parent, byte parentType, boolean isDynamic) {
-		return new ConfigurationElement(self, contributorId, name, propertiesAndValue, children, extraDataOffset, parent, parentType, registry, isDynamic);
+	public ConfigurationElement createConfigurationElement(int self, String contributorId, String name, String[] propertiesAndValue, int[] children, int extraDataOffset, int parent, byte parentType, boolean persist) {
+		return new ConfigurationElement(self, contributorId, name, propertiesAndValue, children, extraDataOffset, parent, parentType, registry, persist);
 	}
 }
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectManager.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectManager.java
index dc4f7f6..d929431 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectManager.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryObjectManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -216,11 +216,11 @@
 	// of this method would have to retrieved the object from disk and check
 	// its "dynamic" status. The problem is that id alone is not enough to get the object
 	// from the disk; object type is needed as well.
-	public boolean isDynamic(int id) {
+	public boolean shouldPersist(int id) {
 		Object result = cache.get(id);
 		if (result != null)
-			return ((RegistryObject) result).isDynamic();
-		return false;
+			return ((RegistryObject) result).shouldPersist();
+		return true;
 	}
 
 	public synchronized RegistryObject[] getObjects(int[] values, byte type) {
@@ -582,4 +582,11 @@
 	public ExtensionRegistry getRegistry() {
 		return registry;
 	}
+
+	synchronized Contribution getContribution(String id) {
+		KeyedElement tmp = newContributions.getByKey(id);
+		if (tmp == null)
+			tmp = getFormerContributions().getByKey(id);
+		return (Contribution) tmp;
+	}
 }
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableReader.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableReader.java
index b3e3ee9..3a83fc4 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableReader.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableReader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -162,7 +162,7 @@
 		int[] children = readArray(is);
 		if (actualContributorId == null)
 			actualContributorId = contributorId;
-		return getObjectFactory().createConfigurationElement(self, actualContributorId, name, propertiesAndValue, children, misc, parentId, parentType, false);
+		return getObjectFactory().createConfigurationElement(self, actualContributorId, name, propertiesAndValue, children, misc, parentId, parentType, true);
 	}
 
 	public Object loadThirdLevelConfigurationElements(int offset, RegistryObjectManager objectManager) {
@@ -232,7 +232,7 @@
 		String namespace = readStringOrNull(mainInput);
 		int[] children = readArray(mainInput);
 		int extraData = mainInput.readInt();
-		return getObjectFactory().createExtension(self, simpleId, namespace, children, extraData, false);
+		return getObjectFactory().createExtension(self, simpleId, namespace, children, extraData, true);
 	}
 
 	public ExtensionPoint loadExtensionPointTree(int offset, RegistryObjectManager objects) {
@@ -282,7 +282,7 @@
 		int self = mainInput.readInt();
 		int[] children = readArray(mainInput);
 		int extraData = mainInput.readInt();
-		return getObjectFactory().createExtensionPoint(self, children, extraData, false);
+		return getObjectFactory().createExtensionPoint(self, children, extraData, true);
 	}
 
 	private int[] readArray(DataInputStream in) throws IOException {
@@ -364,7 +364,7 @@
 				KeyedHashSet result = new KeyedHashSet(size);
 				for (int i = 0; i < size; i++) {
 					String contributorId = readStringOrNull(namespaceInput);
-					Contribution n = getObjectFactory().createContribution(contributorId, false);
+					Contribution n = getObjectFactory().createContribution(contributorId, true);
 					n.setRawChildren(readArray(namespaceInput));
 					result.add(n);
 				}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableWriter.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableWriter.java
index 3c6cdc9..9f8b71c 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableWriter.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/TableWriter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 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
@@ -149,27 +149,27 @@
 		// get count of contributions that will be cached
 		int cacheSize = 0;
 		for (int i = 0; i < newElements.length; i++) {
-			if (shouldCache((Contribution) newElements[i]))
+			if (((Contribution) newElements[i]).shouldPersist())
 				cacheSize++;
 		}
 		for (int i = 0; i < formerElements.length; i++) {
-			if (shouldCache((Contribution) formerElements[i]))
+			if (((Contribution) formerElements[i]).shouldPersist())
 				cacheSize++;
 		}
 		outputNamespace.writeInt(cacheSize);
 
 		for (int i = 0; i < newElements.length; i++) {
 			Contribution element = (Contribution) newElements[i];
-			if (shouldCache(element)) {
+			if (element.shouldPersist()) {
 				writeStringOrNull(element.getContributorId(), outputNamespace);
-				saveArray(element.getRawChildren(), outputNamespace);
+				saveArray(filter(element.getRawChildren()), outputNamespace);
 			}
 		}
 		for (int i = 0; i < formerElements.length; i++) {
 			Contribution element = (Contribution) formerElements[i];
-			if (shouldCache(element)) {
+			if (element.shouldPersist()) {
 				writeStringOrNull(element.getContributorId(), outputNamespace);
-				saveArray(element.getRawChildren(), outputNamespace);
+				saveArray(filter(element.getRawChildren()), outputNamespace);
 			}
 		}
 		outputNamespace.flush();
@@ -183,7 +183,7 @@
 		writeCacheHeader(outputTable, registryTimeStamp);
 		outputTable.writeInt(objectManager.getNextId());
 		offsets.save(outputTable);
-		objectManager.getExtensionPoints().save(outputTable, this); // uses writer to filter contents
+		objectManager.getExtensionPoints().save(outputTable, objectManager); // uses writer to filter contents
 		outputTable.flush();
 		fosTable.getFD().sync();
 		outputTable.close();
@@ -214,7 +214,7 @@
 	}
 
 	private void saveExtensionPoint(ExtensionPointHandle xpt) throws IOException {
-		if (!shouldCache(xpt))
+		if (!xpt.shouldPersist())
 			return;
 		//save the file position
 		offsets.put(xpt.getId(), mainOutput.size());
@@ -228,7 +228,7 @@
 	}
 
 	private void saveExtension(ExtensionHandle ext, DataOutputStream outputStream) throws IOException {
-		if (!shouldCache(ext))
+		if (!ext.shouldPersist())
 			return;
 		offsets.put(ext.getId(), outputStream.size());
 		outputStream.writeInt(ext.getId());
@@ -248,7 +248,7 @@
 
 	//Save Configuration elements depth first
 	private void saveConfigurationElement(ConfigurationElementHandle element, DataOutputStream outputStream, DataOutputStream extraOutputStream, int depth) throws IOException {
-		if (!shouldCache(element))
+		if (!element.shouldPersist())
 			return;
 		DataOutputStream currentOutput = outputStream;
 		if (depth > 2)
@@ -285,7 +285,7 @@
 			int countCElements = 0;
 			boolean[] save = new boolean[ces.length];
 			for (int j = 0; j < ces.length; j++) {
-				if (shouldCache((ConfigurationElementHandle) ces[j])) {
+				if (((ConfigurationElementHandle) ces[j]).shouldPersist()) {
 					save[j] = true;
 					countCElements++;
 				} else
@@ -353,42 +353,12 @@
 		registry.log(status);
 	}
 
-	private boolean shouldCache(ExtensionPointHandle extensionPoint) {
-		if (extensionPoint.isDynamic())
-			return saveDynamic();
-		return true;
-	}
-
-	private boolean shouldCache(ExtensionHandle extension) {
-		if (extension.isDynamic())
-			return saveDynamic();
-		return true;
-	}
-
-	private boolean shouldCache(ConfigurationElementHandle configElement) {
-		if (configElement.isDynamic())
-			return saveDynamic();
-		return true;
-	}
-
-	private boolean shouldCache(Contribution contribution) {
-		if (contribution.isDynamic())
-			return saveDynamic();
-		return true;
-	}
-
-	public boolean shouldCache(int registryObjectId) {
-		if (objectManager.isDynamic(registryObjectId))
-			return saveDynamic();
-		return true;
-	}
-
 	// Filters out registry objects that should not be cached
 	private int[] filter(int[] input) {
 		boolean[] save = new boolean[input.length];
 		int resultSize = 0;
 		for (int i = 0; i < input.length; i++) {
-			if (shouldCache(input[i])) {
+			if (objectManager.shouldPersist(input[i])) {
 				save[i] = true;
 				resultSize++;
 			} else
@@ -404,9 +374,4 @@
 		}
 		return result;
 	}
-
-	// Regulates if we are saving dynamic registry objects
-	public boolean saveDynamic() {
-		return false;
-	}
 }
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EclipseBundleListener.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EclipseBundleListener.java
index 7bb22e6..12a70d3 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EclipseBundleListener.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EclipseBundleListener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -136,7 +136,7 @@
 			//Ignore the exception
 		}
 
-		registry.addContribution(is, contributorId, manifestName, b, token);
+		registry.addContribution(is, contributorId, true, manifestName, b, token);
 
 		// bug 70941
 		// need to ensure we can find resource bundles from fragments
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ConfigurationElementAttribute.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ConfigurationElementAttribute.java
new file mode 100644
index 0000000..03ddd53
--- /dev/null
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ConfigurationElementAttribute.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 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.core.internal.registry.spi;
+
+import org.eclipse.equinox.registry.IConfigurationElement;
+
+/**
+ * Describes properties of configuration elements to be added to the registry. 
+ * Properties are represented as pairs of strings: {attribute name; attribute value}.
+ * <p>
+ * It is expected that both attribute name and attribute value are not null.
+ * </p>
+ * <p>
+ * This class can be instantited.
+ * </p>
+ * <p>
+ * This class is not intended to be subclassed.
+ * </p>
+ * @see ConfigurationElementDescription
+ * @see IConfigurationElement
+ */
+public final class ConfigurationElementAttribute {
+
+	/**
+	 * Attribute name.
+	 * @see IConfigurationElement#getAttributeNames()
+	 */
+	private String name;
+
+	/**
+	 * Attribute value.
+	 * @see IConfigurationElement#getAttributeAsIs(String)
+	 */
+	private String value;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param name attribute name
+	 * @param value attribute value
+	 */
+	public ConfigurationElementAttribute(String name, String value) {
+		this.name = name;
+		this.value = value;
+	}
+
+	/**
+	 * Returns attribute name.
+	 * @return attribute name
+	 * @see IConfigurationElement#getAttributeNames()
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns value of the attribute.
+	 * @return attribute value
+	 * @see IConfigurationElement#getAttributeAsIs(String)
+	 */
+	public String getValue() {
+		return value;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ConfigurationElementDescription.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ConfigurationElementDescription.java
new file mode 100644
index 0000000..c5118ce
--- /dev/null
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ConfigurationElementDescription.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 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.core.internal.registry.spi;
+
+import org.eclipse.equinox.registry.IConfigurationElement;
+
+/**
+ * Describes configuration elements (content of an extension) to be added to 
+ * the extension registry. Configuration element can contain attributes or 
+ * a String value. Configuration element can contain other configuration 
+ * elements (children).
+ * <p>
+ * It is expected that configuration element's name is not null. Attributes and 
+ * children of the extension description might be null; value might be null as well.
+ * </p>
+ * <p>
+ * This class can be instantiated.
+ * </p>
+ * <p>
+ * This class is not intended to be subclassed.
+ * </p>
+ * @see ConfigurationElementAttribute
+ */
+public final class ConfigurationElementDescription {
+
+	/**
+	 * Name of the configuration element.
+	 * @see IConfigurationElement#getName()
+	 */
+	private String name;
+
+	/**
+	 * Attributes of the configuration element.
+	 * @see IConfigurationElement#getAttribute(String)
+	 */
+	private ConfigurationElementAttribute[] attributes;
+
+	/**
+	 * String value to be stored in this configuration element.
+	 * @see IConfigurationElement#getValue()
+	 */
+	private String value;
+
+	/**
+	 * Children of the configuration element.
+	 * @see IConfigurationElement#getChildren() 
+	 */
+	private ConfigurationElementDescription[] children;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param name - name of the configuration element
+	 * @param attributes - attributes of the configuration element. Might be null.
+	 * @param value - string value to be stored. Might be null.
+	 * @param children - children of the configuration element. Might be null.
+	 * @see IConfigurationElement#getName()
+	 * @see IConfigurationElement#getChildren() 
+	 * @see IConfigurationElement#getAttribute(String)
+	 * @see IConfigurationElement#getValue()
+	 */
+	public ConfigurationElementDescription(String name, ConfigurationElementAttribute[] attributes, String value, ConfigurationElementDescription[] children) {
+		this.name = name;
+		this.attributes = attributes;
+		this.value = value;
+		this.children = children;
+	}
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param name - name of the configuration element
+	 * @param attribute - attribute of the configuration element. Might be null.
+	 * @param value - string value to be stored. Might be null.
+	 * @param children - children of the configuration element. Might be null.
+	 * @see IConfigurationElement#getName()
+	 * @see IConfigurationElement#getChildren() 
+	 * @see IConfigurationElement#getAttribute(String)
+	 * @see IConfigurationElement#getValue()
+	 */
+	public ConfigurationElementDescription(String name, ConfigurationElementAttribute attribute, String value, ConfigurationElementDescription[] children) {
+		this.name = name;
+		this.attributes = new ConfigurationElementAttribute[] {attribute};
+		this.value = value;
+		this.children = children;
+	}
+
+	/**
+	 * Returns children of the configuration element.
+	 * @return - children of the extension
+	 * @see IConfigurationElement#getChildren() 
+	 */
+	public ConfigurationElementDescription[] getChildren() {
+		return children;
+	}
+
+	/**
+	 * Returns name of the configuration element.
+	 * @return - extension name
+	 * @see IConfigurationElement#getName()
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns attributes of the configuration element.
+	 * @return - attributes of the extension description
+	 * @see IConfigurationElement#getAttribute(String)
+	 */
+	public ConfigurationElementAttribute[] getAttributes() {
+		return attributes;
+	}
+
+	/**
+	 * Returns string value stored in the configuration element.
+	 * @return - String value to be stored in the element
+	 * @see IConfigurationElement#getValue()
+	 */
+	public String getValue() {
+		return value;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ExtensionDescription.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ExtensionDescription.java
deleted file mode 100644
index c5b3f75..0000000
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ExtensionDescription.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005 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.core.internal.registry.spi;
-
-/**
- * Describes an extension to be added to the extension registry.
- * 
- * It is expected that extension name is not null. Properties and children of 
- * the extension description might be null; value might be null as well.
- * 
- * This class is not intended to be subclassed.
- * 
- * @since org.eclipse.equinox.registry 1.0
- */
-public final class ExtensionDescription {
-
-	/**
-	 * Name of the extension.
-	 */
-	private String elementName;
-
-	/**
-	 * Properties of the extension element. 
-	 * @see ExtensionProperty
-	 */
-	private ExtensionProperty[] properties;
-
-	/**
-	 * String value to be stored in this configuration element.
-	 */
-	private String value;
-
-	/**
-	 * Children of the extension element.
-	 */
-	private ExtensionDescription[] children;
-
-	/**
-	 * Constructor.
-	 * @param name - name of the extension
-	 * @param properties - properties of the extension
-	 * @param value - string value to be stored
-	 * @param children - children of the extension element
-	 */
-	public ExtensionDescription(String name, ExtensionProperty[] properties, String value, ExtensionDescription[] children) {
-		this.elementName = name;
-		this.properties = properties;
-		this.value = value;
-		this.children = children;
-	}
-
-	/**
-	 * Constructor.
-	 * @param name - name of the extension
-	 * @param property - property of the extension
-	 * @param value - string value to be stored
-	 * @param children - children of the extension element
-	 */
-	public ExtensionDescription(String name, ExtensionProperty property, String value, ExtensionDescription[] children) {
-		this.elementName = name;
-		this.properties = new ExtensionProperty[] {property};
-		this.value = value;
-		this.children = children;
-	}
-
-	/**
-	 * @return - children of the extension 
-	 */
-	public ExtensionDescription[] getChildren() {
-		return children;
-	}
-
-	/**
-	 * @return - extension name
-	 */
-	public String getElementName() {
-		return elementName;
-	}
-
-	/**
-	 * @return - properties of the extension description
-	 */
-	public ExtensionProperty[] getProperties() {
-		return properties;
-	}
-
-	/**
-	 * @return true - extension description has some properties associated with it; false - no properties 
-	 * are associated with the extension description
-	 */
-	public boolean hasProperties() {
-		return (properties != null) ? properties.length != 0 : false;
-	}
-
-	/**
-	 * @return - String value to be stored in the element
-	 */
-	public String getValue() {
-		return value;
-	}
-
-}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ExtensionProperty.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ExtensionProperty.java
deleted file mode 100644
index 818d5e4..0000000
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/spi/ExtensionProperty.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005 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.core.internal.registry.spi;
-
-/**
- * Describes properties of an extension. Properties are pairs of strings: 
- * {property name; property value}.
- * 
- * It is expected that both property name and property value are not null. 
- *  
- * This class is not intended to be subclassed.
- * 
- * @since org.eclipse.equinox.registry 1.0
- */
-public final class ExtensionProperty {
-
-	/**
-	 * Property name.
-	 */
-	private String name;
-
-	/**
-	 * Property value
-	 */
-	private String value;
-
-	/**
-	 * Constructor.
-	 * @param name - property name
-	 * @param value - property value
-	 */
-	public ExtensionProperty(String name, String value) {
-		this.name = name;
-		this.value = value;
-	}
-
-	/**
-	 * @return - property name
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * @return - property value
-	 */
-	public String getValue() {
-		return value;
-	}
-}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/IExtensionRegistry.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/IExtensionRegistry.java
index b4185cb..bb6705d 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/IExtensionRegistry.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/IExtensionRegistry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2006 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
@@ -51,7 +51,6 @@
  * <p>
  * This interface is not intended to be implemented by clients.
  * </p>
- * @since 3.0
  */
 public interface IExtensionRegistry {
 	/**
@@ -232,7 +231,6 @@
 	 * empty array if there are no known extensions/extension points in this registry.
 	 * 
 	 * @return all namespaces known to this registry
-	 * @since 3.0 
 	 */
 	//TODO This needs to be clarified.
 	public String[] getNamespaces();
@@ -249,36 +247,77 @@
 	public void removeRegistryChangeListener(EventListener listener);
 
 	/**
-	 * Adds to the extension registry an extension point(s), extension(s), or 
-	 * a combination of those described by the XML file.
-	 * 
-	 * If registry is no modifiable, this method is an access controlled method. 
-	 * Proper token is required for non-modifiable registries.
-	 * 
-	 * @see org.eclipse.equinox.registry.spi.RegistryStrategy#isModifiable()
-	 * 
-	 * @param is - stream open on the XML file. The XML file can contain an extension
+	 * Adds to this extension registry an extension point(s), extension(s), or 
+	 * a combination of those described by the XML file. The information in 
+	 * the XML file should be supplied in the same format as the plugin.xml; in fact,
+	 * Plug-in Manifest editor can be used to prepare the XML file. The top token
+	 * of the contribution (normally, "plugin" or "fragment" in the Plug-in Manifest 
+	 * editor) is ignored by this method. 
+	 * <p>
+	 * This method is an access controlled method. Proper token (master token or user token) should 
+	 * be passed as an argument.
+	 * </p>
+	 * @param is stream open on the XML file. The XML file can contain an extension
 	 * poin(s) or/and extension(s) described in the format similar to plugin.xml 
-	 * @param contributorId - ID of the supplier of this contribution
-	 * @param name - optional name of the contribution. Used for error reporting; might be null
-	 * @param translationBundle - optional resource bundle used for translations; might be null 
-	 * @param token - the key used to check permissions. The registry had two keys specified in its
-	 * creation {@link RegistryFactory#createRegistry(org.eclipse.equinox.registry.spi.RegistryStrategy, Object, Object)}: 
-	 * master token and a user token. Use the user token to specify that contribution has dynamic 
-	 * nature. If registry is created with a registry strategy that specified isModifiable() as "true", 
-	 * null can be passed instead of a token.
+	 * @param contributorId ID of the supplier of this contribution
+	 * @param persist indicates if contribution should be stored in the registry cache. If false,
+	 * contribution is not persisted in the registry cache and is lost on Eclipse restart
+	 * @param name optional name of the contribution. Used for error reporting; might be null
+	 * @param translationBundle optional resource bundle used for translations; might be null 
+	 * @param token the key used to check permissions. Two registry keys are set in the registry
+	 * constructor {@link RegistryFactory#createRegistry(org.eclipse.equinox.registry.spi.RegistryStrategy, Object, Object)}: 
+	 * master token and a user token. Master token allows all operations; user token 
+	 * allows non-persisted registry elements to be modified.
 	 * @return - true: the contribution was successfully processed; false - error in 
 	 * the processing of the contribution
+	 * @throws IllegalArgumentException if incorrect token is passed
 	 */
-	public boolean addContribution(InputStream is, String contributorId, String name, ResourceBundle translationBundle, Object token);
+	public boolean addContribution(InputStream is, String contributorId, boolean persist, String name, ResourceBundle translationBundle, Object token) throws IllegalArgumentException;
 
 	/**
-	 * Call this method to properly stop the registry. It stops registry event processing
+	 * Removes extension.
+	 * 
+	 * @param extension extension to be removed
+	 * @param token the key used to check permissions. Two registry keys are set in the registry
+	 * constructor {@link RegistryFactory#createRegistry(org.eclipse.equinox.registry.spi.RegistryStrategy, Object, Object)}: 
+	 * master token and a user token. Master token allows all operations; user token only
+	 * allows non-persisted registry elements to be modified.
+	 * <p>
+	 * This method is an access controlled method. Proper token (master token or user token) should 
+	 * be passed as an argument.
+	 * </p>
+	 * @return true if the extension was successfully removed
+	 * @throws IllegalArgumentException if incorrect token is passed
+	 */
+	public boolean removeExtension(IExtension extension, Object token) throws IllegalArgumentException;
+
+	/**
+	 * Removes extension point.
+	 * 
+	 * @param extensionPoint extension point to be removed
+	 * @param token the key used to check permissions. Two registry keys are set in the registry
+	 * constructor {@link RegistryFactory#createRegistry(org.eclipse.equinox.registry.spi.RegistryStrategy, Object, Object)}: 
+	 * master token and a user token. Master token allows all operations; user token only
+	 * allows non-persisted registry elements to be modified.
+	 * <p>
+	 * This method is an access controlled method. Proper token (master token or user token) should 
+	 * be passed as an argument.
+	 * </p>
+	 * @return true if the extension point was successfully removed
+	 * @throws IllegalArgumentException if incorrect token is passed
+	 */
+	public boolean removeExtensionPoint(IExtensionPoint extensionPoint, Object token) throws IllegalArgumentException;
+
+	/**
+	 * Call this method to properly stop the registry. The method stops registry event processing
 	 * and writes out cache information to be used in the next run. This is an access controlled 
 	 * method; master token is required.
-	 *
+	 * <p>
+	 * This method is an access controlled method. Master token should be passed as an argument.
+	 * </p>
 	 * @see RegistryFactory#createRegistry(org.eclipse.equinox.registry.spi.RegistryStrategy, Object, Object)
-	 * @param token - master token for the registry
+	 * @param token master token for the registry
+	 * @throws IllegalArgumentException if incorrect token is passed
 	 */
-	public void stop(Object token);
+	public void stop(Object token) throws IllegalArgumentException;
 }
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/spi/RegistryStrategy.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/spi/RegistryStrategy.java
index b5009d7..00091e6 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/spi/RegistryStrategy.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/spi/RegistryStrategy.java
@@ -279,7 +279,7 @@
 	}
 
 	/**
-	 * Specifies if lazy cahe loading is used. If cache startegy is not supplied,
+	 * Specifies if lazy cache loading is used. If cache startegy is not supplied,
 	 * lazy cache loading is used.
 	 * 
 	 * This basic implementation specifies that lazy cache loading is going to be used.