You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by am...@apache.org on 2006/04/18 04:49:28 UTC
svn commit: r394827 - in /geronimo/branches/1.1/modules/system/src:
java/org/apache/geronimo/system/configuration/ schema/
Author: ammulder
Date: Mon Apr 17 19:49:26 2006
New Revision: 394827
URL: http://svn.apache.org/viewcvs?rev=394827&view=rev
Log:
Support for upgrade lists, obsoletes, etc.
As an example, now you can upgrade a minimal tomcat server to a J2EE tomcat
server with one command.
Modified:
geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigInstallerGBean.java
geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigurationMetadata.java
geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadPoller.java
geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadResults.java
geronimo/branches/1.1/modules/system/src/schema/config-list.xsd
Modified: geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigInstallerGBean.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigInstallerGBean.java?rev=394827&r1=394826&r2=394827&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigInstallerGBean.java (original)
+++ geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigInstallerGBean.java Mon Apr 17 19:49:26 2006
@@ -34,6 +34,7 @@
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
import javax.security.auth.login.FailedLoginException;
@@ -193,13 +194,18 @@
return new ConfigurationList(repo, backupURLs, data);
}
- private ConfigurationMetadata processConfiguration(Element config) {
+ private ConfigurationMetadata processConfiguration(Element config) throws SAXException {
String configId = getChildText(config, "config-id");
NodeList licenseNodes = config.getElementsByTagName("license");
ConfigurationMetadata.License[] licenses = new ConfigurationMetadata.License[licenseNodes.getLength()];
for(int j=0; j<licenseNodes.getLength(); j++) {
Element node = (Element) licenseNodes.item(j);
- licenses[j] = new ConfigurationMetadata.License(getText(node), Boolean.valueOf(node.getAttribute("osi-approved")).booleanValue());
+ String licenseName = getText(node);
+ String openSource = node.getAttribute("osi-approved");
+ if(licenseName == null || licenseName.equals("") || openSource == null || openSource.equals("")) {
+ throw new SAXException("Invalid config file: license name and osi-approved flag required");
+ }
+ licenses[j] = new ConfigurationMetadata.License(licenseName, Boolean.valueOf(openSource).booleanValue());
}
boolean eligible = true;
NodeList preNodes = config.getElementsByTagName("prerequisite");
@@ -207,6 +213,9 @@
for(int j=0; j<preNodes.getLength(); j++) {
Element node = (Element) preNodes.item(j);
String originalConfigId = getChildText(node, "id");
+ if(originalConfigId == null) {
+ throw new SAXException("Prerequisite requires <id>");
+ }
Artifact artifact = Artifact.create(originalConfigId.replaceAll("\\*", ""));
boolean present = resolver.queryArtifacts(artifact).length > 0;
prereqs[j] = new ConfigurationMetadata.Prerequisite(artifact, present,
@@ -222,6 +231,9 @@
boolean match = false;
for (int j = 0; j < gerVersions.length; j++) {
String gerVersion = gerVersions[j];
+ if(gerVersion == null || gerVersion.equals("")) {
+ throw new SAXException("geronimo-version should not be empty!");
+ }
if(gerVersion.equals(version)) {
match = true;
break;
@@ -235,6 +247,9 @@
boolean match = false;
for (int j = 0; j < jvmVersions.length; j++) {
String jvmVersion = jvmVersions[j];
+ if(jvmVersion == null || jvmVersion.equals("")) {
+ throw new SAXException("jvm-version should not be empty!");
+ }
if(version.startsWith(jvmVersion)) {
match = true;
break;
@@ -242,8 +257,12 @@
}
if(!match) eligible = false;
}
- Artifact artifact = Artifact.create(configId);
- boolean installed = configManager.isLoaded(artifact);
+ Artifact artifact = null;
+ boolean installed = false;
+ if (configId != null) {
+ artifact = Artifact.create(configId);
+ installed = configManager.isLoaded(artifact);
+ }
log.trace("Checking "+configId+": installed="+installed+", eligible="+eligible);
ConfigurationMetadata data = new ConfigurationMetadata(artifact, getChildText(config, "name"),
getChildText(config, "description"), getChildText(config, "category"), installed, eligible);
@@ -251,7 +270,19 @@
data.setJvmVersions(jvmVersions);
data.setLicenses(licenses);
data.setPrerequisites(prereqs);
- data.setDependencies(getChildrenText(config, "dependency"));
+ NodeList list = config.getElementsByTagName("dependency");
+ List start = new ArrayList();
+ String deps[] = new String[list.getLength()];
+ for(int i=0; i<list.getLength(); i++) {
+ Element node = (Element) list.item(i);
+ deps[i] = getText(node);
+ if(node.hasAttribute("start") && node.getAttribute("start").equalsIgnoreCase("true")) {
+ start.add(deps[i]);
+ }
+ }
+ data.setDependencies(deps);
+ data.setForceStart((String[]) start.toArray(new String[start.size()]));
+ data.setObsoletes(getChildrenText(config, "obsoletes"));
return data;
}
@@ -313,17 +344,71 @@
public void install(ConfigurationList list, String username, String password, DownloadPoller poller) {
try {
- // For each configuration in the list to install...
+ // Step 1: validate everything
for (int i = 0; i < list.getConfigurations().length; i++) {
- // 1. Identify the configuration
ConfigurationMetadata metadata = list.getConfigurations()[i];
- // 2. Validate that we can install it
validateConfiguration(metadata);
+ }
+
+ // Step 2: everything is valid, do the installation
+ for (int i = 0; i < list.getConfigurations().length; i++) {
+ // 1. Identify the configuration
+ ConfigurationMetadata metadata = list.getConfigurations()[i];
+ // 2. Unload obsoleted configurations
+ List obsoletes = new ArrayList();
+ for (int j = 0; j < metadata.getObsoletes().length; j++) {
+ String name = metadata.getObsoletes()[j];
+ Artifact obsolete = Artifact.create(name);
+ if(configManager.isLoaded(obsolete)) {
+ if(configManager.isRunning(obsolete)) {
+ configManager.stopConfiguration(obsolete);
+ }
+ configManager.unloadConfiguration(obsolete);
+ obsoletes.add(obsolete);
+ }
+ }
// 3. Download the artifact if necessary, and its dependencies
- downloadArtifact(metadata.getConfigId(), list.getMainRepository(), list.getBackupRepositories(),
- username, password, new ResultsFileWriteMonitor(poller));
- // 4. Installation of this configuration finished successfully
- poller.addInstalledConfigID(metadata.getConfigId());
+ Set working = new HashSet();
+ if(metadata.getConfigId() != null) {
+ downloadArtifact(metadata.getConfigId(), list.getMainRepository(), list.getBackupRepositories(),
+ username, password, new ResultsFileWriteMonitor(poller), working);
+ poller.addInstalledConfigID(metadata.getConfigId());
+ } else {
+ String[] deps = metadata.getDependencies();
+ for (int j = 0; j < deps.length; j++) {
+ String dep = deps[j];
+ Artifact entry = Artifact.create(dep);
+ if(configManager.isRunning(entry)) {
+ continue;
+ }
+ downloadArtifact(entry, list.getMainRepository(), list.getBackupRepositories(),
+ username, password, new ResultsFileWriteMonitor(poller), working);
+ }
+ }
+ // 4. Uninstall obsolete configurations
+ for (int j = 0; j < obsoletes.size(); j++) {
+ Artifact artifact = (Artifact) obsoletes.get(j);
+ configManager.uninstallConfiguration(artifact);
+ }
+ // 5. Installation of this configuration finished successfully
+ if(metadata.getConfigId() != null) {
+ poller.addInstalledConfigID(metadata.getConfigId());
+ }
+ }
+
+ // Step 3: Start anything that's marked accordingly
+ for (int i = 0; i < list.getConfigurations().length; i++) {
+ ConfigurationMetadata metadata = list.getConfigurations()[i];
+ for (int j = 0; j < metadata.getForceStart().length; j++) {
+ String id = metadata.getForceStart()[j];
+ Artifact artifact = Artifact.create(id);
+ if(configManager.isConfiguration(artifact)) {
+ poller.setCurrentFilePercent(-1);
+ poller.setCurrentMessage("Starting "+artifact);
+ configManager.loadConfiguration(artifact);
+ configManager.startConfiguration(artifact);
+ }
+ }
}
} catch (Exception e) {
poller.setFailure(e);
@@ -346,16 +431,16 @@
// 2. Validate that we can install this
validateConfiguration(data.getConfiguration());
- // 3. Install the CAR into the repository
- ResultsFileWriteMonitor monitor = new ResultsFileWriteMonitor(poller);
- writeableRepo.copyToRepository(carFile, data.getConfiguration().getConfigId(), monitor);
-
- // 4. Download all the dependencies
- downloadArtifact(data.getConfiguration().getConfigId(), data.getRepository(), data.getBackups(),
- username, password, monitor);
+ // 3. Install the CAR into the repository (it shouldn't be re-downloaded)
+ if(data.getConfiguration().getConfigId() != null) {
+ ResultsFileWriteMonitor monitor = new ResultsFileWriteMonitor(poller);
+ writeableRepo.copyToRepository(carFile, data.getConfiguration().getConfigId(), monitor);
+ }
- // 5. Installation of the main configuration finished successfully
- poller.addInstalledConfigID(data.getConfiguration().getConfigId());
+ // 4. Use the standard logic to remove obsoletes, install dependencies, etc.
+ // This will validate all over again (oh, well)
+ install(new ConfigurationList(data.getRepository(), data.getBackups(), new ConfigurationMetadata[]{data.getConfiguration()}),
+ username, password, poller);
} catch (Exception e) {
poller.setFailure(e);
} finally {
@@ -365,8 +450,18 @@
private void validateConfiguration(ConfigurationMetadata metadata) throws MissingDependencyException {
// 1. Check that it's not already running
- if(configManager.isRunning(metadata.getConfigId())) {
- throw new IllegalArgumentException("Configuration "+metadata.getConfigId()+" is already running!");
+ if(metadata.getConfigId() != null) { // that is, it's a real configuration not a plugin list
+ if(configManager.isRunning(metadata.getConfigId())) {
+ throw new IllegalArgumentException("Configuration "+metadata.getConfigId()+" is already running!");
+ }
+ } else { // Different validation for plugin lists
+ for (int i = 0; i < metadata.getDependencies().length; i++) {
+ String dep = metadata.getDependencies()[i];
+ Artifact artifact = Artifact.create(dep);
+ if(!artifact.isResolved()) {
+ throw new MissingDependencyException("Configuration list "+metadata.getName()+" may not use partal artifact names for dependencies ("+dep+")");
+ }
+ }
}
// 2. Check that we meet the prerequisites
ConfigurationMetadata.Prerequisite[] prereqs = metadata.getPrerequisites();
@@ -442,7 +537,12 @@
* are not accepted
* @throws MissingDependencyException When a dependency cannot be located in any of the listed repositories
*/
- private void downloadArtifact(Artifact configID, URL repoURL, URL[] backups, String username, String password, ResultsFileWriteMonitor monitor) throws IOException, FailedLoginException, MissingDependencyException {
+ private void downloadArtifact(Artifact configID, URL repoURL, URL[] backups, String username, String password, ResultsFileWriteMonitor monitor, Set soFar) throws IOException, FailedLoginException, MissingDependencyException {
+ if(soFar.contains(configID)) {
+ return; // Avoid enless work due to circular dependencies
+ } else {
+ soFar.add(configID);
+ }
//todo: check all repositories?
if(!writeableRepo.contains(configID)) {
InputStream in = openStream(configID, repoURL, backups, username, password, monitor);
@@ -469,7 +569,7 @@
for (int i = 0; i < dependencies.length; i++) {
Dependency dep = dependencies[i];
Artifact artifact = dep.getArtifact();
- downloadArtifact(artifact, repoURL, backups, username, password, monitor);
+ downloadArtifact(artifact, repoURL, backups, username, password, monitor, soFar);
}
} catch (NoSuchConfigException e) {
throw new IllegalStateException("Installed configuration into repository but ConfigStore does not see it: "+e.getMessage());
@@ -496,7 +596,7 @@
* Used to get dependencies for a Configuration
*/
private static Dependency[] getDependencies(ConfigurationData data) {
- List dependencies = data.getEnvironment().getDependencies();
+ List dependencies = new ArrayList(data.getEnvironment().getDependencies());
Collection children = data.getChildConfigurations().values();
for (Iterator it = children.iterator(); it.hasNext();) {
ConfigurationData child = (ConfigurationData) it.next();
@@ -511,6 +611,8 @@
private static InputStream openStream(Artifact artifact, URL repo, URL[] backups, String username, String password, ResultsFileWriteMonitor monitor) throws IOException, FailedLoginException, MissingDependencyException {
if(monitor != null) {
+ monitor.getResults().setCurrentFilePercent(-1);
+ monitor.getResults().setCurrentMessage("Attempting to download "+artifact);
monitor.setTotalBytes(-1); // In case the server doesn't say
}
InputStream in;
Modified: geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigurationMetadata.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigurationMetadata.java?rev=394827&r1=394826&r2=394827&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigurationMetadata.java (original)
+++ geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/ConfigurationMetadata.java Mon Apr 17 19:49:26 2006
@@ -33,9 +33,11 @@
private final boolean installed;
private final boolean eligible;
private String[] dependencies;
+ private String[] obsoletes;
private License[] licenses;
private String[] geronimoVersions;
private String[] jvmVersions;
+ private String[] forceStart;
private Prerequisite[] prerequisites;
public ConfigurationMetadata(Artifact configId, String name, String description, String category, boolean installed, boolean eligible) {
@@ -51,6 +53,14 @@
this.dependencies = dependencies;
}
+ public void setObsoletes(String[] obsoletes) {
+ this.obsoletes = obsoletes;
+ }
+
+ public void setForceStart(String[] forceStart) {
+ this.forceStart = forceStart;
+ }
+
/**
* Gets the Config ID for this configuration, which is a globally unique
* identifier.
@@ -92,11 +102,28 @@
/**
* Gets the JAR or configuration dependencies for this configuration, Each
- * String in the result is an Artifact (or Config ID) in String form. The
- * dependency names may be partial artifact names
+ * String in the result is an Artifact (or Config ID) in String form.
+ * Generally speaking, the dependency names may be partial artifact names
+ * (but not, for example, if this whole thing is a plugin list).
*/
public String[] getDependencies() {
return dependencies;
+ }
+
+ /**
+ * Gets the configurations obsoleted by this configuration. Each
+ * String in the result is an Artifact (or Config ID) in String form.
+ */
+ public String[] getObsoletes() {
+ return obsoletes;
+ }
+
+ /**
+ * Gets the configurations that should definitely be started when the
+ * install process completes.
+ */
+ public String[] getForceStart() {
+ return forceStart;
}
public String[] getGeronimoVersions() {
Modified: geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadPoller.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadPoller.java?rev=394827&r1=394826&r2=394827&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadPoller.java (original)
+++ geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadPoller.java Mon Apr 17 19:49:26 2006
@@ -22,27 +22,88 @@
* An interface for callers who want to monitor the progress of an installation.
* These are all callbacks sent by the server.
*
+ * @see ConfigurationInstaller
+ *
* @version $Rev: 46019 $ $Date: 2004-09-14 05:56:06 -0400 (Tue, 14 Sep 2004) $
*/
public interface DownloadPoller {
- void addInstalledConfigID(Artifact dep);
-
+ /**
+ * Notes a configuration that was removed because it was obsoleted by a
+ * newly-installed configuration.
+ */
+ void addRemovedConfigID(Artifact obsolete);
+
+ /**
+ * Notes that a configuration passed as an argument to the install
+ * operation was successfully installed. This will only be called on
+ * the original arguments to the install command, not on anything
+ * installed because it was a dependency.
+ */
+ void addInstalledConfigID(Artifact target);
+
+ /**
+ * Notes that a configuration was restarted as a result of the
+ * current operation. This usually means that it depended on a
+ * configuration that was obsoleted (removed), so it shut down when
+ * the remove happened, and was started up again after the replacement
+ * was installed.
+ */
+ void addRestartedConfigID(Artifact target);
+
+ /**
+ * Notes that the current install operation found a dependency, and that
+ * dependency was satisfied by an artifact already available in the
+ * current server environment.
+ */
void addDependencyPresent(Artifact dep);
+ /**
+ * Notes that the current install operation found a dependency, and that
+ * dependency was downloaded from a remote repository and installed into
+ * the local server environment.
+ */
void addDependencyInstalled(Artifact dep);
+ /**
+ * Indicates which file the configuration installer is working on at the
+ * moment. Mainly for purposes of user feedback during asynchronous
+ * requests.
+ */
void setCurrentFile(String currentFile);
+ /**
+ * Describes the current operation status as a text message. Mainly for
+ * purposes of user feedback during asynchronous requests.
+ */
void setCurrentMessage(String currentMessage);
+ /**
+ * Gives the percent complete for a file currently being downloaded.
+ * Mainly for purposes of user feedback during asynchronous requests.
+ * This may be -1 if the download server does not supply the file size in
+ * advance.
+ */
void setCurrentFilePercent(int currentFileProgress);
+ /**
+ * Called at the end of a file download with the number of bytes downloaded
+ * in the current operation. This can be used to calculate a rough
+ * transfer rate (the time between setCurrentFile and setDownloadBytes) as
+ * well as if the caller wants to total the size of all downloads for the
+ * current installation.
+ */
void addDownloadBytes(long bytes);
+ /**
+ * Indicates that a failure was encountered during the installation
+ * operation. Any failure is currently treated as fatal -- the installer
+ * will not attempt to complete additional tasks after a failure.
+ */
void setFailure(Exception failure);
/**
- * This will be called even in the event of a failure.
+ * Always called when the operation is complete, regardless of whether
+ * there was a failure or not.
*/
void setFinished();
}
Modified: geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadResults.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadResults.java?rev=394827&r1=394826&r2=394827&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadResults.java (original)
+++ geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/configuration/DownloadResults.java Mon Apr 17 19:49:26 2006
@@ -28,6 +28,8 @@
* @version $Rev: 46019 $ $Date: 2004-09-14 05:56:06 -0400 (Tue, 14 Sep 2004) $
*/
public class DownloadResults implements Serializable, DownloadPoller {
+ private List removedConfigIDs = new ArrayList();
+ private List restartedConfigIDs = new ArrayList();
private List installedConfigIDs = new ArrayList();
private List dependenciesPresent = new ArrayList();
private List dependenciesInstalled = new ArrayList();
@@ -42,6 +44,14 @@
installedConfigIDs.add(dep);
}
+ public void addRemovedConfigID(Artifact obsolete) {
+ removedConfigIDs.add(obsolete);
+ }
+
+ public void addRestartedConfigID(Artifact target) {
+ restartedConfigIDs.add(target);
+ }
+
public void addDependencyPresent(Artifact dep) {
dependenciesPresent.add(dep);
}
@@ -63,6 +73,7 @@
}
public void setFailure(Exception failure) {
+failure.printStackTrace();
this.failure = failure;
}
@@ -106,6 +117,14 @@
*/
public Artifact[] getInstalledConfigIDs() {
return (Artifact[]) installedConfigIDs.toArray(new Artifact[installedConfigIDs.size()]);
+ }
+
+ public Artifact[] getRemovedConfigIDs() {
+ return (Artifact[]) removedConfigIDs.toArray(new Artifact[installedConfigIDs.size()]);
+ }
+
+ public Artifact[] getRestartedConfigIDs() {
+ return (Artifact[]) restartedConfigIDs.toArray(new Artifact[installedConfigIDs.size()]);
}
/**
Modified: geronimo/branches/1.1/modules/system/src/schema/config-list.xsd
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.1/modules/system/src/schema/config-list.xsd?rev=394827&r1=394826&r2=394827&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/system/src/schema/config-list.xsd (original)
+++ geronimo/branches/1.1/modules/system/src/schema/config-list.xsd Mon Apr 17 19:49:26 2006
@@ -103,11 +103,18 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="config-id" type="xs:string">
+ <xs:element name="config-id" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
The Geronimo configId for this configuration, which uniquely identifies
- it, and also is used to construct a path to download it if necessary
+ it, and also is used to construct a path to download it if necessary.
+
+ If no config-id is provided, that means this is a plugin group, which is
+ just a list of other plugins to install. The prerequisites must still be
+ met, but then the dependencies listed for this configuration will be
+ treated as the list of actual configuraitons to install. NOTE: for plugin
+ lists, each of the dependencies must be a full config-id; entries without
+ a version number for example will not work.
</xs:documentation>
</xs:annotation>
</xs:element>
@@ -234,6 +241,28 @@
</xs:documentation>
</xs:annotation>
</xs:element>
+ <xs:element name="obsoletes" type="xs:string" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+ The configId of another configuration that this configuration replaces.
+ That can be used, for example, to replace a less functional configuration
+ with a more functional one, or to upgrade a component to a newer version.
+
+ This is applied as an exact match, except that the version number may be
+ omitted, in which case any matching version of the configuration will be
+ replaced. Be aware that omitting the version number may cause a
+ configuration to be downgraded, so you may choose to explicitly list all
+ lesser versions. That may not be desirable either, though. If the
+ server has foo-1.0.2 installed and you install foo-1.0.1, would you
+ rather have it downgrade or end up with both installed?
+
+ NOTE: currently the "obsoletes" entries are only processed on the
+ configuration(s) passed directly to the ConfigurationInstaller (not on
+ dependencies that are brought down as a result). That means that a
+ plugin group must list obsoletes for all its components, etc.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
</xs:sequence>
</xs:complexType>
@@ -261,6 +290,34 @@
</xs:simpleContent>
</xs:complexType>
+ <xs:complexType name="dependencyType">
+ <xs:annotation>
+ <xs:documentation>
+ See configurationType/dependency above
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="start" use="optional" type="xs:boolean" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ Normally when a configuration dependency is installed it will not
+ be started. The user may be prompted to start the configuration
+ with whatever tool kicked off the install to begin with.
+
+ This attribute may be set to "true" to force the dependency to
+ be started after it is installed. NOTE: this currently only
+ affects the dependencies of the configurations actually passed to
+ the Configuration Installer (not nested dependencies). This
+ means it's primarily useful for plugin lists.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
<xs:complexType name="prerequisiteType">
<xs:sequence>
<xs:element name="id" type="xs:string">
@@ -280,7 +337,7 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="resource-type" type="xs:string">
+ <xs:element name="resource-type" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
Describes the type of resource that the prerequisite is. Examples
@@ -309,7 +366,7 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="description" type="xs:string">
+ <xs:element name="description" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
A description for the user about why this is a prerequisite and what