Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/CompositeArtifactRepository.java46
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/CompositeMetadataRepository.java63
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/CompositeArtifactRepositoryTest.java51
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java67
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeArtifacts.xml12
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeContent.xml12
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/artifacts.xml29
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/content.xml128
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeArtifacts.xml14
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeContent.xml13
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/artifacts.xml29
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/content.xml128
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/three/artifacts.xml28
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildren/compositeContent.xml1
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/compositeContent.xml14
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/one/content.xml128
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/three/content.xml128
17 files changed, 857 insertions, 34 deletions
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/CompositeArtifactRepository.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/CompositeArtifactRepository.java
index 473119f8a..da28f2711 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/CompositeArtifactRepository.java
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/CompositeArtifactRepository.java
@@ -38,6 +38,8 @@ public class CompositeArtifactRepository extends AbstractArtifactRepository impl
static final public String JAR_EXTENSION = ".jar"; //$NON-NLS-1$
static final public String CONTENT_FILENAME = "compositeArtifacts"; //$NON-NLS-1$
public static final String PI_REPOSITORY_TYPE = "compositeArtifactRepository"; //$NON-NLS-1$
+ static final public String PROP_ATOMIC_LOADING = "p2.atomic.composite.loading"; //$NON-NLS-1$
+ static final public boolean ATOMIC_LOADING_DEFAULT = false;
// keep a list of the child URIs. they can be absolute or relative. they may or may not point
// to a valid reachable repo
@@ -83,12 +85,14 @@ public class CompositeArtifactRepository extends AbstractArtifactRepository impl
/**
* This is only called by the parser when loading a repository.
*/
- CompositeArtifactRepository(IArtifactRepositoryManager manager, CompositeRepositoryState state, IProgressMonitor monitor) {
+ CompositeArtifactRepository(IArtifactRepositoryManager manager, CompositeRepositoryState state, IProgressMonitor monitor) throws ProvisionException {
super(manager.getAgent(), state.getName(), state.getType(), state.getVersion(), state.getLocation(), state.getDescription(), state.getProvider(), state.getProperties());
this.manager = manager;
SubMonitor sub = SubMonitor.convert(monitor, 100 * state.getChildren().length);
+ List<URI> repositoriesToBeRemovedOnFailure = new ArrayList<URI>();
+ boolean failOnChildFailure = shouldFailOnChildFailure(state);
for (URI child : state.getChildren())
- addChild(child, false, sub.newChild(100));
+ addChild(child, false, sub.newChild(100), failOnChildFailure, repositoriesToBeRemovedOnFailure);
}
/**
@@ -144,10 +148,15 @@ public class CompositeArtifactRepository extends AbstractArtifactRepository impl
}
public void addChild(URI childURI) {
- addChild(childURI, true, null);
+ try {
+ addChild(childURI, true, null, false, null);
+ } catch (ProvisionException e) {
+ //already logged
+ }
}
- private void addChild(URI childURI, boolean save, IProgressMonitor monitor) {
+ //successfully loaded repo will be added to the list repositoriesToBeRemovedOnFailure if the list is not null and the repo wasn't previously loaded
+ private void addChild(URI childURI, boolean save, IProgressMonitor monitor, boolean propagateException, List<URI> repositoriesToBeRemovedOnFailure) throws ProvisionException {
SubMonitor sub = SubMonitor.convert(monitor);
URI absolute = URIUtil.makeAbsolute(childURI, getLocation());
if (childrenURIs.contains(childURI) || childrenURIs.contains(absolute)) {
@@ -158,10 +167,19 @@ public class CompositeArtifactRepository extends AbstractArtifactRepository impl
if (save)
save();
try {
+ boolean currentLoaded = getManager().contains(absolute);
IArtifactRepository repo = load(childURI, sub);
+ if (!currentLoaded && propagateException)
+ repositoriesToBeRemovedOnFailure.add(absolute);
loadedRepos.add(new ChildInfo(repo));
} catch (ProvisionException e) {
+ //repository failed to load. fall through
LogHelper.log(e);
+ if (propagateException) {
+ removeFromRepoManager(repositoriesToBeRemovedOnFailure);
+ String msg = NLS.bind(Messages.io_failedRead, getLocation());
+ throw new ProvisionException(new Status(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_FAILED_READ, msg, e));
+ }
}
}
@@ -595,4 +613,24 @@ public class CompositeArtifactRepository extends AbstractArtifactRepository impl
result = Status.OK_STATUS;
return result;
}
+
+ private void removeFromRepoManager(List<URI> currentLoadedRepositories) {
+ if (currentLoadedRepositories == null)
+ return;
+ for (URI loadedChild : currentLoadedRepositories) {
+ manager.removeRepository(loadedChild);
+ }
+ }
+
+ private boolean shouldFailOnChildFailure(CompositeRepositoryState state) {
+ Map<String, String> repoProperties = state.getProperties();
+ boolean failOnChildFailure = ATOMIC_LOADING_DEFAULT;
+ if (repoProperties != null) {
+ String value = repoProperties.get(PROP_ATOMIC_LOADING);
+ if (value != null) {
+ failOnChildFailure = Boolean.parseBoolean(value);
+ }
+ }
+ return failOnChildFailure;
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/CompositeMetadataRepository.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/CompositeMetadataRepository.java
index ab01e4b44..3b331a83b 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/CompositeMetadataRepository.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/CompositeMetadataRepository.java
@@ -35,7 +35,10 @@ import org.eclipse.osgi.util.NLS;
public class CompositeMetadataRepository extends AbstractMetadataRepository implements ICompositeRepository<IInstallableUnit>, IIndexProvider<IInstallableUnit> {
static final public String REPOSITORY_TYPE = CompositeMetadataRepository.class.getName();
- public static final String PI_REPOSITORY_TYPE = "compositeMetadataRepository"; //$NON-NLS-1$
+ static final public String PI_REPOSITORY_TYPE = "compositeMetadataRepository"; //$NON-NLS-1$
+ static final public String PROP_ATOMIC_LOADING = "p2.atomic.composite.loading"; //$NON-NLS-1$
+ static final public boolean ATOMIC_LOADING_DEFAULT = false;
+
static final private Integer REPOSITORY_VERSION = new Integer(1);
static final public String XML_EXTENSION = ".xml"; //$NON-NLS-1$
static final private String JAR_EXTENSION = ".jar"; //$NON-NLS-1$
@@ -89,22 +92,25 @@ public class CompositeMetadataRepository extends AbstractMetadataRepository impl
return isLocal();
}
- CompositeMetadataRepository(IMetadataRepositoryManager manager, URI location, String name, Map<String, String> properties) {
- super(manager.getAgent(), name == null ? (location != null ? location.toString() : "") : name, REPOSITORY_TYPE, REPOSITORY_VERSION.toString(), location, null, null, properties); //$NON-NLS-1$
- this.manager = manager;
- //when creating a repository, we must ensure it exists on disk so a subsequent load will succeed
- save();
- }
-
/*
* This is only called by the parser when loading a repository.
*/
- CompositeMetadataRepository(IMetadataRepositoryManager manager, CompositeRepositoryState state, IProgressMonitor monitor) {
+ CompositeMetadataRepository(IMetadataRepositoryManager manager, CompositeRepositoryState state, IProgressMonitor monitor) throws ProvisionException {
super(manager.getAgent(), state.getName(), state.getType(), state.getVersion(), state.getLocation(), state.getDescription(), state.getProvider(), state.getProperties());
this.manager = manager;
SubMonitor sub = SubMonitor.convert(monitor, 100 * state.getChildren().length);
+ List<URI> repositoriesToBeRemovedOnFailure = new ArrayList<URI>();
+ boolean failOnChildFailure = shouldFailOnChildFailure(state);
for (URI child : state.getChildren())
- addChild(child, false, sub.newChild(100));
+ addChild(child, false, sub.newChild(100), failOnChildFailure, repositoriesToBeRemovedOnFailure);
+
+ }
+
+ CompositeMetadataRepository(IMetadataRepositoryManager manager, URI location, String name, Map<String, String> properties) {
+ super(manager.getAgent(), name == null ? (location != null ? location.toString() : "") : name, REPOSITORY_TYPE, REPOSITORY_VERSION.toString(), location, null, null, properties); //$NON-NLS-1$
+ this.manager = manager;
+ //when creating a repository, we must ensure it exists on disk so a subsequent load will succeed
+ save();
}
/*
@@ -141,7 +147,8 @@ public class CompositeMetadataRepository extends AbstractMetadataRepository impl
}
}
- private void addChild(URI childURI, boolean save, IProgressMonitor monitor) {
+ //successfully loaded repo will be added to the list repositoriesToBeRemovedOnFailure if the list is not null and the repo wasn't previously loaded
+ private void addChild(URI childURI, boolean save, IProgressMonitor monitor, boolean propagateException, List<URI> repositoriesToBeRemovedOnFailure) throws ProvisionException {
SubMonitor sub = SubMonitor.convert(monitor);
URI absolute = URIUtil.makeAbsolute(childURI, getLocation());
if (childrenURIs.contains(childURI) || childrenURIs.contains(absolute)) {
@@ -161,13 +168,21 @@ public class CompositeMetadataRepository extends AbstractMetadataRepository impl
getManager().setEnabled(absolute, false);
//set repository to system to hide from users
getManager().setRepositoryProperty(absolute, IRepository.PROP_SYSTEM, String.valueOf(true));
+ if (propagateException)
+ repositoriesToBeRemovedOnFailure.add(absolute);
}
currentRepo.compress(iuPool); // Share IUs across this CompositeMetadataRepository
// we successfully loaded the repo so remember it
loadedRepos.add(currentRepo);
+
} catch (ProvisionException e) {
//repository failed to load. fall through
LogHelper.log(e);
+ if (propagateException) {
+ removeFromRepoManager(repositoriesToBeRemovedOnFailure);
+ String msg = NLS.bind(Messages.io_failedRead, getLocation());
+ throw new ProvisionException(new Status(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_FAILED_READ, msg, e));
+ }
}
}
@@ -175,7 +190,11 @@ public class CompositeMetadataRepository extends AbstractMetadataRepository impl
* @see org.eclipse.equinox.p2.repository.ICompositeRepository#addChild(java.net.URI)
*/
public void addChild(URI childURI) {
- addChild(childURI, true, null);
+ try {
+ addChild(childURI, true, null, false, null);
+ } catch (ProvisionException e) {
+ //already logged
+ }
}
/* (non-Javadoc)
@@ -377,4 +396,24 @@ public class CompositeMetadataRepository extends AbstractMetadataRepository impl
return null;
}
+ private void removeFromRepoManager(List<URI> currentLoadedRepositories) {
+ if (currentLoadedRepositories == null)
+ return;
+ for (URI loadedChild : currentLoadedRepositories) {
+ manager.removeRepository(loadedChild);
+ }
+ }
+
+ private boolean shouldFailOnChildFailure(CompositeRepositoryState state) {
+ Map<String, String> repoProperties = state.getProperties();
+ boolean failOnChildFailure = ATOMIC_LOADING_DEFAULT;
+ if (repoProperties != null) {
+ String value = repoProperties.get(PROP_ATOMIC_LOADING);
+ if (value != null) {
+ failOnChildFailure = Boolean.parseBoolean(value);
+ }
+ }
+ return failOnChildFailure;
+ }
+
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/CompositeArtifactRepositoryTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/CompositeArtifactRepositoryTest.java
index 4947f8dd3..4ba73afba 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/CompositeArtifactRepositoryTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/CompositeArtifactRepositoryTest.java
@@ -1352,4 +1352,55 @@ public class CompositeArtifactRepositoryTest extends AbstractProvisioningTest {
return null;
}
}
+
+ public void testFailingChildFailsCompleteRepository() throws ProvisionException, OperationCanceledException {
+ boolean exception = false;
+ IArtifactRepository repo = null;
+ IArtifactRepositoryManager manager = getArtifactRepositoryManager();
+
+ File repoFile = getTestData("Strict composite with missing child", "/testData/artifactRepo/compositeBadChildrenStrict");
+ URI correctChildURI = URIUtil.append(repoFile.toURI(), "one");
+ URI repoURI = repoFile.getAbsoluteFile().toURI();
+
+ File alreadyLoadedChildFile = getTestData("Strict composite with missing child", "/testData/artifactRepo/compositeBadChildrenStrict/three");
+ IArtifactRepository alreadyLoadedChild = manager.loadRepository(alreadyLoadedChildFile.toURI(), null);
+ assertNotNull(alreadyLoadedChild);
+ URI previouslyAddedChildURI = URIUtil.append(repoFile.toURI(), "three");
+
+ assertFalse("Child one should not be available in repo manager", manager.contains(correctChildURI));
+ try {
+ repo = manager.loadRepository(repoFile.toURI(), null);
+ } catch (ProvisionException e) {
+
+ assertFalse("Exception message should not contain the location of failing child", e.getMessage().contains(URIUtil.append(repoURI, "two").toString()));
+ assertTrue("Exception message should contain the composite repository location " + repoURI + ": " + e.getMessage(), e.getMessage().contains(repoURI.toString()));
+ exception = true;
+ }
+ assertNull(repo);
+ assertTrue("an exception should have been reported", exception);
+ assertFalse("Successfully loaded child should be removed when composite loading mode is set to strict", manager.contains(correctChildURI));
+ assertTrue("Periously loaded child should remain in repo manager", manager.contains(previouslyAddedChildURI));
+
+ }
+
+ public void testFailingChildLoadsCompleteRepository() {
+ boolean exception = false;
+ IArtifactRepository repo = null;
+ IArtifactRepositoryManager manager = getArtifactRepositoryManager();
+
+ File repoFile = getTestData("Composite with missing child", "/testData/artifactRepo/compositeBadChildren");
+ URI correctChildURI = URIUtil.append(repoFile.toURI(), "one");
+
+ assertFalse("Child should not be available in repo manager", manager.contains(correctChildURI));
+ try {
+ repo = manager.loadRepository(repoFile.toURI(), null);
+ } catch (ProvisionException e) {
+ exception = true;
+ }
+
+ assertNotNull(repo);
+ assertFalse("an exception should have been reported", exception);
+ assertTrue("Successfully loaded child should be available in repo manager", manager.contains(URIUtil.append(repo.getLocation(), "one")));
+
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java
index 2891dfe6d..4631a98fb 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/CompositeMetadataRepositoryTest.java
@@ -17,8 +17,7 @@ import java.io.PrintStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.URIUtil;
+import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository;
import org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepositoryFactory;
import org.eclipse.equinox.internal.p2.persistence.CompositeRepositoryState;
@@ -681,20 +680,54 @@ public class CompositeMetadataRepositoryTest extends AbstractProvisioningTest {
}
}
- // public void testFailingChildFailsCompleteRepository() {
- // IMetadataRepositoryManager manager = getMetadataRepositoryManager();
- // File repoFile = getTestData("Strict composite with missing child", "/testData/metadataRepo/compositeBadChildren");
- // IMetadataRepository repo = null;
- // boolean exception = false;
- //
- // try {
- // repo = manager.loadRepository(repoFile.toURI(), null);
- // } catch (ProvisionException e) {
- // exception = true;
- // }
- // assertTrue("an exception should have been reported", exception);
- // assertNull(repo);
- //
- // }
+ public void testFailingChildFailsCompleteRepository() throws ProvisionException, OperationCanceledException {
+ boolean exception = false;
+ IMetadataRepository repo = null;
+ IMetadataRepositoryManager manager = getMetadataRepositoryManager();
+
+ File repoFile = getTestData("Strict composite with missing child", "/testData/metadataRepo/compositeBadChildrenStrict");
+ URI correctChildURI = URIUtil.append(repoFile.toURI(), "one");
+ URI repoURI = repoFile.getAbsoluteFile().toURI();
+
+ File alreadyLoadedChildFile = getTestData("Strict composite with missing child", "/testData/metadataRepo/compositeBadChildrenStrict/three");
+ IMetadataRepository alreadyLoadedChild = manager.loadRepository(alreadyLoadedChildFile.toURI(), null);
+ assertNotNull(alreadyLoadedChild);
+ URI previouslyAddedChildURI = URIUtil.append(repoFile.toURI(), "three");
+
+ assertFalse("Child one should not be available in repo manager", manager.contains(correctChildURI));
+ try {
+ repo = manager.loadRepository(repoFile.toURI(), null);
+ } catch (ProvisionException e) {
+
+ assertFalse("Exception message should not contain the location of failing child", e.getMessage().contains(URIUtil.append(repoURI, "two").toString()));
+ assertTrue("Exception message should contain the composite repository location " + repoURI + ": " + e.getMessage(), e.getMessage().contains(repoURI.toString()));
+ exception = true;
+ }
+ assertNull(repo);
+ assertTrue("an exception should have been reported", exception);
+ assertFalse("Successfully loaded child should be removed when composite loading mode is set to strict", manager.contains(correctChildURI));
+ assertTrue("Periously loaded child should remain in repo manager", manager.contains(previouslyAddedChildURI));
+
+ }
+ public void testFailingChildLoadsCompleteRepository() {
+ boolean exception = false;
+ IMetadataRepository repo = null;
+ IMetadataRepositoryManager manager = getMetadataRepositoryManager();
+
+ File repoFile = getTestData("Composite with missing child", "/testData/metadataRepo/compositeBadChildren");
+ URI correctChildURI = URIUtil.append(repoFile.toURI(), "one");
+
+ assertFalse("Child should not be available in repo manager", manager.contains(correctChildURI));
+ try {
+ repo = manager.loadRepository(repoFile.toURI(), null);
+ } catch (ProvisionException e) {
+ exception = true;
+ }
+
+ assertNotNull(repo);
+ assertFalse("an exception should have been reported", exception);
+ assertTrue("Successfully loaded child should be available in repo manager", manager.contains(URIUtil.append(repo.getLocation(), "one")));
+
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeArtifacts.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeArtifacts.xml
new file mode 100644
index 000000000..26105adf9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeArtifacts.xml
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?compositeArtifactRepository version='1.0.0'?>
+<repository name='artifact name' type='org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository' version='1.0.0'>
+ <properties size='2'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1234'/>
+ </properties>
+ <children size='2'>
+ <child location='one'/>
+ <child location='two'/>
+ </children>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeContent.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeContent.xml
new file mode 100644
index 000000000..af4be35bc
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/compositeContent.xml
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?compositeMetadataRepository version='1.0.0'?>
+<repository name='metadata name' type='org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository' version='1.0.0'>
+ <properties size='2'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1234'/>
+ </properties>
+ <children size='2'>
+ <child location='one'/>
+ <child location='two'/>
+ </children>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/artifacts.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/artifacts.xml
new file mode 100644
index 000000000..19e55d746
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/artifacts.xml
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?artifactRepository class='org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository' version='1.0.0'?>
+<repository name='Good Test Repository' type='org.eclipse.equinox.p2.artifact.repository.simpleRepository' version='1' description='Good test repository description'>
+ <properties size='3'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1218734853468'/>
+ <property name='p2.system' value='false'/>
+ </properties>
+ <mappings size='3'>
+ <rule filter='(&amp; (classifier=osgi.bundle))' output='${repoUrl}/plugins/${id}_${version}.jar'/>
+ <rule filter='(&amp; (classifier=binary))' output='${repoUrl}/binary/${id}_${version}'/>
+ <rule filter='(&amp; (classifier=org.eclipse.update.feature))' output='${repoUrl}/features/${id}_${version}.jar'/>
+ </mappings>
+ <artifacts size='2'>
+ <artifact classifier='osgi.bundle' id='aaPlugin' version='1.0.0'>
+ <properties size='3'>
+ <property name='artifact.size' value='469'/>
+ <property name='download.size' value='469'/>
+ <property name='download.contentType' value='application/zip'/>
+ </properties>
+ </artifact>
+ <artifact classifier='org.eclipse.update.feature' id='aaFeature' version='1.0.0'>
+ <properties size='2'>
+ <property name='artifact.size' value='670'/>
+ <property name='download.size' value='670'/>
+ </properties>
+ </artifact>
+ </artifacts>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/content.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/content.xml
new file mode 100644
index 000000000..41f172f48
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildren/one/content.xml
@@ -0,0 +1,128 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?metadataRepository class='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1.0.0'?>
+<repository name='Good Test Repository' type='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1' description='Good test repository description'>
+ <properties size='3'>
+ <property name='p2.system' value='true'/>
+ <property name='p2.timestamp' value='1221680367875'/>
+ <property name='site.checksum' value='2404093275'/>
+ </properties>
+ <units size='5'>
+ <unit id='test.feature.feature.jar' version='1.0.0'>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='feature' version='1.0.0'/>
+ <provided namespace='org.eclipse.update.feature' name='test.feature' version='1.0.0'/>
+ </provides>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ <artifacts size='1'>
+ <artifact classifier='org.eclipse.update.feature' id='test.feature' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='zipped'>
+ true
+ </instruction>
+ </instructions>
+ </touchpointData>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='test.bundle' version='1.0.0' singleton='false'>
+ <update id='test.bundle' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.bundle' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.bundle' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.bundle' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.fragment' version='1.0.0' singleton='false'>
+ <update id='test.fragment' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.fragment' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.fragment' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.fragment' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.feature.feature.group' version='1.0.0' singleton='false'>
+ <update id='test.feature.feature.group' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='5'>
+ <property name='org.eclipse.equinox.p2.name' value='%featurename'/>
+ <property name='org.eclipse.equinox.p2.description' value='[Enter Feature Description here.]'/>
+ <property name='org.eclipse.equinox.p2.description.url' value='http://www.example.com/description'/>
+ <property name='org.eclipse.equinox.p2.type.group' value='true'/>
+ <property name='df_LT.featurename' value='j the feature'/>
+ </properties>
+ <provides size='2'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.localization' name='df_LT' version='1.0.0'/>
+ </provides>
+ <requires size='3'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.bundle' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.fragment' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' range='[1.0.0,1.0.0]'>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ </required>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='Default' version='0.0.0'>
+ <properties size='3'>
+ <property name='org.eclipse.equinox.p2.name' value='Uncategorized'/>
+ <property name='org.eclipse.equinox.p2.description' value='Default category for otherwise uncategorized features'/>
+ <property name='org.eclipse.equinox.p2.type.category' value='true'/>
+ </properties>
+ <provides size='1'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='Default' version='0.0.0'/>
+ </provides>
+ <requires size='1'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' range='[1.0.0,1.0.0]'/>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ </unit>
+ </units>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeArtifacts.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeArtifacts.xml
new file mode 100644
index 000000000..8b544dabe
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeArtifacts.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?compositeArtifactRepository version='1.0.0'?>
+<repository name='artifact name' type='org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository' version='1.0.0'>
+ <properties size='2'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1234'/>
+ <property name='p2.atomic.composite.loading' value='true'/>
+ </properties>
+ <children size='3'>
+ <child location='one'/>
+ <child location='two'/>
+ <child location='three'/>
+ </children>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeContent.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeContent.xml
new file mode 100644
index 000000000..733bd2ae6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/compositeContent.xml
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?compositeMetadataRepository version='1.0.0'?>
+<repository name='metadata name' type='org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository' version='1.0.0'>
+ <properties size='2'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1234'/>
+ <property name='p2.atomic.composite.loading' value='true'/>
+ </properties>
+ <children size='2'>
+ <child location='one'/>
+ <child location='two'/>
+ </children>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/artifacts.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/artifacts.xml
new file mode 100644
index 000000000..19e55d746
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/artifacts.xml
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?artifactRepository class='org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository' version='1.0.0'?>
+<repository name='Good Test Repository' type='org.eclipse.equinox.p2.artifact.repository.simpleRepository' version='1' description='Good test repository description'>
+ <properties size='3'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1218734853468'/>
+ <property name='p2.system' value='false'/>
+ </properties>
+ <mappings size='3'>
+ <rule filter='(&amp; (classifier=osgi.bundle))' output='${repoUrl}/plugins/${id}_${version}.jar'/>
+ <rule filter='(&amp; (classifier=binary))' output='${repoUrl}/binary/${id}_${version}'/>
+ <rule filter='(&amp; (classifier=org.eclipse.update.feature))' output='${repoUrl}/features/${id}_${version}.jar'/>
+ </mappings>
+ <artifacts size='2'>
+ <artifact classifier='osgi.bundle' id='aaPlugin' version='1.0.0'>
+ <properties size='3'>
+ <property name='artifact.size' value='469'/>
+ <property name='download.size' value='469'/>
+ <property name='download.contentType' value='application/zip'/>
+ </properties>
+ </artifact>
+ <artifact classifier='org.eclipse.update.feature' id='aaFeature' version='1.0.0'>
+ <properties size='2'>
+ <property name='artifact.size' value='670'/>
+ <property name='download.size' value='670'/>
+ </properties>
+ </artifact>
+ </artifacts>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/content.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/content.xml
new file mode 100644
index 000000000..41f172f48
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/one/content.xml
@@ -0,0 +1,128 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?metadataRepository class='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1.0.0'?>
+<repository name='Good Test Repository' type='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1' description='Good test repository description'>
+ <properties size='3'>
+ <property name='p2.system' value='true'/>
+ <property name='p2.timestamp' value='1221680367875'/>
+ <property name='site.checksum' value='2404093275'/>
+ </properties>
+ <units size='5'>
+ <unit id='test.feature.feature.jar' version='1.0.0'>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='feature' version='1.0.0'/>
+ <provided namespace='org.eclipse.update.feature' name='test.feature' version='1.0.0'/>
+ </provides>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ <artifacts size='1'>
+ <artifact classifier='org.eclipse.update.feature' id='test.feature' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='zipped'>
+ true
+ </instruction>
+ </instructions>
+ </touchpointData>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='test.bundle' version='1.0.0' singleton='false'>
+ <update id='test.bundle' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.bundle' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.bundle' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.bundle' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.fragment' version='1.0.0' singleton='false'>
+ <update id='test.fragment' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.fragment' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.fragment' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.fragment' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.feature.feature.group' version='1.0.0' singleton='false'>
+ <update id='test.feature.feature.group' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='5'>
+ <property name='org.eclipse.equinox.p2.name' value='%featurename'/>
+ <property name='org.eclipse.equinox.p2.description' value='[Enter Feature Description here.]'/>
+ <property name='org.eclipse.equinox.p2.description.url' value='http://www.example.com/description'/>
+ <property name='org.eclipse.equinox.p2.type.group' value='true'/>
+ <property name='df_LT.featurename' value='j the feature'/>
+ </properties>
+ <provides size='2'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.localization' name='df_LT' version='1.0.0'/>
+ </provides>
+ <requires size='3'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.bundle' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.fragment' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' range='[1.0.0,1.0.0]'>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ </required>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='Default' version='0.0.0'>
+ <properties size='3'>
+ <property name='org.eclipse.equinox.p2.name' value='Uncategorized'/>
+ <property name='org.eclipse.equinox.p2.description' value='Default category for otherwise uncategorized features'/>
+ <property name='org.eclipse.equinox.p2.type.category' value='true'/>
+ </properties>
+ <provides size='1'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='Default' version='0.0.0'/>
+ </provides>
+ <requires size='1'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' range='[1.0.0,1.0.0]'/>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ </unit>
+ </units>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/three/artifacts.xml b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/three/artifacts.xml
new file mode 100644
index 000000000..6c73323c4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/artifactRepo/compositeBadChildrenStrict/three/artifacts.xml
@@ -0,0 +1,28 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?artifactRepository class='org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository' version='1.0.0'?>
+<repository name='file:/C:/1target/provmiddle/aaTestSite/ - artifacts' type='org.eclipse.equinox.p2.artifact.repository.simpleRepository' version='1'>
+ <properties size='2'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1218734853468'/>
+ </properties>
+ <mappings size='3'>
+ <rule filter='(&amp; (classifier=osgi.bundle))' output='${repoUrl}/plugins/${id}_${version}.jar'/>
+ <rule filter='(&amp; (classifier=binary))' output='${repoUrl}/binary/${id}_${version}'/>
+ <rule filter='(&amp; (classifier=org.eclipse.update.feature))' output='${repoUrl}/features/${id}_${version}.jar'/>
+ </mappings>
+ <artifacts size='2'>
+ <artifact classifier='osgi.bundle' id='aaPlugin' version='1.0.0'>
+ <properties size='3'>
+ <property name='artifact.size' value='469'/>
+ <property name='download.size' value='469'/>
+ <property name='download.contentType' value='application/zip'/>
+ </properties>
+ </artifact>
+ <artifact classifier='org.eclipse.update.feature' id='aaFeature' version='1.0.0'>
+ <properties size='2'>
+ <property name='artifact.size' value='670'/>
+ <property name='download.size' value='670'/>
+ </properties>
+ </artifact>
+ </artifacts>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildren/compositeContent.xml b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildren/compositeContent.xml
index 6c8fd790c..af4be35bc 100644
--- a/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildren/compositeContent.xml
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildren/compositeContent.xml
@@ -4,7 +4,6 @@
<properties size='2'>
<property name='p2.compressed' value='false'/>
<property name='p2.timestamp' value='1234'/>
- <property name='composite.restrictive.loading' value='true'/>
</properties>
<children size='2'>
<child location='one'/>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/compositeContent.xml b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/compositeContent.xml
new file mode 100644
index 000000000..420982854
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/compositeContent.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?compositeMetadataRepository version='1.0.0'?>
+<repository name='metadata name' type='org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository' version='1.0.0'>
+ <properties size='2'>
+ <property name='p2.compressed' value='false'/>
+ <property name='p2.timestamp' value='1234'/>
+ <property name='p2.atomic.composite.loading' value='true'/>
+ </properties>
+ <children size='3'>
+ <child location='one'/>
+ <child location='two'/>
+ <child location='three'/>
+ </children>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/one/content.xml b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/one/content.xml
new file mode 100644
index 000000000..41f172f48
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/one/content.xml
@@ -0,0 +1,128 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?metadataRepository class='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1.0.0'?>
+<repository name='Good Test Repository' type='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1' description='Good test repository description'>
+ <properties size='3'>
+ <property name='p2.system' value='true'/>
+ <property name='p2.timestamp' value='1221680367875'/>
+ <property name='site.checksum' value='2404093275'/>
+ </properties>
+ <units size='5'>
+ <unit id='test.feature.feature.jar' version='1.0.0'>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='feature' version='1.0.0'/>
+ <provided namespace='org.eclipse.update.feature' name='test.feature' version='1.0.0'/>
+ </provides>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ <artifacts size='1'>
+ <artifact classifier='org.eclipse.update.feature' id='test.feature' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='zipped'>
+ true
+ </instruction>
+ </instructions>
+ </touchpointData>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='test.bundle' version='1.0.0' singleton='false'>
+ <update id='test.bundle' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.bundle' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.bundle' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.bundle' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.fragment' version='1.0.0' singleton='false'>
+ <update id='test.fragment' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.fragment' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.fragment' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.fragment' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.feature.feature.group' version='1.0.0' singleton='false'>
+ <update id='test.feature.feature.group' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='5'>
+ <property name='org.eclipse.equinox.p2.name' value='%featurename'/>
+ <property name='org.eclipse.equinox.p2.description' value='[Enter Feature Description here.]'/>
+ <property name='org.eclipse.equinox.p2.description.url' value='http://www.example.com/description'/>
+ <property name='org.eclipse.equinox.p2.type.group' value='true'/>
+ <property name='df_LT.featurename' value='j the feature'/>
+ </properties>
+ <provides size='2'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.localization' name='df_LT' version='1.0.0'/>
+ </provides>
+ <requires size='3'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.bundle' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.fragment' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' range='[1.0.0,1.0.0]'>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ </required>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='Default' version='0.0.0'>
+ <properties size='3'>
+ <property name='org.eclipse.equinox.p2.name' value='Uncategorized'/>
+ <property name='org.eclipse.equinox.p2.description' value='Default category for otherwise uncategorized features'/>
+ <property name='org.eclipse.equinox.p2.type.category' value='true'/>
+ </properties>
+ <provides size='1'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='Default' version='0.0.0'/>
+ </provides>
+ <requires size='1'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' range='[1.0.0,1.0.0]'/>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ </unit>
+ </units>
+</repository>
diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/three/content.xml b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/three/content.xml
new file mode 100644
index 000000000..41f172f48
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/testData/metadataRepo/compositeBadChildrenStrict/three/content.xml
@@ -0,0 +1,128 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<?metadataRepository class='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1.0.0'?>
+<repository name='Good Test Repository' type='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1' description='Good test repository description'>
+ <properties size='3'>
+ <property name='p2.system' value='true'/>
+ <property name='p2.timestamp' value='1221680367875'/>
+ <property name='site.checksum' value='2404093275'/>
+ </properties>
+ <units size='5'>
+ <unit id='test.feature.feature.jar' version='1.0.0'>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='feature' version='1.0.0'/>
+ <provided namespace='org.eclipse.update.feature' name='test.feature' version='1.0.0'/>
+ </provides>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ <artifacts size='1'>
+ <artifact classifier='org.eclipse.update.feature' id='test.feature' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='zipped'>
+ true
+ </instruction>
+ </instructions>
+ </touchpointData>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='test.bundle' version='1.0.0' singleton='false'>
+ <update id='test.bundle' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.bundle' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.bundle' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.bundle' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.fragment' version='1.0.0' singleton='false'>
+ <update id='test.fragment' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='1'>
+ <property name='org.eclipse.equinox.p2.partial.iu' value='true'/>
+ </properties>
+ <provides size='3'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.fragment' version='1.0.0'/>
+ <provided namespace='osgi.bundle' name='test.fragment' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
+ </provides>
+ <artifacts size='1'>
+ <artifact classifier='osgi.bundle' id='test.fragment' version='1.0.0'/>
+ </artifacts>
+ <touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
+ <touchpointData size='1'>
+ <instructions size='1'>
+ <instruction key='manifest'>
+ </instruction>
+ </instructions>
+ </touchpointData>
+ </unit>
+ <unit id='test.feature.feature.group' version='1.0.0' singleton='false'>
+ <update id='test.feature.feature.group' range='[0.0.0,1.0.0)' severity='0'/>
+ <properties size='5'>
+ <property name='org.eclipse.equinox.p2.name' value='%featurename'/>
+ <property name='org.eclipse.equinox.p2.description' value='[Enter Feature Description here.]'/>
+ <property name='org.eclipse.equinox.p2.description.url' value='http://www.example.com/description'/>
+ <property name='org.eclipse.equinox.p2.type.group' value='true'/>
+ <property name='df_LT.featurename' value='j the feature'/>
+ </properties>
+ <provides size='2'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' version='1.0.0'/>
+ <provided namespace='org.eclipse.equinox.p2.localization' name='df_LT' version='1.0.0'/>
+ </provides>
+ <requires size='3'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.bundle' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.fragment' range='[1.0.0,1.0.0]'/>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.jar' range='[1.0.0,1.0.0]'>
+ <filter>
+ (org.eclipse.update.install.features=true)
+ </filter>
+ </required>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ <licenses size='1'>
+ <license url='http://www.example.com/license'>
+ [Enter License Description here.]
+ </license>
+ </licenses>
+ <copyright url='http://www.example.com/copyright'>
+ [Enter Copyright Description here.]
+ </copyright>
+ </unit>
+ <unit id='Default' version='0.0.0'>
+ <properties size='3'>
+ <property name='org.eclipse.equinox.p2.name' value='Uncategorized'/>
+ <property name='org.eclipse.equinox.p2.description' value='Default category for otherwise uncategorized features'/>
+ <property name='org.eclipse.equinox.p2.type.category' value='true'/>
+ </properties>
+ <provides size='1'>
+ <provided namespace='org.eclipse.equinox.p2.iu' name='Default' version='0.0.0'/>
+ </provides>
+ <requires size='1'>
+ <required namespace='org.eclipse.equinox.p2.iu' name='test.feature.feature.group' range='[1.0.0,1.0.0]'/>
+ </requires>
+ <touchpoint id='null' version='0.0.0'/>
+ </unit>
+ </units>
+</repository>

Back to the top