Called by: Pierre van Rooden Total tally on this call : +9
YEA (9) : Eduard Witteveen, Johannes Verelst, Daniel Ockeloen, Rob Vermeulen, Kees Jongenburger, Rico Jansen, Nico Klasens, Rob van Maris, Michiel Meeuwissen
ABSTAIN (0) :
NAY (0) :
VETO (0) :
No votes, assumed abstained (6): Jaco de Groot, Marcel Maatkamp, David van Zeventer, Wilbert Hengst, Gerard van Enk, Mark Huijser
Call Result:
Hack is accepted and will be included in MMBase 1.7
'requirements' will be a tag.
Application-dependecy will be verified using maintainer and version information (optional attributes).
Pierre van Rooden wrote:
Hi,
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:
------------------------------------------------------------------------
? 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)>
-- Pierre van Rooden Mediapark, C 107 tel. +31 (0)35 6772815 "Never summon anything bigger than your head."
