Source Code Cross Referenced for BuilderReader.java in  » Database-ORM » MMBase » org » mmbase » util » xml » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » MMBase » org.mmbase.util.xml 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:        This software is OSI Certified Open Source Software.
0004:        OSI Certified is a certification mark of the Open Source Initiative.
0005:
0006:        The license (Mozilla version 1.0) can be read at the MMBase site.
0007:        See http://www.MMBase.org/license
0008:
0009:         */
0010:        package org.mmbase.util.xml;
0011:
0012:        import java.util.*;
0013:
0014:        import org.w3c.dom.*;
0015:        import org.xml.sax.InputSource;
0016:        import org.mmbase.bridge.Field;
0017:        import org.mmbase.bridge.NodeManager;
0018:        import org.mmbase.core.CoreField;
0019:        import org.mmbase.core.util.Fields;
0020:        import org.mmbase.datatypes.*;
0021:        import org.mmbase.datatypes.util.xml.DataTypeReader;
0022:        import org.mmbase.datatypes.util.xml.DependencyException;
0023:        import org.mmbase.module.core.MMBase;
0024:        import org.mmbase.module.core.MMObjectBuilder;
0025:        import org.mmbase.storage.util.Index;
0026:
0027:        import org.mmbase.util.LocalizedString;
0028:        import org.mmbase.util.XMLEntityResolver;
0029:        import org.mmbase.util.functions.*;
0030:        import org.mmbase.util.logging.*;
0031:
0032:        /**
0033:         * Used to parse and retrieve data from a builder configuration file.
0034:         * The parser support builders for builder dtd 1.1.
0035:         *
0036:         * @since MMBase 1.7
0037:         * @author Case Roole
0038:         * @author Rico Jansen
0039:         * @author Pierre van Rooden
0040:         * @author Michiel Meeuwissen
0041:         * @version $Id: BuilderReader.java,v 1.97 2008/03/12 15:21:43 michiel Exp $
0042:         */
0043:        public class BuilderReader extends DocumentReader {
0044:
0045:            /** Public ID of the Builder DTD version 1.0 */
0046:            public static final String PUBLIC_ID_BUILDER_1_0 = "-//MMBase//DTD builder config 1.0//EN";
0047:            /** Public ID of the Builder DTD version 1.1 */
0048:            public static final String PUBLIC_ID_BUILDER_1_1 = "-//MMBase//DTD builder config 1.1//EN";
0049:
0050:            // deprecated builder dtds
0051:            private static final String PUBLIC_ID_BUILDER_1_0_FAULT = "-//MMBase/DTD builder config 1.0//EN";
0052:            private static final String PUBLIC_ID_BUILDER_OLD = "/MMBase - builder//";
0053:            private static final String PUBLIC_ID_BUILDER_1_1_FAULT = "-//MMBase/DTD builder config 1.1//EN";
0054:
0055:            /** DTD resource filename of the Builder DTD version 1.0 */
0056:            public static final String DTD_BUILDER_1_0 = "builder_1_0.dtd";
0057:            /** DTD resource filename of the Builder DTD version 1.1 */
0058:            public static final String DTD_BUILDER_1_1 = "builder_1_1.dtd";
0059:
0060:            /** Public ID of the most recent Builder DTD */
0061:            public static final String PUBLIC_ID_BUILDER = PUBLIC_ID_BUILDER_1_1;
0062:            /** DTD respource filename of the most recent Builder DTD */
0063:            public static final String DTD_BUILDER = DTD_BUILDER_1_1;
0064:
0065:            public static final String XSD_BUILDER_2_0 = "builder.xsd";
0066:            public static final String NAMESPACE_BUILDER_2_0 = "http://www.mmbase.org/xmlns/builder";
0067:            public static final String NAMESPACE_BUILDER = NAMESPACE_BUILDER_2_0;
0068:
0069:            private static final Logger log = Logging
0070:                    .getLoggerInstance(BuilderReader.class);
0071:
0072:            /**
0073:             * Register the namespace and XSD used by DataTypeConfigurer
0074:             * This method is called by XMLEntityResolver.
0075:             */
0076:            public static void registerSystemIDs() {
0077:                XMLEntityResolver.registerSystemID(NAMESPACE_BUILDER_2_0
0078:                        + ".xsd", XSD_BUILDER_2_0, BuilderReader.class);
0079:            }
0080:
0081:            /**
0082:             * Register the Public Ids for DTDs used by BuilderReader
0083:             * This method is called by XMLEntityResolver.
0084:             */
0085:            public static void registerPublicIDs() {
0086:                // various builder dtd versions
0087:                XMLEntityResolver.registerPublicID(PUBLIC_ID_BUILDER_1_0,
0088:                        DTD_BUILDER_1_0, BuilderReader.class);
0089:                XMLEntityResolver.registerPublicID(PUBLIC_ID_BUILDER_1_1,
0090:                        DTD_BUILDER_1_1, BuilderReader.class);
0091:                //XMLEntityResolver.registerPublicID("-//MMBase//DTD builder config 2.0//EN", "builder_2_0.dtd", BuilderReader.class);
0092:
0093:                // legacy public IDs (wrong, don't use these)
0094:                XMLEntityResolver.registerPublicID(PUBLIC_ID_BUILDER_1_0_FAULT,
0095:                        DTD_BUILDER_1_0, BuilderReader.class);
0096:                XMLEntityResolver.registerPublicID(PUBLIC_ID_BUILDER_OLD,
0097:                        DTD_BUILDER_1_0, BuilderReader.class);
0098:                XMLEntityResolver.registerPublicID(PUBLIC_ID_BUILDER_1_1_FAULT,
0099:                        DTD_BUILDER_1_1, BuilderReader.class);
0100:            }
0101:
0102:            /**
0103:             * MMBase instance, used to load parent (extending) builders
0104:             */
0105:            private MMBase mmbase;
0106:
0107:            /**
0108:             * Parent builder.
0109:             * If assigned, the properties of this builder are used as 'defaults'
0110:             * and the fields of the builder are inherited.
0111:             * @since MMbase-1.6
0112:             */
0113:            private MMObjectBuilder parentBuilder;
0114:
0115:            /**
0116:             * If false, the parent builder could not be resolved.
0117:             * A builder with an unresolved parent is set to 'inactive', regardless of actual status
0118:             * The default value is false, as resolving Inheritance is mandatory when loading builders.
0119:             * @since MMbase-1.6
0120:             */
0121:            private boolean inheritanceResolved = false;
0122:
0123:            /**
0124:             * searchPositions and inputPositions are used to adminstrate 'occupied' positions (from
0125:             * editor/positions), which is used to find defaults if not specified.
0126:             * @since MMBase-1.7
0127:             */
0128:            private SortedSet<Integer> searchPositions = new TreeSet<Integer>();
0129:            private SortedSet<Integer> inputPositions = new TreeSet<Integer>();
0130:
0131:            /**
0132:             * @since MMBase-1.7
0133:             */
0134:            public BuilderReader(InputSource source, MMBase mmb) {
0135:                super (source, BuilderReader.class);
0136:                mmbase = mmb;
0137:                if (getRootElement().getTagName().equals("builder")) {
0138:                    resolveInheritance();
0139:                }
0140:            }
0141:
0142:            /**
0143:             * @since MMBase-1.8
0144:             */
0145:            public BuilderReader(Document doc, MMBase mmb) {
0146:                super (doc);
0147:                mmbase = mmb;
0148:                if (getRootElement().getTagName().equals("builder")) {
0149:                    resolveInheritance();
0150:                }
0151:            }
0152:
0153:            /**
0154:             * Resolves inheritance.
0155:             * If a builder 'extends' another builder, the parser attempts to
0156:             * retrieve a reference to this builder (using getParentBuilder).
0157:             * Note that if inheritance cannot be resolved, the builder cannot be activated.
0158:             * This method returns false if the builder to extend from is inactive.
0159:             * It throws a RuntimeException is the builder to extend from is not allowed as
0160:             * an parent builder.
0161:             *
0162:             * @since MMBase-1.6
0163:             * @return true if inheritance could be resolved, false if the .
0164:             * @see #isInheritanceResolved()
0165:             * @throws RuntimeException when the builder to extend from is not allowed as parent
0166:             */
0167:            protected boolean resolveInheritance() {
0168:                String buildername = getExtends();
0169:                if (buildername.equals("")) {
0170:                    parentBuilder = null;
0171:                    inheritanceResolved = true;
0172:                } else {
0173:                    inheritanceResolved = false;
0174:                    if (mmbase != null) {
0175:                        parentBuilder = mmbase.getBuilder(buildername);
0176:                        inheritanceResolved = (parentBuilder != null);
0177:                        if (inheritanceResolved) { // fill inputPositions, searchPositions
0178:                            Iterator<CoreField> fields = parentBuilder
0179:                                    .getFields(NodeManager.ORDER_EDIT)
0180:                                    .iterator();
0181:                            while (fields.hasNext()) {
0182:                                CoreField def = fields.next();
0183:                                inputPositions.add(def.getEditPosition());
0184:                            }
0185:                            fields = parentBuilder.getFields(
0186:                                    NodeManager.ORDER_SEARCH).iterator();
0187:                            while (fields.hasNext()) {
0188:                                CoreField def = fields.next();
0189:                                searchPositions.add(def.getSearchPosition());
0190:                            }
0191:                        }
0192:                    }
0193:                }
0194:                return inheritanceResolved;
0195:            }
0196:
0197:            /**
0198:             * Detremines if inheritance is resolved.
0199:             * This method returns true if a call to resolveInheritance succeeded.
0200:             * it returns false if resolveInheritance failed (returned false or threw an exception)
0201:             *
0202:             * @since MMBase-1.6
0203:             * @return true if inheritance could be resolved
0204:             * @see #resolveInheritance()
0205:             */
0206:            public boolean isInheritanceResolved() {
0207:                return inheritanceResolved;
0208:            }
0209:
0210:            /**
0211:             * Get the status of this builder.
0212:             * Note that if inheritance cannot be resolved, this method always returns "inactive".
0213:             * @return a String decribing the status ("active" or "inactive")
0214:             */
0215:            public String getStatus() {
0216:                if (!inheritanceResolved) {
0217:                    return "inactive"; // extends an inactive or non-existing builder
0218:                } else {
0219:                    String val = getElementValue("builder.status")
0220:                            .toLowerCase();
0221:                    if (!val.equals("inactive")) {
0222:                        val = "active"; // fix invalid values, including empty value, in which case
0223:                        // assume it extends an active builder (i.e. object)
0224:                    }
0225:                    return val;
0226:                }
0227:            }
0228:
0229:            /**
0230:             * Retrieves the Search Age.
0231:             * The search age may be used by editors or search forms to determine
0232:             * the maximum age in days of an object to be searched (limiting the resultset
0233:             * of a search)
0234:             * @return the search age in days
0235:             */
0236:            public int getSearchAge() {
0237:                int val = 30;
0238:                String sval = getElementValue("builder.searchage");
0239:                if (sval.equals("") && (parentBuilder != null)) {
0240:                    sval = parentBuilder.getSearchAge();
0241:                }
0242:                try {
0243:                    val = Integer.parseInt(sval);
0244:                } catch (Exception f) {
0245:                }
0246:                return val;
0247:            }
0248:
0249:            /**
0250:             * Get the class name to use for instantiating this builder.
0251:             * Note that it is possible to specify a short-hand format in
0252:             * the builder configuration file.
0253:             * If only the classname (withoput package name) is given, the classname
0254:             * is expanded to fall into the <code>org.mmbase.module.builders</code> package.
0255:             * @return the classname to use.
0256:             */
0257:            public String getClassName() {
0258:                String val = getElementValue("builder.class");
0259:                if (val.equals("")) {
0260:                    val = getElementValue("builder.classfile");// deprecated!! (makes no sense, it is no file)
0261:                }
0262:
0263:                if (val.equals("")) {
0264:                    if (parentBuilder != null) {
0265:                        return parentBuilder.getClass().getName();
0266:                    } else {
0267:                        return "";
0268:                    }
0269:                }
0270:                // is it a full name or inside the org.mmbase.module.builders.* path
0271:                int pos = val.indexOf('.');
0272:                if (pos == -1) {
0273:                    val = "org.mmbase.module.builders." + val;
0274:                }
0275:                if ("org.mmbase.module.corebuilders.ObjectTypes".equals(val)) {
0276:                    log
0277:                            .warn("Specified the removed builder 'ObjectTypes', fall back to TypeDef. You can remove all core-builders from your configuration directory (the ones present in mmbase.jar are ok)");
0278:                    val = "org.mmbase.module.corebuilders.TypeDef";
0279:                }
0280:                return val;
0281:            }
0282:
0283:            /**
0284:             * Get the datatypes defined for this builder.
0285:             * @param collector A DataTypeCollector to which the newly found DataTypes will be added.
0286:             * @return Returns the data-types of the given collector after adding the ones which are configured
0287:             * @since MMBase-1.8
0288:             */
0289:            public Map<String, BasicDataType<?>> getDataTypes(
0290:                    DataTypeCollector collector) {
0291:                Element element = getElementByPath("builder.datatypes");
0292:                if (element != null) {
0293:                    DataTypeReader.readDataTypes(element, collector);
0294:                }
0295:                return collector.getDataTypes();
0296:            }
0297:
0298:            /**
0299:             * Get the field definitions of this builder.
0300:             * If applicable, this includes the fields inherited from a parent builder.
0301:             *
0302:             * @return a List of all Fields as CoreField
0303:             * @since MMBase-1.8
0304:             */
0305:            public List<CoreField> getFields() {
0306:                return getFields(null, DataTypes.getSystemCollector());
0307:            }
0308:
0309:            /**
0310:             * Get the field definitions of this builder.
0311:             * If applicable, this includes the fields inherited from a parent builder.
0312:             *
0313:             * @param builder the MMObjectBuilder to which the fields will be added
0314:             * @param collector the datatype collector used to access the datatypes available for the fields to read.
0315:             * @return a List of all Fields as CoreField
0316:             * @since MMBase-1.8
0317:             */
0318:            public List<CoreField> getFields(MMObjectBuilder builder,
0319:                    DataTypeCollector collector) {
0320:                List<CoreField> results = new ArrayList<CoreField>();
0321:                Map<String, CoreField> oldset = new HashMap<String, CoreField>();
0322:                int pos = 1;
0323:                if (parentBuilder != null) {
0324:                    List<CoreField> parentfields = parentBuilder
0325:                            .getFields(NodeManager.ORDER_CREATE);
0326:                    if (parentfields != null) {
0327:                        // have to clone the parent fields
0328:                        // need clone()!
0329:                        for (CoreField f : parentfields) {
0330:                            CoreField newField = (CoreField) f.clone(f
0331:                                    .getName());
0332:                            newField.setParent(builder);
0333:                            while (newField.getStoragePosition() >= pos)
0334:                                pos++;
0335:                            newField.finish();
0336:                            results.add(newField);
0337:                            oldset.put(newField.getName(), newField);
0338:                        }
0339:                    }
0340:                }
0341:
0342:                for (Element fieldList : getChildElements("builder",
0343:                        "fieldlist")) {
0344:                    for (Element field : getChildElements(fieldList, "field")) {
0345:                        String fieldName = getElementAttributeValue(field,
0346:                                "name");
0347:                        if ("".equals(fieldName)) {
0348:                            fieldName = getElementValue(getElementByPath(field,
0349:                                    "field.db.name"));
0350:                        }
0351:                        CoreField def = oldset.get(fieldName);
0352:                        try {
0353:                            if (def != null) {
0354:                                def.rewrite();
0355:                                DataType dataType = decodeDataType(builder,
0356:                                        collector, def.getName(), field, def
0357:                                                .getType(), def
0358:                                                .getListItemType(), false);
0359:                                if (dataType != null) {
0360:                                    def.setDataType(dataType); // replace datatype
0361:                                }
0362:                                decodeFieldDef(field, def, collector);
0363:                                decodeFieldAttributes(field, def);
0364:                                def.finish();
0365:                            } else {
0366:                                def = decodeFieldDef(builder, collector, field);
0367:                                def.setStoragePosition(pos++);
0368:                                def.finish();
0369:                                results.add(def);
0370:                            }
0371:                        } catch (Exception e) {
0372:                            log.error("During parsing of "
0373:                                    + XMLWriter.write(field, true, true) + " "
0374:                                    + e.getMessage(), e);
0375:                        }
0376:                    }
0377:                }
0378:                return results;
0379:            }
0380:
0381:            /**
0382:             * Get the named indices of this builder.
0383:             * Note that the 'default' index (set with the 'key' attribute) is also included
0384:             * in this list (with the name {@link Index#MAIN}).
0385:             *
0386:             * @param builder the MMObjectBuilder to which the fields will be added
0387:             * @return a List of all Indices
0388:             */
0389:            public List<Index> getIndices(MMObjectBuilder builder) {
0390:                List<Index> results = new ArrayList<Index>();
0391:                Index mainIndex = null;
0392:                if (parentBuilder != null) {
0393:                    // create the
0394:                    Index parentIndex = parentBuilder.getStorageConnector()
0395:                            .getIndex(Index.MAIN);
0396:                    if (parentIndex != null) {
0397:                        mainIndex = new Index(builder, Index.MAIN);
0398:                        mainIndex.setUnique(true);
0399:                        for (Field field : parentIndex) {
0400:                            mainIndex.add(builder.getField(field.getName()));
0401:                        }
0402:                    }
0403:                }
0404:
0405:                for (Element field : getChildElements("builder.fieldlist",
0406:                        "field")) {
0407:                    Element dbtype = getElementByPath(field, "field.db.type");
0408:                    if (dbtype != null) {
0409:                        String key = getElementAttributeValue(dbtype, "key");
0410:                        if (key != null && key.equalsIgnoreCase("true")) {
0411:                            String fieldName = getElementAttributeValue(field,
0412:                                    "name");
0413:                            if ("".equals(fieldName)) {
0414:                                fieldName = getElementValue(getElementByPath(
0415:                                        field, "field.db.name"));
0416:                            }
0417:                            if (mainIndex == null)
0418:                                mainIndex = new Index(builder, Index.MAIN);
0419:                            mainIndex.add(builder.getField(fieldName));
0420:                        }
0421:                    }
0422:                }
0423:                if (mainIndex != null) {
0424:                    results.add(mainIndex);
0425:                }
0426:
0427:                if (parentBuilder != null) {
0428:                    Collection<Index> parentIndices = parentBuilder
0429:                            .getStorageConnector().getIndices().values();
0430:                    if (parentIndices != null) {
0431:                        for (Index parentIndex : parentIndices) {
0432:                            Index newIndex = new Index(builder, parentIndex
0433:                                    .getName());
0434:                            ;
0435:                            newIndex.setUnique(parentIndex.isUnique());
0436:                            for (Field field : parentIndex) {
0437:                                newIndex.add(builder.getField(field.getName()));
0438:                            }
0439:                            results.add(newIndex);
0440:                        }
0441:                    }
0442:                }
0443:
0444:                for (Element indexList : getChildElements("builder",
0445:                        "indexlist")) {
0446:                    for (Element indexElement : getChildElements(indexList,
0447:                            "index")) {
0448:                        String indexName = indexElement.getAttribute("name");
0449:                        if (indexName != null && !indexName.equals("")) {
0450:                            String unique = indexElement.getAttribute("unique");
0451:                            Index index = new Index(builder, indexName);
0452:                            index.setUnique(unique != null
0453:                                    && unique.equals("true"));
0454:                            for (Element fieldElement : getChildElements(
0455:                                    indexElement, "indexfield")) {
0456:                                String fieldName = fieldElement
0457:                                        .getAttribute("name");
0458:                                Field field = builder.getField(fieldName);
0459:                                if (field == null) {
0460:                                    log.error("field '" + fieldName
0461:                                            + "' in index '" + indexName
0462:                                            + "' in builder "
0463:                                            + builder.getTableName()
0464:                                            + " does not exist");
0465:                                } else {
0466:                                    index.add(field);
0467:                                }
0468:                            }
0469:                            results.add(index);
0470:                        } else {
0471:                            log.error("index in builder "
0472:                                    + builder.getTableName() + " has no name");
0473:                        }
0474:                    }
0475:                }
0476:                return results;
0477:            }
0478:
0479:            /**
0480:             * @since MMBase-1.8
0481:             */
0482:            public Set<Function> getFunctions(final MMObjectBuilder builder) {
0483:                Map<String, Function> results = new HashMap<String, Function>();
0484:                for (Element functionList : getChildElements("builder",
0485:                        "functionlist")) {
0486:                    for (Element functionElement : getChildElements(
0487:                            functionList, "function")) {
0488:                        try {
0489:                            final String functionName = functionElement
0490:                                    .getAttribute("name");
0491:                            String providerKey = functionElement
0492:                                    .getAttribute("key");
0493:                            String functionClass = getNodeTextValue(getElementByPath(
0494:                                    functionElement, "function.class"));
0495:
0496:                            Function function;
0497:                            log.debug("Using function class '" + functionClass
0498:                                    + "'");
0499:                            final Class claz = Class.forName(functionClass);
0500:                            if (Function.class.isAssignableFrom(claz)) {
0501:                                if (!providerKey.equals("")) {
0502:                                    log
0503:                                            .warn("Specified a key attribute for a Function "
0504:                                                    + claz
0505:                                                    + " in "
0506:                                                    + getSystemId()
0507:                                                    + ", this makes only sense for FunctionProviders.");
0508:                                }
0509:                                function = (Function) claz.newInstance();
0510:                            } else if (FunctionProvider.class
0511:                                    .isAssignableFrom(claz)) {
0512:                                if ("".equals(providerKey))
0513:                                    providerKey = functionName;
0514:                                if ("".equals(providerKey)) {
0515:                                    log.error("FunctionProvider " + claz
0516:                                            + " specified in " + getSystemId()
0517:                                            + " without key or name");
0518:                                    continue;
0519:                                }
0520:                                FunctionProvider provider = (FunctionProvider) claz
0521:                                        .newInstance();
0522:                                function = provider.getFunction(providerKey);
0523:                                if (function == null) {
0524:                                    log.error("Function provider " + provider
0525:                                            + "has no function '" + providerKey
0526:                                            + "'");
0527:                                    continue;
0528:                                }
0529:                            } else {
0530:                                if ("".equals(providerKey))
0531:                                    providerKey = functionName;
0532:                                if ("".equals(providerKey)) {
0533:                                    log
0534:                                            .error("Speficied class "
0535:                                                    + claz
0536:                                                    + " in "
0537:                                                    + getSystemId()
0538:                                                    + "/functionslist/function is not a Function or FunctionProvider and can not be wrapped in a BeanFunction, because neither key nor name attribute were specified.");
0539:                                    continue;
0540:                                }
0541:                                java.lang.reflect.Method method = MethodFunction
0542:                                        .getMethod(claz, providerKey);
0543:                                if (method == null) {
0544:                                    log.error("Could not find  method '"
0545:                                            + providerKey + "' in " + claz);
0546:                                    continue;
0547:                                } else {
0548:                                    if (method.getParameterTypes().length == 0) {
0549:                                        function = BeanFunction.getFunction(
0550:                                                claz, providerKey,
0551:                                                new BeanFunction.Producer() {
0552:                                                    public Object getInstance() {
0553:                                                        try {
0554:                                                            return BeanFunction
0555:                                                                    .getInstance(
0556:                                                                            claz,
0557:                                                                            builder);
0558:                                                        } catch (Exception e) {
0559:                                                            log
0560:                                                                    .error(
0561:                                                                            e
0562:                                                                                    .getMessage(),
0563:                                                                            e);
0564:                                                            return null;
0565:                                                        }
0566:                                                    }
0567:
0568:                                                    public String toString() {
0569:                                                        return ""
0570:                                                                + claz
0571:                                                                        .getName()
0572:                                                                + "."
0573:                                                                + builder
0574:                                                                        .getTableName();
0575:                                                    }
0576:                                                });
0577:                                    } else {
0578:                                        if (method.getClass().isInstance(
0579:                                                builder)) {
0580:                                            function = MethodFunction
0581:                                                    .getFunction(method,
0582:                                                            providerKey,
0583:                                                            builder);
0584:                                        } else {
0585:                                            function = MethodFunction
0586:                                                    .getFunction(method,
0587:                                                            providerKey);
0588:                                        }
0589:                                    }
0590:                                }
0591:                            }
0592:                            if (!functionName.equals("")
0593:                                    && !function.getName().equals(functionName)) {
0594:                                log.debug("Wrapping " + function.getName()
0595:                                        + " to " + functionName);
0596:                                function = new WrappedFunction(function) {
0597:                                    public String getName() {
0598:                                        return functionName;
0599:                                    }
0600:                                };
0601:                            }
0602:
0603:                            String key = function.getName();
0604:                            Function existing = results.get(key);
0605:
0606:                            if (existing != null) {
0607:                                log.info("Function " + key
0608:                                        + " already defined, will combine it");
0609:                                CombinedFunction cf;
0610:                                if (existing instanceof  CombinedFunction) {
0611:                                    cf = (CombinedFunction) existing;
0612:                                } else {
0613:                                    cf = new CombinedFunction(key);
0614:                                    cf.addFunction(existing);
0615:                                }
0616:                                cf.addFunction(function);
0617:                                function = cf;
0618:                            }
0619:
0620:                            NodeFunction nf = NodeFunction.wrap(function);
0621:                            if (nf != null)
0622:                                function = nf;
0623:
0624:                            results.put(key, function);
0625:                            log.debug("functions are now: " + results);
0626:                        } catch (ClassNotFoundException cnfe) {
0627:                            log.warn(cnfe.getMessage());
0628:                        } catch (Throwable e) {
0629:                            log.error(e.getMessage(), e);
0630:                        }
0631:                    }
0632:                }
0633:                Set<Function> r = new HashSet<Function>();
0634:                for (Function fun : results.values()) {
0635:                    r.add(fun);
0636:                }
0637:                log.debug("Found functions " + r);
0638:                return r;
0639:
0640:            }
0641:
0642:            /**
0643:             * Determine an integer value from an elements body.
0644:             * Used for the List, Search, and Edit position values.
0645:             * @param elm The element containing the value.
0646:             * @return the parsed integer
0647:             */
0648:            private int getEditorPos(Element elm) {
0649:                try {
0650:                    int val = Integer.parseInt(getElementValue(elm));
0651:                    return val;
0652:                } catch (Exception e) {
0653:                    return -1;
0654:                }
0655:            }
0656:
0657:            /**
0658:             * Alter a specified, named FieldDef object using information obtained from the buidler configuration.
0659:             * Only GUI information is retrieved and stored (name and type of the field sg=hould already be specified).
0660:             * @since MMBase-1.6
0661:             * @param elm The element containing the field information acc. to the buidler xml format
0662:             * @param def The field definition to alter
0663:             */
0664:            private void decodeFieldDef(Element field, CoreField def,
0665:                    DataTypeCollector collector) {
0666:                // Gui
0667:                Element descriptions = getElementByPath(field,
0668:                        "field.descriptions");
0669:                if (descriptions != null) {
0670:                    def.getLocalizedDescription().fillFromXml("description",
0671:                            descriptions);
0672:                }
0673:
0674:                // XXX: deprecated tag 'gui'
0675:                Element gui = getElementByPath(field, "field.gui");
0676:                if (gui != null) {
0677:                    def.getLocalizedGUIName().fillFromXml("guiname", gui);
0678:                    // XXX: even more deprecated
0679:                    def.getLocalizedGUIName().fillFromXml("name", gui);
0680:                }
0681:
0682:                // Editor
0683:                Element editorpos = getElementByPath(field,
0684:                        "field.editor.positions.input");
0685:                if (editorpos != null) {
0686:                    int inputPos = getEditorPos(editorpos);
0687:                    if (inputPos > -1)
0688:                        inputPositions.add(inputPos);
0689:                    def.setEditPosition(inputPos);
0690:                } else {
0691:                    // if not specified, use lowest 'free' position.
0692:                    int i = 1;
0693:                    while (inputPositions.contains(i)) {
0694:                        ++i;
0695:                    }
0696:                    inputPositions.add(i);
0697:                    def.setEditPosition(i);
0698:
0699:                }
0700:                editorpos = getElementByPath(field,
0701:                        "field.editor.positions.list");
0702:                if (editorpos != null) {
0703:                    def.setListPosition(getEditorPos(editorpos));
0704:                }
0705:                editorpos = getElementByPath(field,
0706:                        "field.editor.positions.search");
0707:                if (editorpos != null) {
0708:                    int searchPos = getEditorPos(editorpos);
0709:                    if (searchPos > -1)
0710:                        searchPositions.add(searchPos);
0711:                    def.setSearchPosition(searchPos);
0712:                } else {
0713:                    // if not specified, use lowest 'free' position, unless, db-type is BINARY (non-sensical searching on that)
0714:                    // or the field is not in storage at all (search cannot be performed by database)
0715:                    if (def.getType() != Field.TYPE_BINARY && !def.isVirtual()) {
0716:                        int i = 1;
0717:                        while (searchPositions.contains(i)) {
0718:                            ++i;
0719:                        }
0720:                        searchPositions.add(i);
0721:                        def.setSearchPosition(i);
0722:                    } else {
0723:                        def.setSearchPosition(-1);
0724:                    }
0725:                }
0726:            }
0727:
0728:            /**
0729:             * Determine a data type instance based on the given gui element
0730:             * @todo  'guitype' may become deprecated in favour of the 'datatype' element
0731:             * @param builder the MMObjectBuilder to which the field belongs
0732:             * @param collector The DataTypeCollector of the bulider.
0733:             * @param fieldName the name of the field (used in log messages)
0734:             * @param field     The 'field' element of the builder xml
0735:             * @param type      The database type of the field
0736:             * @param listItemType If the database type is a List, there is also a type of its element
0737:             * @param forceInstance If true, it will never return <code>null</code>, but will return (a clone) of the DataType associated with the database type.
0738:             * @since MMBase-1.8
0739:             */
0740:            protected DataType decodeDataType(final MMObjectBuilder builder,
0741:                    final DataTypeCollector collector, final String fieldName,
0742:                    final Element field, final int type,
0743:                    final int listItemType, final boolean forceInstance) {
0744:                BasicDataType baseDataType = null;
0745:                if (type == Field.TYPE_LIST) {
0746:                    baseDataType = DataTypes.getListDataType(listItemType);
0747:                } else if (type != Field.TYPE_UNKNOWN) {
0748:                    baseDataType = DataTypes.getDataType(type);
0749:                }
0750:                BasicDataType dataType = null;
0751:                Element guiTypeElement = getElementByPath(field,
0752:                        "field.gui.guitype");
0753:
0754:                // XXX: deprecated tag 'type'
0755:                if (guiTypeElement == null) {
0756:                    guiTypeElement = getElementByPath(field, "field.gui.type");
0757:                }
0758:
0759:                // Backwards compatible 'guitype' support
0760:                if (guiTypeElement != null && collector != null) {
0761:                    if (baseDataType == null) {
0762:                        throw new IllegalArgumentException("No type defined");
0763:                    }
0764:                    String guiType = getElementValue(guiTypeElement);
0765:                    if (!guiType.equals("")) {
0766:                        if (guiType.indexOf('.') != -1) {
0767:                            // apparently, this is a class path, which means it is probably an enumeration
0768:                            // (if not, what else?)
0769:                            dataType = (BasicDataType) baseDataType.clone();
0770:                            dataType.getEnumerationFactory().addBundle(guiType,
0771:                                    getClass().getClassLoader(), null,
0772:                                    dataType.getTypeAsClass(), null);
0773:                            dataType.getEnumerationRestriction()
0774:                                    .setEnforceStrength(DataType.ENFORCE_NEVER);
0775:                        } else {
0776:                            // check for builder names when the type is NODE
0777:                            MMObjectBuilder enumerationBuilder = null;
0778:                            // The guitype is deprecated. Normally coincides with datatype's id.
0779:                            // The following are exceptions:
0780:                            // 'string' is surrogated with the datatype 'line'.
0781:                            if ("string".equals(guiType)) {
0782:                                guiType = "line";
0783:                                if (log.isDebugEnabled()) {
0784:                                    log
0785:                                            .debug("Converted deprecated guitype 'string' for field "
0786:                                                    + (builder != null ? builder
0787:                                                            .getTableName()
0788:                                                            + "."
0789:                                                            : "")
0790:                                                    + fieldName
0791:                                                    + " with datatype 'line'.");
0792:                                }
0793:                            } else
0794:                            // 'eventtime' is surrogated with the datatype 'datetime'.
0795:                            if ("eventtime".equals(guiType)) {
0796:                                guiType = "datetime";
0797:                                if (log.isDebugEnabled()) {
0798:                                    log
0799:                                            .debug("Converted deprecated guitype 'eventtime' for field "
0800:                                                    + (builder != null ? builder
0801:                                                            .getTableName()
0802:                                                            + "."
0803:                                                            : "")
0804:                                                    + fieldName
0805:                                                    + " with datatype 'datetime'.");
0806:                                }
0807:                            } else
0808:                            // 'relativetime' is surrogated with the datatype 'line'.
0809:                            if ("relativetime".equals(guiType)) {
0810:                                guiType = "duration";
0811:                                if (log.isDebugEnabled()) {
0812:                                    log
0813:                                            .debug("Converted deprecated guitype 'relativetime' for field "
0814:                                                    + (builder != null ? builder
0815:                                                            .getTableName()
0816:                                                            + "."
0817:                                                            : "")
0818:                                                    + fieldName
0819:                                                    + " with datatype 'duration'.");
0820:                                }
0821:                            } else if (type == Field.TYPE_NODE) {
0822:                                if (guiType == null) {
0823:                                    if (log.isDebugEnabled())
0824:                                        log.debug("Gui type of NODE field '"
0825:                                                + fieldName + "' is null");
0826:                                } else {
0827:                                    enumerationBuilder = mmbase
0828:                                            .getBuilder(guiType);
0829:                                    if (enumerationBuilder == null) {
0830:                                        if (log.isDebugEnabled())
0831:                                            log
0832:                                                    .debug("Gui type of NODE field is '"
0833:                                                            + fieldName
0834:                                                            + "'not a known builder");
0835:                                    }
0836:                                }
0837:                            }
0838:                            if (enumerationBuilder != null) {
0839:                                //  Create a query element of the format:
0840:                                //  <query type="[buildername]" xmlns="http://www.mmbase.org/xmlns/searchquery" />
0841:                                // and add it to the enumerationfactory using addQuery()
0842:                                Element queryElement = guiTypeElement
0843:                                        .getOwnerDocument()
0844:                                        .createElementNS(
0845:                                                "http://www.mmbase.org/xmlns/searchquery",
0846:                                                "query");
0847:                                queryElement.setAttribute("type",
0848:                                        enumerationBuilder.getTableName());
0849:                                dataType = (BasicDataType) baseDataType.clone();
0850:                                Document queryDocument = DocumentReader
0851:                                        .toDocument(queryElement);
0852:                                dataType
0853:                                        .getEnumerationFactory()
0854:                                        .addQuery(
0855:                                                LocalizedString
0856:                                                        .getLocale(queryElement),
0857:                                                queryDocument);
0858:                                dataType.getEnumerationRestriction()
0859:                                        .setEnforceStrength(
0860:                                                DataType.ENFORCE_NEVER);
0861:                            } else {
0862:                                dataType = collector.getDataTypeInstance(
0863:                                        guiType, baseDataType);
0864:                                if (dataType == null) {
0865:                                    log.warn("Could not find data type for "
0866:                                            + baseDataType
0867:                                            + " / "
0868:                                            + guiType
0869:                                            + " for builder: '"
0870:                                            + (builder == null ? "NULL"
0871:                                                    : builder.getTableName())
0872:                                            + "'");
0873:
0874:                                }
0875:                            }
0876:                        }
0877:                    }
0878:                }
0879:
0880:                Element dataTypeElement = getElementByPath(field,
0881:                        "field.datatype");
0882:
0883:                if (dataTypeElement != null) {
0884:                    if (dataType != null) {
0885:                        log
0886:                                .warn("Using both deprecated 'gui/guitype' and 'datatype' subelements in field tag for field '"
0887:                                        + fieldName
0888:                                        + "', ignoring the first one.");
0889:                    }
0890:                    BasicDataType requestedBaseDataType; // pointer to the original field's datatype which will be used as a base.
0891:                    String base = dataTypeElement.getAttribute("base");
0892:                    if (base.equals("")) {
0893:                        if (log.isDebugEnabled()) {
0894:                            log.debug("No base defined, using '" + baseDataType
0895:                                    + "'");
0896:                        }
0897:                        if (baseDataType == null) {
0898:                            throw new IllegalArgumentException(
0899:                                    "No base datatype given, and no field type defined");
0900:                        }
0901:                        requestedBaseDataType = baseDataType;
0902:                    } else {
0903:                        requestedBaseDataType = collector == null ? null
0904:                                : collector.getDataType(base, true);
0905:                        if (requestedBaseDataType == null) {
0906:                            log.error("Could not find base datatype for '"
0907:                                    + base
0908:                                    + "' falling back to "
0909:                                    + baseDataType
0910:                                    + " in builder '"
0911:                                    + (builder == null ? "NULL" : builder
0912:                                            .getTableName()) + "'");
0913:                            requestedBaseDataType = baseDataType;
0914:                        }
0915:                    }
0916:                    try {
0917:                        dataType = DataTypeReader.readDataType(dataTypeElement,
0918:                                requestedBaseDataType, collector).dataType;
0919:                    } catch (DependencyException de) {
0920:                        dataType = de.fallback();
0921:                    }
0922:                    if (log.isDebugEnabled())
0923:                        log.debug("Found datatype " + dataType + " for field "
0924:                                + fieldName);
0925:                }
0926:
0927:                // try to resolve any issues where the datatype differs from the database type
0928:                if (dataType != null
0929:                        && baseDataType != null
0930:                        && !baseDataType.getClass().isAssignableFrom(
0931:                                dataType.getClass())) {
0932:                    // the thus configured datatype is not compatible with the database type.
0933:                    // Fix that as good as possible:
0934:                    BasicDataType newDataType = (BasicDataType) dataType
0935:                            .clone();
0936:                    newDataType.inherit(baseDataType);
0937:                    if (log.isDebugEnabled())
0938:                        log
0939:                                .debug(""
0940:                                        + dataType
0941:                                        + " in '"
0942:                                        + getSystemId()
0943:                                        + "' field "
0944:                                        + fieldName
0945:                                        + " is not compatible with "
0946:                                        + baseDataType
0947:                                        + ". Cloning and inheriting to support gracefull fall backs -> "
0948:                                        + newDataType);
0949:                    dataType = newDataType;
0950:                }
0951:
0952:                if (dataType == null && forceInstance) {
0953:                    // DataType is null if no data type element was found
0954:                    if (baseDataType == null) {
0955:                        throw new IllegalArgumentException(
0956:                                "No datatype given, and no type defined");
0957:                    }
0958:                    dataType = (BasicDataType) baseDataType.clone(""); // clone with empty id
0959:                }
0960:
0961:                return dataType;
0962:            }
0963:
0964:            /**
0965:             * @since MMBase-1.8.6
0966:             */
0967:            private void decodeFieldAttributes(Element field, CoreField def) {
0968:                String fieldState = getElementAttributeValue(field, "state");
0969:                String fieldReadOnly = getElementAttributeValue(field,
0970:                        "readonly");
0971:                // deprecated db type tag - only use if no other data is given!
0972:                Element dbtype = getElementByPath(field, "field.db.type");
0973:                if (dbtype != null) {
0974:                    if ("".equals(fieldState))
0975:                        fieldState = getElementAttributeValue(dbtype, "state");
0976:                    if ("".equals(fieldReadOnly))
0977:                        fieldReadOnly = getElementAttributeValue(dbtype,
0978:                                "readonly");
0979:                }
0980:
0981:                // state - default peristent
0982:                int state = Field.STATE_PERSISTENT;
0983:                if (!"".equals(fieldState)) {
0984:                    state = Fields.getState(fieldState);
0985:                }
0986:                if (state != def.getState())
0987:                    def.setState(state);
0988:
0989:                boolean readOnly = false;
0990:                if ("".equals(fieldReadOnly)) {
0991:                    readOnly = state == Field.STATE_SYSTEM
0992:                            || state == Field.STATE_SYSTEM_VIRTUAL;
0993:                } else {
0994:                    readOnly = "true".equalsIgnoreCase(fieldReadOnly);
0995:                }
0996:
0997:                if (def.isReadOnly() != readOnly) {
0998:                    def.setReadOnly(readOnly);
0999:                }
1000:            }
1001:
1002:            /**
1003:             * Construct a FieldDef object using a field Element using information
1004:             * obtained from the builder configuration.
1005:             * @since MMBase-1.8
1006:             */
1007:            private CoreField decodeFieldDef(MMObjectBuilder builder,
1008:                    DataTypeCollector collector, Element field) {
1009:                // create a new CoreField we need to fill
1010:
1011:                // obtain field name.
1012:                // if both the field name attribute and the <db><name> tag are specified, the attribute takes precedence.
1013:                String fieldName = getElementAttributeValue(field, "name");
1014:                String fieldDBName = getElementValue(getElementByPath(field,
1015:                        "field.db.name"));
1016:                if ("".equals(fieldName)) {
1017:                    if ("".equals(fieldDBName)) {
1018:                        throw new IllegalArgumentException(
1019:                                "Field name was not specified for builder "
1020:                                        + builder.getTableName() + ".");
1021:                    }
1022:                    if (log.isDebugEnabled()) {
1023:                        log.debug("<db><name> tag for field '" + fieldDBName
1024:                                + "' is deprecated. Use the name attribute.");
1025:                    }
1026:                    fieldName = fieldDBName;
1027:                } else if (!"".equals(fieldDBName)) {
1028:                    log
1029:                            .warn("Specified field name twice: once in the name attribute ('"
1030:                                    + fieldName
1031:                                    + "') and once in the <name> tag ('"
1032:                                    + fieldDBName + "'). Ignoring name tag.");
1033:                }
1034:
1035:                // implied by datatype
1036:                // use db/type to override for legacy database issues
1037:                // (mostly to prevent warnings in the log, as mmbase fixes this anyway)
1038:                String fieldType = "";
1039:                String fieldSize = "";
1040:                String fieldNotNull = "";
1041:
1042:                // defined in datatype
1043:                String fieldRequired = "";
1044:                String fieldUnique = "";
1045:
1046:                // deprecated db type tag - only use if no other data is given!
1047:                Element dbtype = getElementByPath(field, "field.db.type");
1048:                if (dbtype != null) {
1049:                    if (!"".equals(fieldType) || !"".equals(fieldNotNull)
1050:                            || !"".equals(fieldSize)) {
1051:                        log
1052:                                .warn("Specified field type info for '"
1053:                                        + fieldName
1054:                                        + "' twice: once in the field tag attributes and once in the <db><type> tag.");
1055:                    } else {
1056:                        if (log.isDebugEnabled()) {
1057:                            log.debug("<db><type> tag for field '" + fieldName
1058:                                    + "' is deprecated.");
1059:                        }
1060:                        fieldType = getElementValue(dbtype);
1061:                        fieldNotNull = getElementAttributeValue(dbtype,
1062:                                "notnull");
1063:                        fieldRequired = getElementAttributeValue(dbtype,
1064:                                "required");
1065:                        fieldUnique = getElementAttributeValue(dbtype, "unique");
1066:                        fieldSize = getElementAttributeValue(dbtype, "size");
1067:                    }
1068:                }
1069:
1070:                // type - default unknown (derived from datatype)
1071:                int type = Field.TYPE_UNKNOWN;
1072:                int listItemType = Field.TYPE_UNKNOWN;
1073:                if (!"".equals(fieldType)) {
1074:                    type = Fields.getType(fieldType);
1075:                    if (type == Field.TYPE_LIST) {
1076:                        if (fieldType.length() > 5) {
1077:                            listItemType = Fields.getType(fieldType.substring(
1078:                                    5, fieldType.length() - 1));
1079:                        }
1080:                    }
1081:                }
1082:
1083:                // datatype
1084:                DataType dataType = decodeDataType(builder, collector,
1085:                        fieldName, field, type, listItemType, true);
1086:
1087:                // determine type from datatype, if possible)
1088:                if (type == Field.TYPE_UNKNOWN) {
1089:                    type = dataType.getBaseType();
1090:                    if (type == Field.TYPE_LIST) {
1091:                        listItemType = ((ListDataType) dataType)
1092:                                .getItemDataType().getBaseType();
1093:                    }
1094:                }
1095:
1096:                CoreField def = Fields.createField(fieldName, type,
1097:                        listItemType, Field.STATE_VIRTUAL,/*temp default, will set by decodeFieldAttributes*/
1098:                        dataType);
1099:                dataType = def.getDataType();
1100:
1101:                decodeFieldAttributes(field, def);
1102:
1103:                def.setParent(builder);
1104:
1105:                if (!fieldSize.equals("")) {
1106:                    try {
1107:                        def.setMaxLength(Integer.parseInt(fieldSize));
1108:                    } catch (NumberFormatException e) {
1109:                        log.warn("invalid value for size : " + fieldSize);
1110:                    }
1111:                }
1112:
1113:                // set required property, but only if given
1114:                if (!"".equals(fieldRequired)) {
1115:                    dataType
1116:                            .setRequired("true".equalsIgnoreCase(fieldRequired));
1117:                }
1118:
1119:                // default for notnull is value of required
1120:                def.setNotNull("true".equals(fieldNotNull)
1121:                        || ("".equals(fieldNotNull) && dataType.isRequired()));
1122:
1123:                // set unique property, but only if given
1124:                if ("implied".equalsIgnoreCase(fieldUnique)) {
1125:                    dataType.setUnique(true);
1126:                    dataType.getUniqueRestriction().setEnforceStrength(
1127:                            DataType.ENFORCE_NEVER);
1128:                } else if ("true".equalsIgnoreCase(fieldUnique)) {
1129:                    dataType.setUnique(true);
1130:                }
1131:
1132:                decodeFieldDef(field, def, collector);
1133:
1134:                return def;
1135:            }
1136:
1137:            /**
1138:             * Get the properties of this builder
1139:             * @code-conventions return type should be Map
1140:             * @return the properties in a Map (as name-value pairs)
1141:             */
1142:            public Hashtable<String, String> getProperties() {
1143:                Hashtable<String, String> results = new Hashtable<String, String>();
1144:                if (parentBuilder != null) {
1145:                    Map<String, String> parentparams = parentBuilder
1146:                            .getInitParameters();
1147:                    if (parentparams != null) {
1148:                        results.putAll(parentparams);
1149:                    }
1150:                }
1151:                for (Element p : getChildElements("builder.properties",
1152:                        "property")) {
1153:                    String name = getElementAttributeValue(p, "name");
1154:                    String value = getElementValue(p);
1155:                    results.put(name, value);
1156:                }
1157:                return results;
1158:            }
1159:
1160:            /**
1161:             * Get the descriptions of this module.
1162:             * @return the descriptions as a LocalizedString
1163:             */
1164:            public LocalizedString getLocalizedDescription(
1165:                    LocalizedString description) {
1166:                description.fillFromXml("description",
1167:                        getElementByPath("builder.descriptions"));
1168:                return description;
1169:            }
1170:
1171:            /**
1172:             * Get the (gui) names of this module.
1173:             * @return the names as a LocalizedString
1174:             */
1175:            public LocalizedString getLocalizedSingularName(
1176:                    LocalizedString guiName) {
1177:                guiName.fillFromXml("singular",
1178:                        getElementByPath("builder.names"));
1179:                return guiName;
1180:            }
1181:
1182:            /**
1183:             * Get the (gui) names of this module.
1184:             * @return the names as a LocalizedString
1185:             */
1186:            public LocalizedString getLocalizedPluralName(
1187:                    LocalizedString guiName) {
1188:                guiName
1189:                        .fillFromXml("plural",
1190:                                getElementByPath("builder.names"));
1191:                return guiName;
1192:            }
1193:
1194:            /**
1195:             * Get the descriptions of this builder
1196:             * @deprecated use getLocalizedDescription()
1197:             * @return the descriptions in a Map, accessible by language
1198:             */
1199:            public Hashtable<String, String> getDescriptions() {
1200:                Hashtable<String, String> results = new Hashtable<String, String>();
1201:                for (Element desc : getChildElements("builder.descriptions",
1202:                        "description")) {
1203:                    String lang = getElementAttributeValue(desc, "xml:lang");
1204:                    results.put(lang, getElementValue(desc));
1205:                }
1206:                return results;
1207:            }
1208:
1209:            /**
1210:             * Get the plural names of this builder
1211:             * @deprecated use getLocalizedPluralName()
1212:             * @return the plural names in a Map, accessible by language
1213:             */
1214:            public Hashtable<String, String> getPluralNames() {
1215:                Hashtable<String, String> results = new Hashtable<String, String>();
1216:                for (Element name : getChildElements("builder.names", "plural")) {
1217:                    String lang = getElementAttributeValue(name, "xml:lang");
1218:                    results.put(lang, getElementValue(name));
1219:                }
1220:                return results;
1221:            }
1222:
1223:            /**
1224:             * Get the singular (GUI) names of this builder
1225:             * @deprecated use getLocalizedSingularName()
1226:             * @return the singular names in a Map, accessible by language
1227:             */
1228:            public Hashtable<String, String> getSingularNames() {
1229:                Hashtable<String, String> results = new Hashtable<String, String>();
1230:                for (Element name : getChildElements("builder.names",
1231:                        "singular")) {
1232:                    String lang = getElementAttributeValue(name, "xml:lang");
1233:                    results.put(lang, getElementValue(name));
1234:                }
1235:                return results;
1236:            }
1237:
1238:            /**
1239:             * Get the builder that this builder extends
1240:             *
1241:             * @since MMBase-1.6
1242:             * @return the parent as an MMObjectBuilder, or null if not specified or unresolved
1243:             */
1244:            public MMObjectBuilder getParentBuilder() {
1245:                return parentBuilder;
1246:            }
1247:
1248:            /**
1249:             * Get the name of the builder that this builder extends
1250:             * @since MMBase-1.8
1251:             * @return the name of the parent builder
1252:             */
1253:            public String getExtends() {
1254:                return getElementAttributeValue("builder", "extends");
1255:            }
1256:
1257:            /**
1258:             * Retrieve the (major) version number of this builder
1259:             * @since MMBase-1.8
1260:             * @return the version as an integer.
1261:             */
1262:            public int getVersion() {
1263:                String version = getElementAttributeValue("builder", "version");
1264:                if (version.equals("") && parentBuilder != null) {
1265:                    return parentBuilder.getVersion();
1266:                } else {
1267:                    int n = 0;
1268:                    if (!version.equals("")) {
1269:                        try {
1270:                            n = Integer.parseInt(version);
1271:                        } catch (Exception f) {
1272:                        }
1273:                    }
1274:                    return n;
1275:                }
1276:            }
1277:
1278:            /**
1279:             * Retrieve the name of the maintainer of this builder
1280:             * @since MMBase-1.8
1281:             * @return the name fo the maintainer as a String
1282:             */
1283:            public String getMaintainer() {
1284:                String maintainer = getElementAttributeValue("builder",
1285:                        "maintainer");
1286:                if (maintainer.equals("")) {
1287:                    if (parentBuilder != null) {
1288:                        maintainer = parentBuilder.getMaintainer();
1289:                    } else {
1290:                        maintainer = "mmbase.org";
1291:                    }
1292:                }
1293:                return maintainer;
1294:            }
1295:
1296:            /**
1297:             * {@inheritDoc}
1298:             * @since MMBase-1.7
1299:             */
1300:            public boolean equals(Object o) {
1301:                if (o instanceof  BuilderReader) {
1302:                    BuilderReader b = (BuilderReader) o;
1303:                    List<CoreField> fields = getFields();
1304:                    List<CoreField> otherFields = b.getFields();
1305:                    return fields.equals(otherFields)
1306:                            && getMaintainer().equals(b.getMaintainer())
1307:                            && getVersion() == b.getVersion()
1308:                            && getExtends().equals(b.getExtends())
1309:                            && getSingularNames().equals(b.getSingularNames())
1310:                            && getPluralNames().equals(b.getPluralNames())
1311:                            && getDescriptions().equals(b.getDescriptions())
1312:                            && getProperties().equals(b.getProperties())
1313:                            && getClassName().equals(b.getClassName());
1314:                } else {
1315:                    return false;
1316:                }
1317:            }
1318:
1319:            /**
1320:             * Whether this builderreader object is equal to another for storage purposes (so, ignoring gui and documentation fields)
1321:             * @since MMBase-1.7
1322:             */
1323:            public boolean storageEquals(BuilderReader f) {
1324:                List<CoreField> otherFields = f.getFields();
1325:                List<CoreField> this Fields = getFields();
1326:                if (otherFields.size() != this Fields.size())
1327:                    return false;
1328:                for (int i = 0; i < this Fields.size(); i++) {
1329:                    CoreField this Field = this Fields.get(i);
1330:                    CoreField otherField = otherFields.get(i);
1331:                    if (!this Field.storageEquals(otherField))
1332:                        return false;
1333:                }
1334:                return true;
1335:            }
1336:
1337:            /**
1338:             * For testing only
1339:             */
1340:            public static void main(String[] argv) throws Exception {
1341:                org.mmbase.util.ResourceLoader rl = org.mmbase.util.ResourceLoader
1342:                        .getSystemRoot();
1343:                Document doc = rl.getDocument(argv[0], true,
1344:                        BuilderReader.class);
1345:                new BuilderReader(doc, null);
1346:            }
1347:
1348:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.