KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > module > tools > ApplicationInstaller


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.module.tools;
11
12 import java.util.*;
13
14 import org.mmbase.bridge.Field;
15 import org.mmbase.core.CoreField;
16 import org.mmbase.module.builders.Versions;
17 import org.mmbase.module.core.*;
18 import org.mmbase.module.corebuilders.*;
19 import org.mmbase.storage.search.*;
20 import org.mmbase.storage.search.implementation.*;
21 import org.mmbase.util.*;
22 import org.mmbase.util.logging.Logger;
23 import org.mmbase.util.logging.Logging;
24 import org.mmbase.util.xml.ApplicationReader;
25 import org.xml.sax.InputSource JavaDoc;
26
27
28 /**
29  * Application installations functionalite of MMAdmin.
30  *
31  * @author Nico Klasens
32  * @since MMBase-1.8
33  * @version $Id: ApplicationInstaller.java,v 1.8.2.1 2006/12/05 21:07:35 michiel Exp $
34  */

35 public class ApplicationInstaller {
36
37     private static final Logger log = Logging.getLoggerInstance(ApplicationInstaller.class);
38
39     /**
40      * reference to MMBase
41      */

42     private MMBase mmb = null;
43
44     public ApplicationInstaller(MMBase mmb) {
45         this.mmb = mmb;
46     }
47
48     public void installApplications() throws SearchQueryException {
49         ResourceLoader applicationLoader = ResourceLoader.getConfigurationRoot().getChildResourceLoader("applications");
50         Iterator i = applicationLoader.getResourcePaths(ResourceLoader.XML_PATTERN, false).iterator();
51         while (i.hasNext()) {
52             String JavaDoc appResource = (String JavaDoc) i.next();
53             ApplicationResult result = new ApplicationResult();
54             if (!installApplication(appResource.substring(0, appResource.length() - 4), -1, null, result, new HashSet(), true)) {
55                 log.error("Problem installing application : " + appResource + ", cause: \n" + result.getMessage());
56             }
57         }
58     }
59
60     /**
61      * Installs the application
62      * @param applicationName Name of the application file, without the xml extension
63      * This is also assumed to be the name of teh application itself
64      * (if not, a warning will be issued)
65      * @param result the result object, containing error messages when the installation fails,
66      * or the installnotice if succesfull or already installed
67      * @param installationSet set of installations that are currently being installed.
68      * used to check if there are circular dependencies
69      * @param autoDeploy if true, the installation is only installed if the application is set to autodeploy
70      * @return true if succesfull, false otherwise
71      */

72     public boolean installApplication(String JavaDoc applicationName, int requiredVersion,
73             String JavaDoc requiredMaintainer, ApplicationResult result, Set installationSet,
74             boolean autoDeploy) throws SearchQueryException {
75
76         if (installationSet.contains(applicationName)) {
77             return result.error("Circular reference to application with name " + applicationName);
78         }
79
80         ApplicationReader reader = getApplicationReader(applicationName);
81         Versions ver = (Versions)mmb.getMMObject("versions");
82         if (reader != null) {
83             // test autodeploy
84
if (autoDeploy && !reader.hasAutoDeploy()) {
85                 return true;
86             }
87             String JavaDoc name = reader.getName();
88             String JavaDoc maintainer = reader.getMaintainer();
89             if (requiredMaintainer != null && !maintainer.equals(requiredMaintainer)) {
90                 return result.error("Install error: " + name + " requires maintainer '" + requiredMaintainer +
91                                     "' but found maintainer '" + maintainer + "'");
92             }
93             int version = reader.getVersion();
94             if (requiredVersion != -1 && version != requiredVersion) {
95                 return result.error("Install error: " + name + " requires version '" + requiredVersion +
96                                     "' but found version '" + version + "'");
97             }
98             int installedVersion = ver.getInstalledVersion(name, "application");
99             if (installedVersion == -1 || version > installedVersion) {
100                 if (!name.equals(applicationName)) {
101                     result.warn("Application name " + name + " not the same as the base filename " + applicationName + ".\n"
102                                 + "This may cause problems when referring to this application.");
103                 }
104                 // We should possibly check whether the maintainer is valid here (see sample code below).
105
// There is currently no way to do this, though, unless we use awful queries.
106
// what we need is a getInstalledMaintainer() method on the Versions builder
107
/* sample code
108                 String installedMaintainer=ver.getInstalledMaintainer(name,"application");
109                 if (!maintainer.equals(installedAppMaintainer)) {
110                     return result.error("Install error: "+name+" is of maintainer '"+maintainer+"' but installed application is of maintainer '"+installedMaintainer+"'");
111                 }
112                  */

113                 // should be installed - add to installation set
114
installationSet.add(applicationName);
115                 List requires = reader.getRequirements();
116                 for (Iterator i = requires.iterator(); i.hasNext();) {
117                     Map reqapp = (Map)i.next();
118                     String JavaDoc reqType = (String JavaDoc)reqapp.get("type");
119                     if (reqType == null || reqType.equals("application")) {
120                         String JavaDoc appName = (String JavaDoc)reqapp.get("name");
121                         int installedAppVersion = ver.getInstalledVersion(appName, "application");
122                         String JavaDoc appMaintainer = (String JavaDoc)reqapp.get("maintainer");
123                         int appVersion = -1;
124                         try {
125                             String JavaDoc appVersionAttr = (String JavaDoc)reqapp.get("version");
126                             if (appVersionAttr != null)
127                                 appVersion = Integer.parseInt(appVersionAttr);
128                         } catch (Exception JavaDoc e) {}
129                         if (installedAppVersion == -1 || appVersion > installedAppVersion) {
130                             log.service("Application '" + applicationName + "' requires : " + appName);
131                             if (!installApplication(appName, appVersion, appMaintainer,
132                                 result, installationSet, false)) {
133                                 return false;
134                             }
135                         } else if (appMaintainer != null) {
136                             // we should possibly check whether the maintainer is valid here (see sample code below).
137
// There is currently no way to do this, though, unless we use awful queries.
138
// what we need is a getInstalledMaintainer() method on the Versions builder
139
/* sample code
140                             String installedAppMaintainer=ver.getInstalledMaintainer(name,"application");
141                             if (!appMaintainer.equals(installedAppMaintainer)) {
142                                 return result.error("Install error: "+name+" requires maintainer '"+appMaintainer+"' but found maintainer '"+installedAppMaintainer+"'");
143                             }
144                              */

145                         }
146                     }
147                 }
148                 // note: currently name and application file name should be the same
149
if (installedVersion == -1) {
150                     log.info("Installing application : " + name);
151                 } else {
152                     log.info("installing application : " + name + " new version from " + installedVersion + " to " + version);
153                 }
154                 if (installBuilders(reader.getNeededBuilders(), "applications/" + applicationName, result)
155                     && installRelDefs(reader.getNeededRelDefs(), result)
156                     && installAllowedRelations(reader.getAllowedRelations(), result)
157                     && installDataSources(reader.getDataSources(), applicationName, result)
158                     && installRelationSources(reader.getRelationSources(), applicationName, result)) {
159
160                     if (installedVersion == -1) {
161                         ver.setInstalledVersion(name, "application", maintainer, version);
162                     } else {
163                         ver.updateInstalledVersion(name, "application", maintainer, version);
164                     }
165                     log.info("Application '" + name + "' deployed succesfully.");
166                     result.success(
167                         "Application loaded oke\n\n"
168                             + "The application has the following install notice for you : \n\n"
169                             + reader.getInstallNotice());
170                 }
171                 // installed or failed - remove from installation set
172
installationSet.remove(applicationName);
173             } else {
174                 // only return this message if the application is the main (first) application
175
// and if it was not auto-deployed (as in that case messages would not be deemed very useful)
176
if (installationSet.size() == 1) {
177                     result.success(
178                         "Application was allready loaded (or a higher version)\n\n"
179                             + "To remind you here is the install notice for you again : \n\n"
180                             + reader.getInstallNotice());
181                 }
182             }
183         } else {
184             result.error("Install error: can't find xml file: applications/" + applicationName + ".xml");
185         }
186         return result.isSuccess();
187     }
188
189     /**
190      * @javadoc
191      * @since MMBase-1.7
192      */

193     protected boolean installDataSources(List dataSources, String JavaDoc appName, ApplicationResult result) {
194         MMObjectBuilder syncbul = mmb.getMMObject("syncnodes");
195
196         List nodeFieldNodes = new ArrayList(); // a temporary list with all nodes that have NODE fields, which should be synced, later.
197
if (syncbul != null) {
198             for (Iterator h = dataSources.iterator(); h.hasNext();) {
199                 Map bh = (Map) h.next();
200                 XMLNodeReader nodeReader = getNodeReader(bh, appName);
201                 if (nodeReader == null) {
202                     continue;
203                 }
204                 else {
205                     installDatasource(syncbul, nodeReader, nodeFieldNodes, result);
206                 }
207             }
208
209             treatNodeFields(nodeFieldNodes, syncbul);
210
211             return result.isSuccess();
212         } else {
213             return result.error("Application installer : can't reach syncnodes builder"); //
214
}
215     }
216
217     private void installDatasource(MMObjectBuilder syncbul, XMLNodeReader nodeReader, List nodeFieldNodes, ApplicationResult result) {
218         String JavaDoc exportsource = nodeReader.getExportSource();
219         int timestamp = nodeReader.getTimeStamp();
220
221         // loop all nodes , and add to syncnodes.
222
for (Iterator n = nodeReader.getNodes(mmb).iterator(); n.hasNext();) {
223             try {
224                 MMObjectNode newNode = (MMObjectNode)n.next();
225
226                 int exportnumber = newNode.getIntValue("number");
227                 if (existsSyncnode(syncbul, exportsource, exportnumber)) {
228                     // XXX To do : we may want to load the node and check/change the fields
229
log.debug("node allready installed : " + exportnumber);
230                 } else {
231                     newNode.setValue("number", -1);
232                     int localnumber = doKeyMergeNode(syncbul, newNode, exportsource, result);
233                     if (localnumber != -1) { // this node was not yet imported earlier
234
createSyncnode(syncbul, exportsource, timestamp, exportnumber, localnumber);
235                         if (localnumber == newNode.getNumber()) {
236                             findFieldsOfTypeNode(nodeFieldNodes, exportsource, newNode);
237                         }
238                     }
239                 }
240             }
241             catch (SearchQueryException sqe) {
242                 log.error(sqe);
243             }
244         }
245     }
246
247     private void findFieldsOfTypeNode(List nodeFieldNodes, String JavaDoc exportsource, MMObjectNode newNode) {
248         // determine if there were NODE fields, which need special treatment later.
249
Collection fields = newNode.getBuilder().getFields();
250         Iterator i = fields.iterator();
251         while (i.hasNext()) {
252             CoreField field = (CoreField) i.next();
253
254             // Fields with type NODE and notnull=true will be handled
255
// by the doKeyMergeNode() method.
256
if (field.getType() == Field.TYPE_NODE
257                     && ! field.getName().equals("number")
258                     && ! field.isRequired()) {
259
260                 newNode.storeValue("__exportsource", exportsource);
261                 nodeFieldNodes.add(newNode);
262                 break;
263             }
264         }
265     }
266
267     private void treatNodeFields(List nodeFieldNodes, MMObjectBuilder syncbul) {
268         Iterator i = nodeFieldNodes.iterator();
269         while (i.hasNext()) {
270             MMObjectNode importedNode = (MMObjectNode) i.next();
271             String JavaDoc exportsource = (String JavaDoc) importedNode.getValues().get("__exportsource");
272             // clean it up
273
importedNode.storeValue("__exportsource", null); // hack to remove it.
274

275             Collection fields = importedNode.getBuilder().getFields();
276             Iterator j = fields.iterator();
277             while (j.hasNext()) {
278                 CoreField def = (CoreField) j.next();
279                 String JavaDoc fieldName = def.getName();
280                 if (def.getType() == Field.TYPE_NODE &&
281                     !fieldName.equals("number") &&
282                     !fieldName.equals("snumber") &&
283                     !fieldName.equals("dnumber") &&
284                     !fieldName.equals("rnumber")
285                    ) {
286
287                     updateFieldWithTypeNode(syncbul, importedNode, exportsource, fieldName);
288                 }
289             }
290             if (importedNode.isChanged()) {
291                 importedNode.commit();
292             }
293         }
294     }
295
296     /**
297      * @javadoc !!!
298      */

299     private int doKeyMergeNode(MMObjectBuilder syncbul, MMObjectNode newNode, String JavaDoc exportsource, ApplicationResult result) {
300         MMObjectBuilder bul = newNode.getBuilder();
301         if (bul != null) {
302             Collection vec = bul.getFields();
303             Constraint constraint = null;
304             NodeSearchQuery query = null;
305             for (Iterator h = vec.iterator(); h.hasNext();) {
306                 CoreField def = (CoreField)h.next();
307                 // check for notnull fields with type NODE.
308
if (def.getType() == Field.TYPE_NODE
309                     && ! def.getName().equals("number")
310                     && ! def.getName().equals("otype")
311                     && def.isRequired()) {
312
313                     // Dangerous territory here.
314
// The node contains a reference to another node.
315
// The referenced node has to exist when this node is inserted.
316
// trying to update the node.
317
updateFieldWithTypeNode(syncbul, newNode, exportsource, def.getName());
318                     if (newNode.getIntValue(def.getName()) == -1) {
319                        // guess that failed
320
result.error("Insert of node " + newNode + " failed. Field '" + def.getName() + "' with type NODE is not allowed to have a null value. " +
321                                     "The referenced node is not found. Try to reorder the nodes so the referenced node is imported before this one.");
322                        return -1;
323                     }
324                 }
325
326                 // generation of key constraint to check if there is a node already present.
327
// if a node is present then we can't insert this one.
328
if (def.isUnique()) {
329                     int type = def.getType();
330                     String JavaDoc name = def.getName();
331                     if (type == Field.TYPE_STRING) {
332                         String JavaDoc value = newNode.getStringValue(name);
333                         if (query==null) {
334                             query = new NodeSearchQuery(bul);
335                         }
336                         StepField field = query.getField(def);
337                         Constraint newConstraint = new BasicFieldValueConstraint(field, value);
338                         if (constraint==null) {
339                             constraint= newConstraint;
340                         } else {
341                             BasicCompositeConstraint compConstraint = new BasicCompositeConstraint(CompositeConstraint.LOGICAL_AND);
342                             compConstraint.addChild(constraint);
343                             compConstraint.addChild(newConstraint);
344                             constraint = compConstraint;
345                         }
346                     }
347                 }
348             }
349             if (query != null && constraint != null) {
350                 query.setConstraint(constraint);
351                 try {
352                     List nodes = bul.getNodes(query);
353                     if (nodes.size()>0) {
354                         MMObjectNode oldNode = (MMObjectNode)nodes.get(0);
355                         return oldNode.getIntValue("number");
356                     }
357                 } catch (SearchQueryException sqe) {
358                     result.error("Application installer can't search builder storage (" + sqe.getMessage()+")");
359                     return -1;
360                 }
361             }
362
363             int localnumber = newNode.insert("import");
364             if (localnumber == -1) {
365                 result.error("Insert of node " + newNode + " failed.");
366             }
367             return localnumber;
368
369         } else {
370             result.error("Application installer can't find builder for : " + newNode);
371             return -1;
372         }
373     }
374
375    /** update the field with the real node number of the referenced node
376     *
377     * @param syncbul syncnode builder
378     * @param importedNode Node to update
379     * @param exportsource export source of the node to update
380     * @param fieldname name of the field
381     */

382    private void updateFieldWithTypeNode(
383       MMObjectBuilder syncbul,
384       MMObjectNode importedNode,
385       String JavaDoc exportsource,
386       String JavaDoc fieldname) {
387
388       int exportnumber;
389       try {
390           exportnumber = Integer.parseInt((String JavaDoc) importedNode.getValues().get("__" + fieldname));
391       } catch (Exception JavaDoc e) {
392           exportnumber = -1;
393       }
394
395       // clean it up (don't know if this is necessary, but don't risk anything!)
396
importedNode.storeValue("__" + fieldname, null);
397
398       int localNumber = -1;
399
400       List syncnodes = null;
401       try {
402           syncnodes = getSyncnodes(syncbul, exportsource, exportnumber);
403       }
404       catch (SearchQueryException e) {
405           log.warn("Search for exportnumber " + exportnumber + " exportsource " + exportsource + "failed", e);
406       }
407       if (syncnodes != null && !syncnodes.isEmpty()) {
408           MMObjectNode n2 = (MMObjectNode) syncnodes.get(0);
409           localNumber = n2.getIntValue("localnumber");
410       }
411       if (localNumber != -1) { // leave it unset in that case, because foreign keys whine otherwise (so, if you have foreign keys (e.g. hsql), the field _must not_ be required).
412
importedNode.setValue(fieldname, localNumber);
413       }
414    }
415
416    /**
417      * @javadoc
418      */

419     boolean installRelationSources(Vector ds, String JavaDoc appname, ApplicationResult result) {
420         MMObjectBuilder syncbul = mmb.getMMObject("syncnodes");
421         InsRel insRel = mmb.getInsRel();
422         if (syncbul != null) {
423             List nodeFieldNodes = new ArrayList(); // a temporary list with all nodes that have NODE fields, which should be synced, later.
424
for (Enumeration h = ds.elements(); h.hasMoreElements();) {
425                 Hashtable bh = (Hashtable)h.nextElement();
426                 XMLRelationNodeReader nodereader = getRelationNodeReader(appname, bh);
427                 if (nodereader == null) {
428                     continue;
429                 }
430                 else {
431                     installRelationSource(syncbul, insRel, nodereader, nodeFieldNodes, result);
432                 }
433             }
434             treatNodeFields(nodeFieldNodes,syncbul);
435         } else {
436             result.error("Application installer : can't reach syncnodes builder");
437         }
438         return result.isSuccess();
439     }
440
441     private void installRelationSource(MMObjectBuilder syncbul, InsRel insRel, XMLRelationNodeReader nodereader, List nodeFieldNodes, ApplicationResult result) {
442         String JavaDoc exportsource = nodereader.getExportSource();
443         int timestamp = nodereader.getTimeStamp();
444
445         for (Enumeration n = (nodereader.getNodes(mmb)).elements(); n.hasMoreElements();) {
446             try {
447                 MMObjectNode newNode = (MMObjectNode)n.nextElement();
448                 int exportnumber = newNode.getIntValue("number");
449
450                 if (existsSyncnode(syncbul, exportsource, exportnumber)) {
451                     // XXX To do : we may want to load the relation node and check/change the fields
452
log.debug("node allready installed : " + exportnumber);
453                 } else {
454                     newNode.setValue("number", -1);
455                     // The following code determines the 'actual' (synced) numbers for the destination and source nodes
456
// This will normally work well, however:
457
// It is _theoretically_ possible that one or both nodes are _themselves_ relation nodes.
458
// (since relations are nodes).
459
// Due to the order in which syncing takles place, it is possible that such structures will fail
460
// to get imported.
461
// ye be warned.
462

463                     // find snumber
464
int snumber = newNode.getIntValue("snumber");
465                     List snumberNodes = getSyncnodes(syncbul, exportsource, snumber);
466                     if (!snumberNodes.isEmpty()) {
467                         MMObjectNode n2 = (MMObjectNode)snumberNodes.get(0);
468                         snumber = n2.getIntValue("localnumber");
469                     } else {
470                         snumber = -1;
471                     }
472                     newNode.setValue("snumber", snumber);
473
474                     // find dnumber
475
int dnumber = newNode.getIntValue("dnumber");
476                     List dnumberNodes = getSyncnodes(syncbul, exportsource, dnumber);
477                     if (!dnumberNodes.isEmpty()) {
478                         MMObjectNode n2 = (MMObjectNode)dnumberNodes.get(0);
479                         dnumber = n2.getIntValue("localnumber");
480                     } else {
481                         dnumber = -1;
482                     }
483                     newNode.setValue("dnumber", dnumber);
484
485                     int localnumber = -1;
486                     if (snumber != -1 && dnumber != -1) {
487                         // test whether a relation with the proposed snumber/dnumber/rnumber already exists
488
// if so, skip this relation when the same
489
if (relationAlreadyExists(insRel, newNode, snumber, dnumber)) {
490                             log.warn("Application tries to add relation which already exists. " +
491                                     "Skipping relation with exportnumber " + exportnumber);
492                         }
493                         else {
494                             localnumber = newNode.insert("import");
495                             if (localnumber != -1) {
496                                 createSyncnode(syncbul, exportsource, timestamp, exportnumber, localnumber);
497                                 if (localnumber == newNode.getNumber()) {
498                                     findFieldsOfTypeNode(nodeFieldNodes, exportsource, newNode);
499                                 }
500                             }
501                         }
502                     } else {
503                         result.error("Cannot sync relation (exportnumber==" + exportnumber
504                                 + ", snumber:" + snumber + ", dnumber:" + dnumber + ")");
505                     }
506                 }
507             }
508             catch (SearchQueryException sqe) {
509                 log.error(sqe);
510             }
511         }
512     }
513
514     private boolean existsSyncnode(MMObjectBuilder syncbul, String JavaDoc exportsource, int exportnumber) throws SearchQueryException {
515         List nodes = getSyncnodes(syncbul, exportsource, exportnumber);
516         return !nodes.isEmpty();
517     }
518
519     private List getSyncnodes(MMObjectBuilder syncbul, String JavaDoc exportsource, int exportnumber) throws SearchQueryException {
520         NodeSearchQuery existQuery = new NodeSearchQuery(syncbul);
521         BasicFieldValueConstraint constraint1 = new BasicFieldValueConstraint(existQuery.getField(syncbul.getField("exportnumber")), new Integer JavaDoc(exportnumber));
522         BasicFieldValueConstraint constraint2 = new BasicFieldValueConstraint(existQuery.getField(syncbul.getField("exportsource")), exportsource);
523         BasicCompositeConstraint constraint = new BasicCompositeConstraint(CompositeConstraint.LOGICAL_AND);
524         constraint.addChild(constraint1);
525         constraint.addChild(constraint2);
526         existQuery.setConstraint(constraint);
527         List nodes = syncbul.getNodes(existQuery);
528         if (nodes == null) {
529             // could this happen?
530
nodes = new ArrayList();
531         }
532         return nodes;
533     }
534
535     private void createSyncnode(MMObjectBuilder syncbul, String JavaDoc exportsource, int timestamp, int exportnumber, int localnumber) {
536         MMObjectNode syncnode = syncbul.getNewNode("import");
537         syncnode.setValue("exportsource", exportsource);
538         syncnode.setValue("exportnumber", exportnumber);
539         syncnode.setValue("timestamp", timestamp);
540         syncnode.setValue("localnumber", localnumber);
541         syncnode.insert("import");
542     }
543
544     /**
545      * This method uses the {@link ResourceLoader} to fetch an application by name. for this purpose
546      * it requests the resource by adding <code>applications/</code> to the start of the appName and appends <code>.xml</core> to the end
547      * @param appName the name of the application to be read.
548      * @return the ApplicationReader for the application, or null is the application wat not found or an exception occured. In the later a message is logged
549      */

550     private ApplicationReader getApplicationReader(String JavaDoc appName) {
551         String JavaDoc resourceName = appName + ".xml";
552         try {
553             ResourceLoader applicationLoader = ResourceLoader.getConfigurationRoot().getChildResourceLoader("applications");
554             InputSource JavaDoc is = applicationLoader.getInputSource(resourceName);
555             if (is == null) {
556                 return null;
557             }
558             return new ApplicationReader(is);
559         } catch (Exception JavaDoc e) {
560             log.error("error while reading application from resource " + resourceName + " : " + e.getMessage() , e);
561             return null;
562         }
563     }
564
565     private XMLNodeReader getNodeReader(Map bh, String JavaDoc appName) {
566         XMLNodeReader nodeReader = null;
567
568         String JavaDoc path = (String JavaDoc) bh.get("path");
569         ResourceLoader applicationLoader = ResourceLoader.getConfigurationRoot().getChildResourceLoader("applications");
570         InputSource JavaDoc is = null;
571         try {
572             is = applicationLoader.getInputSource(path);
573         } catch (Exception JavaDoc e) {
574             log.info("No datasource resource " + path);
575         }
576         if (is != null) {
577             nodeReader = new XMLNodeReader(is, applicationLoader.getChildResourceLoader(appName));
578         }
579         return nodeReader;
580     }
581
582     private XMLRelationNodeReader getRelationNodeReader(String JavaDoc appname, Hashtable bh) {
583         XMLRelationNodeReader nodereader = null;
584
585         String JavaDoc path = (String JavaDoc)bh.get("path");
586         ResourceLoader applicationLoader = ResourceLoader.getConfigurationRoot().getChildResourceLoader("applications");
587         InputSource JavaDoc is = null;
588         try {
589             is = applicationLoader.getInputSource(path);
590         } catch (Exception JavaDoc e) {
591             log.info("No relationsource resource " + path);
592         }
593         if (is != null) {
594             nodereader = new XMLRelationNodeReader(is, applicationLoader.getChildResourceLoader(appname));
595         }
596         return nodereader;
597     }
598
599     private boolean relationAlreadyExists(InsRel insRel, MMObjectNode newNode, int snumber, int dnumber) {
600         boolean relationAlreadyExists = false;
601         MMObjectNode testNode = insRel.getRelation(snumber, dnumber, newNode.getIntValue("rnumber"));
602         if (testNode != null) {
603             relationAlreadyExists = true;
604             Map values = newNode.getValues();
605             for (Iterator iter = values.entrySet().iterator(); iter.hasNext();) {
606                 Map.Entry entry = (Map.Entry) iter.next();
607                 String JavaDoc newFieldName = (String JavaDoc) entry.getKey();
608                 if (!insRel.hasField(newFieldName)) {
609                     Object JavaDoc newValue = entry.getValue();
610                     Object JavaDoc testValue = testNode.getValue(newFieldName);
611                     if (!newValue.equals(testValue)) {
612                         relationAlreadyExists = false;
613                     }
614                 }
615             }
616         }
617         return relationAlreadyExists;
618     }
619
620     /**
621      * Checks and if required installs needed relation definitions.
622      * Retrieves, for each reldef entry, the attributes, and passes these on to {@link #installRelDef}
623      * @param reldefs a list of hashtables. Each hashtable represents a reldef entry, and contains a list of name-value
624      * pairs (the reldef attributes).
625      * @return Always <code>true</code> (?)
626      */

627     private boolean installRelDefs(Vector reldefs, ApplicationResult result) {
628         for (Enumeration h = reldefs.elements(); h.hasMoreElements();) {
629             Hashtable bh = (Hashtable)h.nextElement();
630             String JavaDoc source = (String JavaDoc)bh.get("source");
631             String JavaDoc target = (String JavaDoc)bh.get("target");
632             String JavaDoc direction = (String JavaDoc)bh.get("direction");
633             String JavaDoc guisourcename = (String JavaDoc)bh.get("guisourcename");
634             String JavaDoc guitargetname = (String JavaDoc)bh.get("guitargetname");
635             // retrieve builder info
636
int builder = -1;
637             if (RelDef.usesbuilder) {
638                 String JavaDoc buildername = (String JavaDoc)bh.get("builder");
639                 // if no 'builder' attribute is present (old format), use source name as builder name
640
if (buildername == null) {
641                     buildername = (String JavaDoc)bh.get("source");
642                 }
643                 builder = mmb.getTypeDef().getIntValue(buildername);
644             }
645             // is not explicitly set to unidirectional, direction is assumed to be bidirectional
646
if ("unidirectional".equals(direction)) {
647                 if (!installRelDef(source, target, 1, guisourcename, guitargetname, builder, result))
648                     return false;
649             } else {
650                 if (!installRelDef(source, target, 2, guisourcename, guitargetname, builder, result))
651                     return false;
652             }
653         }
654         return true;
655     }
656
657     /**
658      * Checks and if required installs needed allowed type relations.
659      * Retrieves, for each allowed relation entry, the attributes, and passes these on to {@link #installTypeRel}
660      * @param relations a list of hashtables. Each hashtable represents a allowedrelation entry, and contains a list of name-value
661      * pairs (the allowed relation attributes).
662      * @return <code>true</code> if succesfull, <code>false</code> if an error occurred
663      */

664     private boolean installAllowedRelations(Vector relations, ApplicationResult result) {
665         for (Enumeration h = relations.elements(); h.hasMoreElements();) {
666             Hashtable bh = (Hashtable)h.nextElement();
667             String JavaDoc from = (String JavaDoc)bh.get("from");
668             String JavaDoc to = (String JavaDoc)bh.get("to");
669             String JavaDoc type = (String JavaDoc)bh.get("type");
670             if (!installTypeRel(from, to, type, -1, result)) {
671                 return false;
672             }
673         }
674         return true;
675     }
676
677     /**
678      * Lists the required builders for this application, and makes attempts to install any builders that are
679      * not present.
680      * If there is a failure, the function returns false.
681      * Failure messages are stored in the lastmsg member.
682      * @param neededbuilders a list with builder data that need be installed on teh system for this application to work
683      * each element in teh list is a Map containing builder properties (in particular, 'name').
684      * @param applicationRoot the rootpath where the application's configuration files are located
685      * @return true if the builders were succesfully installed, false if the installation failed
686      */

687     private boolean installBuilders(List neededbuilders, String JavaDoc applicationRoot, ApplicationResult result) {
688         for (Iterator i = neededbuilders.iterator(); i.hasNext();) {
689             Map builderdata = (Map)i.next();
690             String JavaDoc name = (String JavaDoc)builderdata.get("name");
691             MMObjectBuilder bul = mmb.getMMObject(name);
692             // if builder not loaded
693
if (bul == null) {
694                 // if 'inactive' in the config/builder path, fail
695
String JavaDoc path = mmb.getBuilderPath(name, "");
696                 if (path != null) {
697                     result.error("The builder '" + name + "' was already on our system, but inactive." +
698                                  "To install this application, make the builder '" + path + name + ".xml ' active");
699                     continue;
700                 }
701                 ResourceLoader appLoader = ResourceLoader.getConfigurationRoot().getChildResourceLoader(ResourceLoader.getDirectory(applicationRoot));
702                 ResourceLoader thisAppLoader = appLoader.getChildResourceLoader(ResourceLoader.getName(applicationRoot));
703                 ResourceLoader builderLoader = thisAppLoader.getChildResourceLoader("builders");
704
705                 // attempt to open the builder file.
706
org.w3c.dom.Document JavaDoc config;
707                 try {
708                     config = builderLoader.getDocument(name + ".xml");
709                 } catch (org.xml.sax.SAXException JavaDoc se) {
710                     String JavaDoc msg = "builder '" + name + "':\n" + se.toString();
711                     log.error(msg, se);
712                     result.error("A XML parsing error occurred (" + se.toString() + "). Check the log for details.");
713                     continue;
714                 } catch (java.io.IOException JavaDoc ioe) {
715                     String JavaDoc msg = "builder '" + name + "':\n" + ioe.toString();
716                     log.error(msg, ioe);
717                     result.error("A file I/O error occurred (" + ioe.toString() + "). Check the log for details.");
718                     continue;
719                 } catch (Throwable JavaDoc t) {
720                     String JavaDoc msg = "builder '" + name + "': " + t.getMessage();
721                     log.error(msg, t);
722                     result.error("An error occured " + t.getClass() + " " + msg);
723                     continue;
724                 }
725
726                 if (config == null) {
727                     result.error("Could not find the builderfile : '" + builderLoader.getResource(name + ".xml") + "' (builder '" + name + "')");
728                     continue;
729                 }
730
731
732                 // check the presence of typedef (if not present, fail)
733
MMObjectBuilder typeDef = mmb.getTypeDef();
734                 if (typeDef == null) {
735                     return result.error("Could not find the typedef builder.");
736                 }
737                 try {
738                     // try to add a node to typedef, same as adding a builder...
739
MMObjectNode typeNode = typeDef.getNewNode("system");
740                     // fill the name....
741
typeNode.setValue("name", name);
742                     typeNode.setValue("config", config);
743                     // insert into mmbase
744
typeNode.insert("system");
745                 } catch (Exception JavaDoc e) {
746                     result.error(e.getMessage());
747                     continue;
748                 }
749                 // we now made the builder active.. look for other builders...
750
}
751         }
752         return result.isSuccess();
753     }
754
755     /**
756      * Checks whether a given relation definition exists, and if not, creates that definition.
757      * @param sname source name of the relation definition
758      * @param dname destination name of the relation definition
759      * @param dir directionality (uni or bi)
760      * @param sguiname source GUI name of the relation definition
761      * @param dguiname destination GUI name of the relation definition
762      * @param builder references the builder to use (only in new format)
763      * @return <code>true</code> if succesfull, <code>false</code> if an error occurred
764      */

765     private boolean installRelDef(String JavaDoc sname, String JavaDoc dname, int dir, String JavaDoc sguiname,
766             String JavaDoc dguiname, int builder, ApplicationResult result) {
767
768         RelDef reldef = mmb.getRelDef();
769         if (reldef != null) {
770             if (reldef.getNumberByName(sname + "/" + dname) == -1) {
771                 MMObjectNode node = reldef.getNewNode("system");
772                 node.setValue("sname", sname);
773                 node.setValue("dname", dname);
774                 node.setValue("dir", dir);
775                 node.setValue("sguiname", sguiname);
776                 node.setValue("dguiname", dguiname);
777                 if (RelDef.usesbuilder) {
778                     // if builder is unknown (falsely specified), use the InsRel builder
779
if (builder <= 0) {
780                         builder = mmb.getInsRel().getNumber();
781                     }
782                     node.setValue("builder", builder);
783                 }
784                 int id = reldef.insert("system", node);
785                 if (id != -1) {
786                     log.debug("RefDef (" + sname + "," + dname + ") installed");
787                 } else {
788                     return result.error("RelDef (" + sname + "," + dname + ") could not be installed");
789                 }
790             }
791         } else {
792             return result.error("Can't get reldef builder");
793         }
794         return true;
795     }
796
797     /**
798      * Checks and if required installs an allowed type relation (typerel object).
799      * @param sname source type name of the type relation
800      * @param dname destination type name of the type relation
801      * @param rname role name of the type relation
802      * @param count cardinality of the type relation
803      * @return <code>true</code> if succesfull, <code>false</code> if an error occurred
804      */

805     private boolean installTypeRel(String JavaDoc sname, String JavaDoc dname, String JavaDoc rname, int count, ApplicationResult result) {
806         TypeRel typerel = mmb.getTypeRel();
807         if (typerel != null) {
808             TypeDef typedef = mmb.getTypeDef();
809             if (typedef == null) {
810                 return result.error("Can't get typedef builder");
811             }
812             RelDef reldef = mmb.getRelDef();
813             if (reldef == null) {
814                 return result.error("Can't get reldef builder");
815             }
816
817             // figure out rnumber
818
int rnumber = reldef.getNumberByName(rname);
819             if (rnumber == -1) {
820                 return result.error("No reldef with role '" + rname + "' defined");
821             }
822
823             // figure out snumber
824
int snumber = typedef.getIntValue(sname);
825             if (snumber == -1) {
826                 return result.error("No builder with name '" + sname + "' defined");
827             }
828
829             // figure out dnumber
830
int dnumber = typedef.getIntValue(dname);
831             if (dnumber == -1) {
832                 return result.error("No builder with name '" + dname + "' defined");
833             }
834
835             if (!typerel.contains(snumber, dnumber, rnumber, TypeRel.STRICT)) {
836                 MMObjectNode node = typerel.getNewNode("system");
837                 node.setValue("snumber", snumber);
838                 node.setValue("dnumber", dnumber);
839                 node.setValue("rnumber", rnumber);
840                 node.setValue("max", count);
841                 int id = typerel.insert("system", node);
842                 if (id != -1) {
843                     log.debug("TypeRel (" + sname + "," + dname + "," + rname + ") installed");
844                 } else {
845                     return result.error("TypeRel (" + sname + "," + dname + "," + rname + ") could not be installed");
846                 }
847             }
848             return true;
849         } else {
850             return result.error("Can't get typerel builder");
851         }
852     }
853
854 }
855
Popular Tags