I have extended the applications code with a mechanism for adding dependency between applications.
Using this hack, you can make a other applications required for the current one, and have these automatically installed too (before the current application is installed)
This calls is about including this fix in 1.7.
I will check the change in in CVS Head so people can try this out (we can roll back if people think its a dumb hack).
If approved, the 'requires' mechanism will be added to application documentation.
Since we don't have a hacktracker, I will check info in as a 'wish' bug once the call is approved.
Hack Doc:
Created by: Pierre van Rooden
Hack date: 13/3/2003
Design: A new attribute is added to the application dtd. This attribute (requires) can be retrieved using ApplicationReader.java, using a new method getApplicationRequires. The private MMAdmin method installApplication now checks for this attribute. I migrated all application-instantiating code to this method, and maintain a set of applications that are being 'installed' to catch circular references.
Also added code so Applicationwriter writes the new attribute;
Functionality:
You can list applications required for the current application by setting a comma-delimited attribute in the application xml file.
For instance:
<application name="MyApp" maintainer="mmbase.org" version="1" requires="Basic,Security" auto-deploy="true">
...
The listed applications are then installed prior to installation of the current application. If the applications have in turn other required applications, these are installed too.
Circular references are not allowed.
Auto-deploy settings are only checked on the initial application.
Installation: not applicable
Working example: appropriated changes will be made in MyNews.xml
Code:
MMAdmin.java:
changed: private installApplication(String applicationname, applicationResult result,Set installationSet, boolean autoDeploy)
changed the calls to this private method
ApplicationReader.java: added: public List getApplicationRequires()
ApplicationWriter.java:
changed: writeXMLFile(XMLApplicationReader app, String targetpath, String goal, MMBase mmb)
application_1_1.dtd : added: requires entity
START OF CALL: Thursday 13 march 2003
END OF CALL: Tuesday 18 march 2003
[_] +1 (YEA)
[_] +0 (ABSTAIN )
[_] -1 (NAY), because :
[_] VETO, because:
-- Pierre van Rooden Mediapark, C 107 tel. +31 (0)35 6772815 "Never summon anything bigger than your head."
? appdiff.txt
Index: module/tools/MMAdmin.java
===================================================================
RCS file: /usr/local/cvs/src/org/mmbase/module/tools/MMAdmin.java,v
retrieving revision 1.59
diff -b -r1.59 MMAdmin.java
204d203
< Versions ver=(Versions)mmb.getMMObject("versions");
206,237c205
< String
path=MMBaseContext.getConfigPath()+File.separator+"applications"+File.separator;
< XMLApplicationReader app=new
XMLApplicationReader(path+appname+".xml");
< if (app!=null) {
< String name=app.getApplicationName();
< String maintainer=app.getApplicationMaintainer();
< int version=app.getApplicationVersion();
< int installedversion=ver.getInstalledVersion(name,"application");
< if (installedversion==-1 || version>installedversion) {
< if (installedversion==-1) {
< log.info("Installing application : "+name);
< } else {
< log.info("installing application : "+name+" new version
from "+installedversion+" to "+version);
< }
< if (installApplication(name,result)) {
< result.success("Application loaded oke\n\n"+
< "The application has the following
install notice for you : \n\n"+
< app.getInstallNotice());
< if (installedversion==-1) {
<
ver.setInstalledVersion(name,"application",maintainer,version);
< } else {
<
ver.updateInstalledVersion(name,"application",maintainer,version);
< }
< }
< } else {
< result.success("Application was allready loaded (or a higher
version)\n\n"+
< "To remind you here is the install notice for
you again : \n\n"+
< app.getInstallNotice());
< }
< } else {
< result.error("Install error: can't find xml file:
"+path+appname+".xml");
< }
< if (result.isSuccess()) {
---
> if (installApplication(appname,result,new HashSet(),false)) {
549c517
< lastmsg="Server Reset requested by '"+user+"' Restart in 3
seconds<BR><BR>\n";
---
> lastmsg="Server Reset requested by '"+user+"' Restart in 3 seconds<br /><br
> />\n";
567,568c535,536
< lastmsg="Started a instance of the MMAppTool with path : <BR><BR>\n";
< lastmsg+=path+File.separator+appname+".xml<BR><BR>\n";
---
> lastmsg="Started a instance of the MMAppTool with path : <br /><br />\n";
> lastmsg+=path+File.separator+appname+".xml<br /><br />\n";
573,575c541,556
< * @javadoc
< */
< private boolean installApplication(String applicationname, ApplicationResult
result) {
---
> * Installs the application
> * @param applicationname Name of the application file, without the xml extension
> * This is also assumed to be the name of teh application
> itself
> * (if not, a warning will be issued)
> * @param result the result object, containing error messages when the
> installation fails,
> or the installnotice if succesfull or already installed
> * @param installationSet set of installations that are currently being
> installed.
> * used to check if there are circular dependencies
> * @param autoDeploy if true, the installation is only installed if the
> application is set to autodeploy
> * @return true if succesfull, false otherwise
> */
> private boolean installApplication(String applicationname, ApplicationResult
> result,
> Set installationSet, boolean autoDeploy) {
> if (installationSet.contains(applicationname)) {
> return result.error("Circular reference to application with name
> "+applicationname);
> }
577a559
> Versions ver=(Versions)mmb.getMMObject("versions");
579,584c561,579
< if (installBuilders(app.getNeededBuilders(), path +
applicationname,result)) {
< if (installRelDefs(app.getNeededRelDefs(),result)) {
< if (installAllowedRelations(app.getAllowedRelations(),result)) {
< if (installDataSources(app.getDataSources(),applicationname,
result)) {
< if (!installRelationSources(app.getRelationSources(),
result)) {
< result.error("Application installer stopped : can't
install relationsources");
---
> // test autodeploy
> if (autoDeploy && !app.getApplicationAutoDeploy()) {
> return true;
> }
> // should be installed - add to installation set
> installationSet.add(applicationname);
> List requires=app.getApplicationRequires();
> for (Iterator i=requires.iterator(); i.hasNext();) {
> String appname= (String)i.next();
> log.service("Application '"+applicationname+"' requires : "+appname);
> if (!installApplication(appname,result,installationSet,false)) {
> return false;
> }
> }
> // note: currently name and application file name should be the same
> String name=app.getApplicationName();
> if(!name.equals(applicationname)) {
> result.warn("Application name "+name+" not the same as the base
> filename "+applicationname+".\n"+
> "This may cause problems when referring to this
> application.");
585a581,588
> String maintainer=app.getApplicationMaintainer();
> int version=app.getApplicationVersion();
> int installedversion=ver.getInstalledVersion(name,"application");
> if (installedversion==-1 || version>installedversion) {
> if (installedversion==-1) {
> log.info("Installing application : "+name);
> } else {
> log.info("installing application : "+name+" new version from
> "+installedversion+" to "+version);
586a590,598
> if (installBuilders(app.getNeededBuilders(), path +
> applicationname,result) &&
> installRelDefs(app.getNeededRelDefs(),result) &&
> installAllowedRelations(app.getAllowedRelations(),result) &&
> installDataSources(app.getDataSources(),applicationname, result)
> &&
> installRelationSources(app.getRelationSources(), result)) {
> if (installedversion==-1) {
>
> ver.setInstalledVersion(name,"application",maintainer,version);
> } else {
>
> ver.updateInstalledVersion(name,"application",maintainer,version);
587a600,613
> log.info("Application '"+name+"' deployed succesfully.");
> result.success("Application loaded oke\n\n"+
> "The application has the following install notice
> for you : \n\n"+
> app.getInstallNotice());
> }
> // installed or failed - remove from installation set
> installationSet.remove(applicationname);
> } else {
> // only return this message if the application is the main (first)
> application
> // and if it was not auto-deployed (as in that case messages would
> not be deemed very useful)
> if (installationSet.size()==1) {
> result.success("Application was allready loaded (or a higher
> version)\n\n"+
> "To remind you here is the install notice for you
> again : \n\n"+
> app.getInstallNotice());
591c617
< result.error("Can't install application : "+path+applicationname+".xml");
---
> result.error("Install error: can't find xml file:
> "+path+applicationname+".xml");
640d665
< log.info(importnode.toString());
1073,1084d1097
< XMLApplicationReader app=new XMLApplicationReader(path+aname);
< if (app!=null && app.getApplicationAutoDeploy()) {
< String name=app.getApplicationName();
< String maintainer=app.getApplicationMaintainer();
< int version=app.getApplicationVersion();
< int
installedversion=ver.getInstalledVersion(name,"application");
< if (installedversion==-1 || version>installedversion) {
< if (installedversion==-1) {
< log.info("Auto deploy application : "+aname+"
started");
< } else {
< log.info("Auto deploy application : "+aname+" new
version from "+installedversion+" to "+version);
< }
1086,1097c1099,1100
< if
(installApplication(aname.substring(0,aname.length()-4),result)) {
< if (installedversion==-1) {
<
ver.setInstalledVersion(name,"application",maintainer,version);
< } else {
<
ver.updateInstalledVersion(name,"application",maintainer,version);
< }
< log.info("Auto deploy application : "+aname+" done");
< } else {
< log.error("Problem installing application : "+name);
< }
< }
<
---
> if
> (!installApplication(aname.substring(0,aname.length()-4),result,new HashSet(),true))
> {
> log.error("Problem installing application : "+aname);
1115,1116c1118,1119
< lastmsg="Application saved oke<BR><BR>\n";
< lastmsg+="Some statistics on the save : <BR><BR>\n";
---
> lastmsg="Application saved oke<br /><br />\n";
> lastmsg+="Some statistics on the save : <br /><br />\n";
1119c1122
< lastmsg+=result+"<BR><BR>\n";
---
> lastmsg+=result+"<br /><br />\n";
1916c1919,1920
< resultMessage += "\n"+message;
---
> if (!resultMessage.equals("")) resultMessage += "\n";
> resultMessage += message;
1923c1927,1928
< resultMessage += "\n"+message;
---
> if (!resultMessage.equals("")) resultMessage += "\n";
> resultMessage += message;
1929c1934,1935
< resultMessage += "\n"+message;
---
> if (!resultMessage.equals("")) resultMessage += "\n";
> resultMessage += message;
Index: util/XMLApplicationReader.java
===================================================================
RCS file: /usr/local/cvs/src/org/mmbase/util/XMLApplicationReader.java,v
retrieving revision 1.16
diff -b -r1.16 XMLApplicationReader.java
72a73,86
> /**
> * Get the applicationlist required by this application
> */
> public List getApplicationRequires() {
> String requires=getElementAttributeValue(root,"requires");
> List ls = new Vector();
> StringTokenizer tok = new StringTokenizer(requires,",");
> while (tok.hasMoreTokens()) {
> String appname=tok.nextToken();
> ls.add(appname);
> }
> return ls;
> }
>
Index: util/XMLApplicationWriter.java
===================================================================
RCS file: /usr/local/cvs/src/org/mmbase/util/XMLApplicationWriter.java,v
retrieving revision 1.20
diff -b -r1.20 XMLApplicationWriter.java
15,17c15
< import java.util.Enumeration;
< import java.util.Hashtable;
< import java.util.Vector;
---
> import java.util.*;
44,48c42,53
< String name =app.getApplicationName();
< String maintainer =app.getApplicationMaintainer();
< int version =app.getApplicationVersion();
< boolean deploy =app.getApplicationAutoDeploy();
<
---
> String name = app.getApplicationName();
> String maintainer = app.getApplicationMaintainer();
> int version = app.getApplicationVersion();
> boolean deploy = app.getApplicationAutoDeploy();
>
> List requireslist = app.getApplicationRequires();
> String requires = "";
> for (Iterator i = requireslist.iterator(); i.hasNext();) {
> String appname = (String)i.next();
> if (!requires.equals("")) requires += ",";
> requires += appname;
> }
52c57,61
< "<application name=\""+name+"\" maintainer=\""+maintainer+"\"
version=\""+version+"\" auto-deploy=\""+deploy+"\">\n";
---
> "<application name=\"" + name +
> "\" maintainer=\"" + maintainer +
> "\" requires=\"" + requires +
> "\" version=\"" + version +
> "\" auto-deploy=\"" + deploy + "\">\n";<!--
application.dtd
- DTD for MMBase builder definitions
-->
<!ELEMENT application (neededbuilderlist,neededreldeflist,allowedrelationlist,datasourcelist,relationsourcelist,contextsourcelist,description?,install-notice?)>
<!ATTLIST application name CDATA #REQUIRED>
<!ATTLIST application requires CDATA #IMPLIED>
<!ATTLIST application maintainer CDATA #IMPLIED>
<!ATTLIST application version CDATA #IMPLIED>
<!ATTLIST application auto-deploy CDATA #IMPLIED>
<!ELEMENT neededbuilderlist (builder*)>
<!ELEMENT builder (#PCDATA)>
<!ATTLIST builder maintainer CDATA #IMPLIED>
<!ATTLIST builder version CDATA #IMPLIED>
<!ELEMENT neededreldeflist (reldef*)>
<!ELEMENT reldef EMPTY>
<!ATTLIST reldef source CDATA #REQUIRED>
<!ATTLIST reldef target CDATA #REQUIRED>
<!ATTLIST reldef direction CDATA #IMPLIED>
<!ATTLIST reldef guisourcename CDATA #IMPLIED>
<!ATTLIST reldef guitargetname CDATA #IMPLIED>
<!ATTLIST reldef builder CDATA #IMPLIED>
<!ELEMENT allowedrelationlist (relation*)>
<!ELEMENT relation EMPTY>
<!ATTLIST relation from CDATA #REQUIRED>
<!ATTLIST relation to CDATA #REQUIRED>
<!ATTLIST relation type CDATA #REQUIRED>
<!ELEMENT datasourcelist (datasource*)>
<!ELEMENT datasource EMPTY>
<!ATTLIST datasource path CDATA #REQUIRED>
<!ATTLIST datasource builder CDATA #REQUIRED>
<!ELEMENT relationsourcelist (relationsource*)>
<!ELEMENT relationsource EMPTY>
<!ATTLIST relationsource path CDATA #REQUIRED>
<!ATTLIST relationsource builder CDATA #REQUIRED>
<!ELEMENT contextsourcelist (contextsource*)>
<!ELEMENT contextsource EMPTY>
<!ATTLIST contextsource path CDATA #REQUIRED>
<!ATTLIST contextsource type CDATA #REQUIRED>
<!ATTLIST contextsource goal CDATA #REQUIRED>
<!ELEMENT description (#PCDATA)>
<!ELEMENT install-notice (#PCDATA)>
