KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > module > corebuilders > TypeDef


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.corebuilders;
11
12 import java.io.*;
13 import java.util.*;
14
15 import org.xml.sax.InputSource JavaDoc;
16
17 import org.mmbase.storage.search.implementation.*;
18 import org.mmbase.storage.search.*;
19 import org.mmbase.module.core.*;
20 import org.mmbase.util.*;
21 import org.mmbase.util.logging.*;
22 import org.mmbase.util.xml.BuilderReader;
23
24 /**
25  * TypeDef is used to define the* object types (builders).
26  * Nodes of this builder have a virtual 'config' field.
27  * This field contains the xml-Document of the builder represented by the node.
28  * The filename used to reference the xml document is derived by extending the field 'name'.
29  * Creating a new typedef node automatically creates a new xml file and loads a new builder.
30  * Removing a node drops and unloads a builder (including the xml).
31  * Changes to the config will also be active on commit of the node.
32  *
33  * @author Daniel Ockeloen
34  * @author Pierre van Rooden
35  * @version $Id: TypeDef.java,v 1.68.2.1 2006/12/05 20:59:30 michiel Exp $
36  */

37 public class TypeDef extends MMObjectBuilder {
38
39     /**
40      * The property in the builder file ('deploy-dir') that sets the directory
41      * where new builder configuration files are to be deployed.
42      */

43     public static final String JavaDoc PROPERTY_DEPLOY_DIR = "deploy-dir";
44
45     // Logger routine
46
private static final Logger log = Logging.getLoggerInstance(TypeDef.class);
47     // Directory where new builder configuration files are deployed by default
48
String JavaDoc defaultDeploy = null;
49
50     /**
51      * Number-to-name cache.
52      * @duplicate should be moved to org.mmbase.cache
53      */

54     private Map numberToNameCache = null; // object number -> typedef name
55

56     /**
57      * Name-to-number cache.
58      * @duplicate should be moved to org.mmbase.cache
59      */

60     private Map nameToNumberCache = null; // typedef name -> object number
61

62     /**
63      * List of known builders.
64      */

65     private Vector typedefsLoaded = new Vector(); // Contains the names of all active builders
66

67     /**
68      * Sets the default deploy directory for the builders.
69      * @return true if init was completed, false if uncompleted.
70      */

71     public boolean init() {
72         broadCastChanges = false;
73         boolean result = super.init();
74         if (defaultDeploy == null) {
75             // determine default deploy directory
76
String JavaDoc builderDeployDir = getInitParameter(PROPERTY_DEPLOY_DIR);
77             if (builderDeployDir == null) {
78                 builderDeployDir = "applications";
79             }
80             defaultDeploy = builderDeployDir;
81         if (!defaultDeploy.endsWith("/") && !defaultDeploy.endsWith("\\")) {
82         defaultDeploy+="/";
83         }
84             log.service("Using '" + defaultDeploy + "' as default deploy dir for our builders.");
85         }
86         return result;
87     }
88
89     protected Map getNumberToNameCache() {
90         if (numberToNameCache == null) readCache();
91         return numberToNameCache;
92     }
93
94     protected Map getNameToNumberCache() {
95         if (nameToNumberCache == null) readCache();
96         return nameToNumberCache;
97     }
98
99     /**
100      * Insert a new object (content provided) in the cloud, including an entry for the object alias (if provided).
101      * This method indirectly calls {@link #preCommit}.
102      * Asside from that, this method loads the builder this node represents, and initalizes it. If you do
103      * not wish to load the builder (i.e. because it is already loaded), use {@link #insert(String, MMObjectNode, boolean)}
104      * @param owner The administrator creating the node
105      * @param node The object to insert. The object need be of the same type as the current builder.
106      * @return An <code>int</code> value which is the new object's unique number, -1 if the insert failed.
107      */

108     public int insert(String JavaDoc owner, MMObjectNode node) {
109         return insert(owner, node, true);
110     }
111
112     /**
113      * Insert a new object (content provided) in the cloud, including an entry for the object alias (if provided).
114      * This method indirectly calls {@link #preCommit}.
115      * @param owner The administrator creating the node
116      * @param node The object to insert. The object need be of the same type as the current builder.
117      * @param loadBuilder if <code>true</code>, the builder should be loaded. This method is set to
118      * <code>false</code> when it is called from the init() method of MMObjectBuilder to prevent
119      * it from being loaded twice
120      * @return An <code>int</code> value which is the new object's unique number, -1 if the insert failed.
121      */

122     public int insert(String JavaDoc owner, MMObjectNode node, boolean loadBuilder) {
123         if (log.isDebugEnabled()) {
124             // would be logical to log this in SERVICE but the same occurance is logged on INFO already in MMObjectBuilder.init()
125
log.debug("Insert of builder-node with name '" + node.getStringValue("name") + "', loadBuilder = " + loadBuilder);
126         }
127         // look if we can store to file, if it aint there yet...
128
String JavaDoc path = getBuilderConfiguration(node);
129         java.net.URL JavaDoc url = mmb.getBuilderLoader().getResource(path);
130         try {
131             if (! url.openConnection().getDoInput()) {
132                 // first store our config....
133
storeBuilderConfiguration(node);
134             }
135         } catch (Exception JavaDoc e) {
136             throw new RuntimeException JavaDoc(e.getMessage(), e);
137         }
138         // try if the builder was already in TypeDef for some reason
139
// this can happen when another thread was here first
140
int result = getIntValue(node.getStringValue("name"));
141         if (result < 0) {
142             // otherwise save the node
143
result = super.insert(owner, node);
144         }
145         if (result != -1) {
146             // update the cache
147
Integer JavaDoc number = new Integer JavaDoc(result);
148             String JavaDoc name = node.getStringValue("name");
149             getNameToNumberCache().put(name, number);
150             getNumberToNameCache().put(number, name);
151             // Load the builder if needed
152
if (loadBuilder) {
153                 loadBuilder(node);
154             }
155         }
156         return result;
157     }
158
159
160     /**
161      * Commit changes to this node to the database. This method indirectly calls {@link #preCommit}.
162      * Use only to commit changes - for adding node, use {@link #insert}.
163      * @param node The node to be committed
164      * @return true if commit successful
165      */

166
167     public boolean commit(MMObjectNode node) {
168         log.service("Commit of builder-node with name '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")");
169         try {
170             MMObjectBuilder builder = getBuilder(node);
171             BuilderReader originalBuilderXml = new BuilderReader(mmb.getBuilderLoader().getDocument(getBuilderConfiguration(node)), getMMBase());
172             String JavaDoc config = node.getStringValue("config");
173             StringReader stringReader;
174             if (config.indexOf("xmlns=\"http://www.mmbase.org/xmlns/builder\"") > 0) {
175                 stringReader = new StringReader("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + config);
176             } else {
177                 stringReader = new StringReader("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
178                                                 "<!DOCTYPE builder PUBLIC \"" + BuilderReader.PUBLIC_ID_BUILDER +
179                                                 "\" \":http://www.mmbase.org/dtd/" + BuilderReader.DTD_BUILDER + "\" >\n" +
180                                                 config);
181             }
182             BuilderReader newBuilderXml = new BuilderReader(new InputSource JavaDoc(stringReader), getMMBase());
183             if (!originalBuilderXml.equals(newBuilderXml)) {
184                 try {
185                     // unload the builder...
186
builder = unloadBuilder(node);
187                     // attempt to apply changes to the database
188
// by dropping the buildertable (ARGH!)
189
if (! originalBuilderXml.storageEquals(newBuilderXml)) {
190                         builder.delete();
191                     }
192                     // finally save our new config.
193
storeBuilderConfiguration(node);
194                 } finally {
195                     // clear config, so it will be refreshed later on
196
node.storeValue("config", null);
197                     // load the builder again.. (will possibly create a new table)
198
loadBuilder(node);
199                 }
200             }
201         } catch (Exception JavaDoc ioe) {
202             log.error(ioe.getMessage(), ioe);
203         }
204         return super.commit(node);
205     }
206
207
208     /**
209      * Remove a node from the cloud, when the represented builder was active
210      * it will also be unloaded
211      * @param node The node to remove.
212      * @throws RuntimeException When the operation could not be performed
213      */

214     public void removeNode(MMObjectNode node) {
215         log.info("Remove of builder-node with name '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")");
216         // only delete when builder is completely empty...
217
MMObjectBuilder builder = getBuilder(node);
218         testBuilderRemovable(builder, node);
219         builder = unloadBuilder(node);
220         // now that the builder cannot be started again (since config is now really missing)
221
if (builder != null) {
222             builder.delete();
223         }
224         // try to delete the configuration file first!.....
225
if (!deleteBuilderConfiguration(node)) {
226             // delete-ing failed, reload the builder again...
227
loadBuilder(node);
228             throw new RuntimeException JavaDoc("Could not delete builder config");
229         }
230         Integer JavaDoc number = node.getIntegerValue("number");
231         String JavaDoc name = node.getStringValue("name");
232         super.removeNode(node);
233         getNameToNumberCache().remove(name);
234         getNumberToNameCache().remove(number);
235     }
236
237     /**
238      * Fill the typedef caches with the initial values.
239      * Caches filled are a number-to-name and a name-to-number cache.
240      * @duplicate should be moved to org.mmbase.cache
241      * @return always true
242      */

243     private boolean readCache() {
244         // at least fill in typedef
245
log.service("Reading typedef caches");
246         numberToNameCache = Collections.synchronizedMap(new HashMap());
247         nameToNumberCache = Collections.synchronizedMap(new HashMap());
248         NodeSearchQuery query = new NodeSearchQuery(this);
249         try {
250             Iterator typedefs = getNodes(query).iterator();
251             while (typedefs.hasNext()) {
252                 MMObjectNode n = (MMObjectNode) typedefs.next();
253                 Integer JavaDoc number = n.getIntegerValue("number");
254                 String JavaDoc name = n.getStringValue("name");
255                 if (number != null && name != null) {
256                     nameToNumberCache.put(name,number);
257                     numberToNameCache.put(number,name);
258                 } else {
259                     log.error("Could not add typedef cache-entry number/name= " + number + "/" + name);
260                 }
261             }
262         } catch (SearchQueryException sqe) {
263             // should never happen.
264
log.error(sqe);
265         }
266         return true;
267     }
268
269     /**
270      * Obtain the type value of the requested builder
271      * @todo smarter cache update
272      * @param builderName name of the builder
273      * @return the object type as an int, -1 if not defined.
274      */

275     public int getIntValue(String JavaDoc builderName) {
276         Integer JavaDoc result = (Integer JavaDoc) getNameToNumberCache().get(builderName);
277         if (result != null) {
278             return result.intValue();
279         } else {
280             return -1;
281         }
282     }
283
284     /**
285      * Obtain the buildername of the requested type
286      * @param type the object type
287      * @return the name of the builder as a string, null if not found
288      */

289     public String JavaDoc getValue(int type) {
290         String JavaDoc result = (String JavaDoc) getNumberToNameCache().get(new Integer JavaDoc(type));
291         if (result == null) {
292             log.warn("Could not find builder name for typedef number " + type);
293         }
294         return result;
295     }
296
297     /**
298      * Obtain the buildername of the requested type
299      * @param type the object type
300      * @return the name of the builder as a string, "unknown" if not found
301      * @deprecated use getValue(int)
302      */

303     public String JavaDoc getValue(String JavaDoc type) {
304         try {
305             return (String JavaDoc) getNumberToNameCache().get(new Integer JavaDoc(Integer.parseInt(type)));
306         } catch(Exception JavaDoc e) {
307             return "unknown";
308         }
309     }
310
311     /**
312      * @javadoc
313      */

314     public String JavaDoc getSingularName(String JavaDoc builderName, String JavaDoc language) {
315         if (builderName == null) return "unknown";
316         MMObjectBuilder bul = mmb.getBuilder(builderName);
317         if (bul!=null) {
318             if (language == null) {
319                 return bul.getSingularName();
320             } else {
321                 return bul.getSingularName(language);
322             }
323         } else {
324             return "inactive ("+builderName+")";
325         }
326     }
327
328     /**
329      * @javadoc
330      */

331     public boolean isRelationTable(String JavaDoc name) {
332         return mmb.getRelDef().isRelationTable(name);
333     }
334
335     /**
336      * Provides additional functionality when obtaining field values.
337      * This method is called whenever a Node of the builder's type fails at evaluating a getValue() request
338      * (generally when a fieldname is supplied that doesn't exist).
339      * It allows the system to add 'functions' to be included with a field name, such as 'html(body)' or 'time(lastmodified)'.
340      * This method will parse the fieldname, determining functions and calling the {@link #executeFunction} method to handle it.
341      * Functions in fieldnames can be given in the format 'functionname(fieldname)'. An old format allows 'functionname_fieldname' instead,
342      * though this only applies to the text functions 'short', 'html', and 'wap'.
343      * Functions can be nested, i.e. 'html(shorted(body))'.
344      * Derived builders should override this method only if they want to provide virtual fieldnames. To provide addiitonal functions,
345      * override {@link #executeFunction} instead.
346      * @param node the node whos efields are queries
347      * @param field the fieldname that is requested
348      * @return the result of the 'function', or null if no valid functions could be determined.
349      */

350     public Object JavaDoc getValue(MMObjectNode node, String JavaDoc field) {
351         if (log.isDebugEnabled()) {
352             log.debug("node:" + node.getNumber() + " field: " + field);
353         }
354         // return the Document from the config file..
355
if (field.equals("config")) {
356             // first check if we already have a value in node fields...
357
Object JavaDoc o = super.getValue(node, field);
358             if (o != null) {
359                 return o;
360             }
361             // otherwise, open the file to return it...
362
if (log.isDebugEnabled()) {
363                log.debug("retrieving the document for node #" + node.getNumber());
364             }
365
366                 // method node.getStringValue("name") should work, since getStringValue("path") checked it already...
367
String JavaDoc path = getBuilderConfiguration(node);
368             org.w3c.dom.Document JavaDoc doc;
369             try {
370                 doc = mmb.getBuilderLoader().getDocument(path);
371             } catch (Exception JavaDoc e) {
372                 log.warn("Error reading builder with name: " + path + " " + e.getMessage());
373                 return null;
374             }
375             if (doc == null) {
376                 log.warn("Resource with name: " + path + " didnt exist, getValue will return null for builder config");
377                 return null;
378             }
379             node.setValue(field, doc);
380             return doc;
381         } else if (field.equals("state")) {
382             int val=node.getIntValue("state");
383             // is it set allready ? if not set it, this code should be
384
// removed ones the autoreloader/state code is done.
385
if (val==-1) {
386                 // state 1 is up and running
387
node.setValue("state",1);
388             }
389             return ""+val;
390         } else if (field.equals("dutchs(name)")) {
391             // replace this function with gui(name) ?
392
// but have to change admin pages first
393
return getGUIIndicator("name",node);
394         }
395         return super.getValue(node, field);
396     }
397
398     /**
399      * Sets a key/value pair in the main values of this node.
400      * Note that if this node is a node in cache, the changes are immediately visible to
401      * everyone, even if the changes are not committed.
402      * The fieldname is added to the (public) 'changed' vector to track changes.
403      * @param node
404      * @param fieldName the name of the field to change
405      * @param originalValue the value which was original in the field
406      * @return <code>true</code> When an update is required(when changed),
407      * <code>false</code> if original value was set back into the field.
408      */

409     public boolean setValue(MMObjectNode node, String JavaDoc fieldName, Object JavaDoc originalValue) {
410         Object JavaDoc newValue = node.retrieveValue(fieldName);
411         if (fieldName.equals("name")) {
412             // the field with the name 'name' may not be changed.....
413
if (originalValue != null && // perhaps legacy, name is null becaue name field was nullable?
414
! originalValue.equals("") && // name field is
415
!originalValue.equals(newValue)) {
416                 // restore the original value...
417
node.storeValue(fieldName, originalValue);
418                 throw new RuntimeException JavaDoc("Cannot change a builder's name from '" + originalValue + "' to '" + newValue + "' typedef node " + node.getNumber());
419 /* } else if (fieldName.equals("config")) {
420                 MMObjectBuilder builder = getBuilder(node);
421                 // TODO: active / not active code.. IT CAN MESS UP BUILDERS THAT ARE SET INACTIVE, AND STILL HAVE DATA IN DATABASE!
422                 if (builder == null) {
423                     log.warn("No builder found for typedef node " + node);
424                 } else if (builder.size() > 0) {
425                     throw new RuntimeException("Cannot change builder config it has nodes (otherwise information could get lost..)");
426                 } else {
427                     log.info("Changing config for typedef " + node + " associated with builder '" + builder.getTableName() + "'");
428                 }
429 */

430             }
431         }
432         return true;
433     }
434
435     /**
436      * @javadoc
437      */

438     public boolean fieldLocalChanged(String JavaDoc number, String JavaDoc builder, String JavaDoc field, String JavaDoc value) {
439         if (field.equals("state")) {
440             if (value.equals("4")) {
441                 // reload request
442
log.service("Reload wanted on : " + builder);
443                 // perform reload
444
MMObjectNode node = getNode(number);
445                 String JavaDoc objectname = node.getStringValue("name");
446                 reloadBuilder(objectname);
447                 if (node != null) {
448                     node.setValue("state", 1);
449                 }
450             }
451         }
452         return true;
453     }
454
455     /**
456      * Returns the path, where the builderfile can be found, for not exising builders, a path will be generated.
457      * @param node The node, from which we want to know it;s MMObjectBuilder
458      * @return The path where the builder should live or <code>null</code> in case of strange failures
459      * When the builder was not loaded.
460      * @since MMBase-1.8
461      */

462     protected String JavaDoc getBuilderConfiguration(MMObjectNode node) {
463         // call our code above, to get our path...
464
String JavaDoc path = getBuilderPath(node);
465         // do we have a path?
466
if (path == null) {
467             log.error("field 'path' was empty.");
468             return null;
469         }
470         return path + node.getStringValue("name") + ".xml";
471     }
472
473
474     /**
475      * Returns the MMObjectBuilder which is represented by the node.
476      * @param node The node, from which we want to know its MMObjectBuilder
477      * @return The builder which is represented by the node, or <code>null</code>
478      * if the builder was not loaded.
479      */

480     public MMObjectBuilder getBuilder(MMObjectNode node) {
481         String JavaDoc builderName = node.getStringValue("name");
482         return mmb.getMMObject(builderName);
483     }
484
485     /**
486      * @javadoc
487      */

488     public boolean reloadBuilder(String JavaDoc objectname) {
489         log.service("Trying to reload builder : "+objectname);
490         // first get all the info we need from the builder allready running
491
MMObjectBuilder oldbul = mmb.getBuilder(objectname);
492         String JavaDoc classname = oldbul.getClass().getName();
493         String JavaDoc description = oldbul.getDescription();
494
495         try {
496             Class JavaDoc newclass = Class.forName("org.mmbase.module.builders." + classname);
497             log.debug("Loaded load class : "+newclass);
498
499             MMObjectBuilder bul = (MMObjectBuilder)newclass.newInstance();
500             log.debug("Started : "+newclass);
501
502             bul.setMMBase(mmb);
503             bul.setTableName(objectname);
504             bul.setDescription(description);
505             bul.init();
506             mmb.addBuilder(objectname, bul);
507         } catch (Exception JavaDoc e) {
508             log.error(Logging.stackTrace(e));
509             return false;
510         }
511         return true;
512     }
513
514     /**
515      * What should a GUI display for this node.
516      * This method returns the gui name (singular name) of the builder that goes with this node.
517      * @param node The node to display
518      * @return the display of the node as a <code>String</code>
519      */

520     public String JavaDoc getGUIIndicator(MMObjectNode node) {
521         return getSingularName(node.getStringValue("name"), null);
522     }
523
524
525     /**
526      * The GUIIndicator can depend on the locale. Override this function
527      * @since MMBase-1.6
528      */

529     protected String JavaDoc getLocaleGUIIndicator(Locale locale, String JavaDoc field, MMObjectNode node) {
530         if (field == null || "".equals(field)) {
531             return getLocaleGUIIndicator(locale, node);
532         } else if ("description".equals(field)) {
533             MMObjectBuilder bul = mmb.getBuilder(node.getStringValue("name"));
534             if (bul != null) {
535                 return bul.getDescription(locale.getLanguage());
536             }
537         }
538         return null;
539     }
540
541     protected String JavaDoc getLocaleGUIIndicator(Locale locale, MMObjectNode node) {
542         String JavaDoc rtn = getSingularName(node.getStringValue("name"), locale.getLanguage());
543         if (rtn == null) return node.getStringValue("name");
544         return rtn;
545     }
546
547     /**
548      * @javadoc
549      */

550     public void loadTypeDef(String JavaDoc name) {
551         if(!typedefsLoaded.contains(name)) {
552             typedefsLoaded.add(name);
553         } else {
554             if (log.isDebugEnabled()) log.debug("Builder "+name+" is already loaded!");
555         }
556     }
557
558     /**
559      * @javadoc
560      */

561     public void unloadTypeDef(String JavaDoc name) {
562         if(typedefsLoaded.contains(name)) {
563             typedefsLoaded.remove(name);
564         } else {
565             log.debug("Builder "+name+" is not loaded!");
566         }
567     }
568
569     /**
570      * @javadoc
571      */

572     public Vector getList(PageInfo sp,StringTagger tagger, StringTokenizer tok) {
573         if (tok.hasMoreTokens()) {
574             String JavaDoc cmd=tok.nextToken();
575             if (cmd.equals("builders")) {
576                 return typedefsLoaded;
577             }
578         }
579         return null;
580     }
581
582     protected Object JavaDoc executeFunction(MMObjectNode node, String JavaDoc function, List args) {
583         log.debug("executefunction of typedef");
584         if (function.equals("info")) {
585             List empty = new ArrayList();
586             java.util.Map JavaDoc info = (java.util.Map JavaDoc) super.executeFunction(node, function, empty);
587             info.put("gui", info.get("info") + " (localized)");
588             if (args == null || args.size() == 0) {
589                 return info;
590             } else {
591                 return info.get(args.get(0));
592             }
593         } else if (function.equals("gui")) {
594             log.debug("GUI of servlet builder with " + args);
595             if (args == null || args.size() ==0) {
596                 return getGUIIndicator(node);
597             } else {
598                 String JavaDoc rtn;
599                 if (args.size() <= 1) {
600                     rtn = getGUIIndicator((String JavaDoc) args.get(0), node);
601                 } else {
602                     String JavaDoc language = (String JavaDoc) args.get(1);
603                     if (language == null) language = mmb.getLanguage();
604                     Locale locale = new Locale(language, "");
605                     rtn = getLocaleGUIIndicator(locale, (String JavaDoc) args.get(0), node);
606                 }
607                 if (rtn == null) return super.executeFunction(node, function, args);
608                 return rtn;
609             }
610         } else if (function.equals("defaultsearchage")) {
611             return new Integer JavaDoc(getBuilder(node).getSearchAge());
612         } else {
613             return super.executeFunction(node, function, args);
614         }
615     }
616
617     private void testBuilderRemovable(MMObjectBuilder builder, MMObjectNode typeDefNode) {
618         if (builder != null && builder.size() > 0) {
619             throw new RuntimeException JavaDoc("Cannot delete this builder, it still contains nodes");
620         } else if (builder == null) {
621             // inactive builder, does it have nodes?
622
MMObjectBuilder rootBuilder = mmb.getRootBuilder();
623             NodeSearchQuery q = new NodeSearchQuery(rootBuilder);
624             Integer JavaDoc value = new Integer JavaDoc(typeDefNode.getNumber());
625             Constraint constraint = new BasicFieldValueConstraint(q.getField(rootBuilder.getField("otype")), value);
626             q.setConstraint(constraint);
627             try {
628                 if (rootBuilder.count(q) > 0) {
629                     throw new RuntimeException JavaDoc("Cannot delete this (inactive) builder, it still contains nodes");
630                 }
631             } catch (SearchQueryException sqe) {
632                 // should never happen
633
log.error(sqe);
634             }
635         }
636
637         // check if there are relations which use this builder
638
{
639             if (builder instanceof InsRel) {
640                 MMObjectNode reldef = mmb.getRelDef().getDefaultForBuilder((InsRel)builder);
641                 if (reldef != null) {
642                     throw new RuntimeException JavaDoc("Cannot delete this builder, it is referenced in reldef #" + reldef.getNumber());
643                 }
644             }
645             try {
646                 MMObjectBuilder typeRel = mmb.getTypeRel();
647                 NodeSearchQuery q = new NodeSearchQuery(typeRel);
648                 Integer JavaDoc value = new Integer JavaDoc(typeDefNode.getNumber());
649                 BasicCompositeConstraint constraint = new BasicCompositeConstraint(CompositeConstraint.LOGICAL_OR);
650                 Constraint constraint1 = new BasicFieldValueConstraint(q.getField(typeRel.getField("snumber")), value);
651                 Constraint constraint2 = new BasicFieldValueConstraint(q.getField(typeRel.getField("dnumber")), value);
652                 constraint.addChild(constraint1);
653                 constraint.addChild(constraint2);
654                 q.setConstraint(constraint);
655                 List typerels = typeRel.getNodes(q);
656                 if (typerels.size() > 0) {
657                     throw new RuntimeException JavaDoc("Cannot delete this builder, it is referenced by typerels: " + typerels);
658                 }
659             } catch (SearchQueryException sqe) {
660                 // should never happen
661
log.error(sqe);
662             }
663         }
664     }
665
666     /**
667      * Returns the path, where the builder configuration file can be found, for not exising builders, a path will be generated.
668      * @param node The node, from which we want to know it;s MMObjectBuilder
669      * @return The path where the builder should live or <code>null</code> in case of strange failures
670      * When the builder was not loaded.
671      */

672     protected String JavaDoc getBuilderPath(MMObjectNode node) {
673         if (log.isDebugEnabled()) {
674             log.debug("retrieving the path for node #" + node.getNumber());
675         }
676         // some basic checking
677
if (node == null) {
678             log.error("node was null");
679             return null;
680         }
681         if (node.getStringValue("name") == null) {
682             log.error("field 'name' was null");
683             return null;
684         }
685         if (node.getStringValue("name").trim().length() == 0) {
686             log.error("field 'name' was empty.");
687             return null;
688         }
689
690         String JavaDoc pathInBuilderDir = mmb.getBuilderPath(node.getStringValue("name"), "");
691         if (pathInBuilderDir != null) {
692             // return the file path,..
693
String JavaDoc file = pathInBuilderDir;
694             if (log.isDebugEnabled()) {
695                 log.debug("builder file:" + file);
696             }
697             return file;
698         }
699         // still null, make up a nice url for our builder!
700
if (defaultDeploy != null) {
701             String JavaDoc file = defaultDeploy;
702             if (log.isDebugEnabled()) {
703                 log.debug("builder file:" + file);
704             }
705             return file;
706         }
707         return null;
708     }
709
710     /**
711      */

712     protected MMObjectBuilder loadBuilder(MMObjectNode node) {
713         if (log.isDebugEnabled()) {
714             log.debug("Load builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")");
715         }
716         String JavaDoc path = getBuilderPath(node);
717         log.info("Loading builder from " + path);
718         MMObjectBuilder builder = mmb.loadBuilderFromXML(node.getStringValue("name"), path);
719         if (builder == null) {
720             // inactive builder?
721
log.info("could not load builder from xml, is in inactive?(name: '" + node.getStringValue("name") + "' path: '" + path + "')");
722             return null;
723         }
724         mmb.initBuilder(builder);
725         return builder;
726     }
727
728     /**
729      */

730     protected void storeBuilderConfiguration(MMObjectNode node) throws java.io.IOException JavaDoc {
731         if (log.isDebugEnabled()) {
732             log.debug("Store builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")");
733         }
734
735         org.w3c.dom.Document JavaDoc doc = node.getXMLValue("config");
736         if (doc == null) {
737             log.error("Field config was null! Could not save the file for " + node.getStringValue("name") + Logging.stackTrace(new Throwable JavaDoc()));
738             return;
739         }
740         String JavaDoc path = getBuilderConfiguration(node);
741         log.info("Store builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ") to " + path);
742         mmb.getBuilderLoader().storeDocument(path, doc);
743
744     }
745
746     /**
747      */

748     protected MMObjectBuilder unloadBuilder(MMObjectNode node) {
749         if (log.isDebugEnabled()) {
750             log.debug("Unload builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")");
751         }
752         // unload the builder,...
753
MMObjectBuilder builder = getBuilder(node);
754         if (builder != null) {
755             mmb.unloadBuilder(builder);
756         }
757         return builder;
758     }
759
760     /**
761      */

762     protected boolean deleteBuilderConfiguration(MMObjectNode node) {
763         if (log.isDebugEnabled()) {
764             log.debug("Delete file of builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")");
765         }
766         File file = new File(getBuilderConfiguration(node));
767         if (file.exists()) {
768             if (!file.canWrite()) {
769                 log.error("file: " + file + " had no write rights for me.");
770                 return false;
771             }
772             // remove the file from the file system..
773
file.delete();
774             if (log.isDebugEnabled()) {
775                 log.debug("file: " + file + " has been deleted");
776             }
777         }
778         return true;
779     }
780 }
781
Popular Tags