Source Code Cross Referenced for CmsXmlContentDefinition.java in  » Content-Management-System » opencms » org » opencms » 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 » Content Management System » opencms » org.opencms.xml 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * File   : $Source: /usr/local/cvs/opencms/src/org/opencms/xml/CmsXmlContentDefinition.java,v $
0003:         * Date   : $Date: 2008-02-27 12:05:50 $
0004:         * Version: $Revision: 1.41 $
0005:         *
0006:         * This library is part of OpenCms -
0007:         * the Open Source Content Management System
0008:         *
0009:         * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
0010:         *
0011:         * This library is free software; you can redistribute it and/or
0012:         * modify it under the terms of the GNU Lesser General Public
0013:         * License as published by the Free Software Foundation; either
0014:         * version 2.1 of the License, or (at your option) any later version.
0015:         *
0016:         * This library is distributed in the hope that it will be useful,
0017:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0019:         * Lesser General Public License for more details.
0020:         *
0021:         * For further information about Alkacon Software GmbH, please see the
0022:         * company website: http://www.alkacon.com
0023:         *
0024:         * For further information about OpenCms, please see the
0025:         * project website: http://www.opencms.org
0026:         * 
0027:         * You should have received a copy of the GNU Lesser General Public
0028:         * License along with this library; if not, write to the Free Software
0029:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0030:         */
0031:
0032:        package org.opencms.xml;
0033:
0034:        import org.opencms.file.CmsObject;
0035:        import org.opencms.main.OpenCms;
0036:        import org.opencms.util.CmsStringUtil;
0037:        import org.opencms.xml.content.CmsDefaultXmlContentHandler;
0038:        import org.opencms.xml.content.I_CmsXmlContentHandler;
0039:        import org.opencms.xml.types.CmsXmlLocaleValue;
0040:        import org.opencms.xml.types.CmsXmlNestedContentDefinition;
0041:        import org.opencms.xml.types.I_CmsXmlContentValue;
0042:        import org.opencms.xml.types.I_CmsXmlSchemaType;
0043:
0044:        import java.io.IOException;
0045:        import java.util.ArrayList;
0046:        import java.util.Arrays;
0047:        import java.util.Collections;
0048:        import java.util.HashMap;
0049:        import java.util.HashSet;
0050:        import java.util.Iterator;
0051:        import java.util.List;
0052:        import java.util.Locale;
0053:        import java.util.Map;
0054:        import java.util.Set;
0055:
0056:        import org.dom4j.Attribute;
0057:        import org.dom4j.Document;
0058:        import org.dom4j.DocumentHelper;
0059:        import org.dom4j.Element;
0060:        import org.dom4j.Namespace;
0061:        import org.dom4j.QName;
0062:        import org.xml.sax.EntityResolver;
0063:        import org.xml.sax.InputSource;
0064:        import org.xml.sax.SAXException;
0065:
0066:        /**
0067:         * Describes the structure definition of an XML content object.<p>
0068:         *
0069:         * @author Alexander Kandzior 
0070:         * 
0071:         * @version $Revision: 1.41 $ 
0072:         * 
0073:         * @since 6.0.0 
0074:         */
0075:        public class CmsXmlContentDefinition implements  Cloneable {
0076:
0077:            /** Constant for the XML schema attribute "mapto". */
0078:            public static final String XSD_ATTRIBUTE_DEFAULT = "default";
0079:
0080:            /** Constant for the XML schema attribute "elementFormDefault". */
0081:            public static final String XSD_ATTRIBUTE_ELEMENT_FORM_DEFAULT = "elementFormDefault";
0082:
0083:            /** Constant for the XML schema attribute "maxOccurs". */
0084:            public static final String XSD_ATTRIBUTE_MAX_OCCURS = "maxOccurs";
0085:
0086:            /** Constant for the XML schema attribute "minOccurs". */
0087:            public static final String XSD_ATTRIBUTE_MIN_OCCURS = "minOccurs";
0088:
0089:            /** Constant for the XML schema attribute "name". */
0090:            public static final String XSD_ATTRIBUTE_NAME = "name";
0091:
0092:            /** Constant for the XML schema attribute "schemaLocation". */
0093:            public static final String XSD_ATTRIBUTE_SCHEMA_LOCATION = "schemaLocation";
0094:
0095:            /** Constant for the XML schema attribute "type". */
0096:            public static final String XSD_ATTRIBUTE_TYPE = "type";
0097:
0098:            /** Constant for the XML schema attribute "use". */
0099:            public static final String XSD_ATTRIBUTE_USE = "use";
0100:
0101:            /** Constant for the XML schema attribute value "language". */
0102:            public static final String XSD_ATTRIBUTE_VALUE_LANGUAGE = "language";
0103:
0104:            /** Constant for the XML schema attribute value "optional". */
0105:            public static final String XSD_ATTRIBUTE_VALUE_OPTIONAL = "optional";
0106:
0107:            /** Constant for the XML schema attribute value "qualified". */
0108:            public static final String XSD_ATTRIBUTE_VALUE_QUALIFIED = "qualified";
0109:
0110:            /** Constant for the XML schema attribute value "required". */
0111:            public static final String XSD_ATTRIBUTE_VALUE_REQUIRED = "required";
0112:
0113:            /** Constant for the XML schema attribute value "unbounded". */
0114:            public static final String XSD_ATTRIBUTE_VALUE_UNBOUNDED = "unbounded";
0115:
0116:            /** Constant for the XML schema attribute value "0". */
0117:            public static final String XSD_ATTRIBUTE_VALUE_ZERO = "0";
0118:
0119:            /** The opencms default type definition include. */
0120:            public static final String XSD_INCLUDE_OPENCMS = CmsXmlEntityResolver.OPENCMS_SCHEME
0121:                    + "opencms-xmlcontent.xsd";
0122:
0123:            /** The schema definition namespace. */
0124:            public static final Namespace XSD_NAMESPACE = Namespace.get("xsd",
0125:                    "http://www.w3.org/2001/XMLSchema");
0126:
0127:            /** Constant for the "annotation" node in the XML schema namespace. */
0128:            public static final QName XSD_NODE_ANNOTATION = QName.get(
0129:                    "annotation", XSD_NAMESPACE);
0130:
0131:            /** Constant for the "appinfo" node in the XML schema namespace. */
0132:            public static final QName XSD_NODE_APPINFO = QName.get("appinfo",
0133:                    XSD_NAMESPACE);
0134:
0135:            /** Constant for the "attribute" node in the XML schema namespace. */
0136:            public static final QName XSD_NODE_ATTRIBUTE = QName.get(
0137:                    "attribute", XSD_NAMESPACE);
0138:
0139:            /** Constant for the "complexType" node in the XML schema namespace. */
0140:            public static final QName XSD_NODE_COMPLEXTYPE = QName.get(
0141:                    "complexType", XSD_NAMESPACE);
0142:
0143:            /** Constant for the "element" node in the XML schema namespace. */
0144:            public static final QName XSD_NODE_ELEMENT = QName.get("element",
0145:                    XSD_NAMESPACE);
0146:
0147:            /** Constant for the "include" node in the XML schema namespace. */
0148:            public static final QName XSD_NODE_INCLUDE = QName.get("include",
0149:                    XSD_NAMESPACE);
0150:
0151:            /** Constant for the "schema" node in the XML schema namespace. */
0152:            public static final QName XSD_NODE_SCHEMA = QName.get("schema",
0153:                    XSD_NAMESPACE);
0154:
0155:            /** Constant for the "sequence" node in the XML schema namespace. */
0156:            public static final QName XSD_NODE_SEQUENCE = QName.get("sequence",
0157:                    XSD_NAMESPACE);
0158:
0159:            /** The XML content handler. */
0160:            private I_CmsXmlContentHandler m_contentHandler;
0161:
0162:            /** The set of included additional XML content definitions. */
0163:            private Set m_includes;
0164:
0165:            /** The inner element name of the content definition (type sequence). */
0166:            private String m_innerName;
0167:
0168:            /** The outer element name of the content definition (languange sequence). */
0169:            private String m_outerName;
0170:
0171:            /** The location from which the XML schema was read (XML system id). */
0172:            private String m_schemaLocation;
0173:
0174:            /** The main type name of this XML content definition. */
0175:            private String m_typeName;
0176:
0177:            /** The Map of configured types. */
0178:            private Map m_types;
0179:
0180:            /** The type sequence. */
0181:            private List m_typeSequence;
0182:
0183:            /**
0184:             * Creates a new XML content definition.<p> 
0185:             * 
0186:             * @param innerName the inner element name to use for the content definiton
0187:             * @param schemaLocation the location from which the XML schema was read (system id)
0188:             */
0189:            public CmsXmlContentDefinition(String innerName,
0190:                    String schemaLocation) {
0191:
0192:                this (innerName + "s", innerName, schemaLocation);
0193:            }
0194:
0195:            /**
0196:             * Creates a new XML content definition.<p> 
0197:             * 
0198:             * @param outerName the outer element name to use for the content definiton
0199:             * @param innerName the inner element name to use for the content definiton
0200:             * @param schemaLocation the location from which the XML schema was read (system id)
0201:             */
0202:            public CmsXmlContentDefinition(String outerName, String innerName,
0203:                    String schemaLocation) {
0204:
0205:                m_outerName = outerName;
0206:                m_innerName = innerName;
0207:                setInnerName(innerName);
0208:                m_typeSequence = new ArrayList();
0209:                m_types = new HashMap();
0210:                m_includes = new HashSet();
0211:                m_schemaLocation = schemaLocation;
0212:                m_contentHandler = new CmsDefaultXmlContentHandler();
0213:            }
0214:
0215:            /**
0216:             * Required empty constructor for clone operation.<p>
0217:             */
0218:            protected CmsXmlContentDefinition() {
0219:
0220:                // noop, required for clone operation
0221:            }
0222:
0223:            /**
0224:             * Factory method to unmarshal (read) a XML content definition instance from a byte array
0225:             * that contains XML data.<p>
0226:             * 
0227:             * @param xmlData the XML data in a byte array
0228:             * @param schemaLocation the location from which the XML schema was read (system id)
0229:             * @param resolver the XML entitiy resolver to use
0230:             * 
0231:             * @return a XML content definition instance unmarshalled from the byte array
0232:             * 
0233:             * @throws CmsXmlException if something goes wrong
0234:             */
0235:            public static CmsXmlContentDefinition unmarshal(byte[] xmlData,
0236:                    String schemaLocation, EntityResolver resolver)
0237:                    throws CmsXmlException {
0238:
0239:                CmsXmlContentDefinition result = getCachedContentDefinition(
0240:                        schemaLocation, resolver);
0241:                if (result == null) {
0242:                    // content definition was not found in the cache, unmarshal the XML document
0243:                    result = unmarshalInternal(CmsXmlUtils.unmarshalHelper(
0244:                            xmlData, resolver), schemaLocation, resolver);
0245:                }
0246:                return result;
0247:            }
0248:
0249:            /**
0250:             * Factory method to unmarshal (read) a XML content definition instance from the OpenCms VFS resource name.<p>
0251:             * 
0252:             * @param cms the current users CmsObject
0253:             * @param resourcename the resource name to unmarshal the XML content definition from
0254:             * 
0255:             * @return a XML content definition instance unmarshalled from the VFS resource
0256:             * 
0257:             * @throws CmsXmlException if something goes wrong
0258:             */
0259:            public static CmsXmlContentDefinition unmarshal(CmsObject cms,
0260:                    String resourcename) throws CmsXmlException {
0261:
0262:                CmsXmlEntityResolver resolver = new CmsXmlEntityResolver(cms);
0263:                String schemaLocation = CmsXmlEntityResolver.OPENCMS_SCHEME
0264:                        .concat(resourcename.substring(1));
0265:                CmsXmlContentDefinition result = getCachedContentDefinition(
0266:                        schemaLocation, resolver);
0267:                if (result == null) {
0268:                    // content definition was not found in the cache, unmarshal the XML document
0269:                    InputSource source = resolver.resolveEntity(null,
0270:                            schemaLocation);
0271:                    result = unmarshalInternal(CmsXmlUtils.unmarshalHelper(
0272:                            source, resolver), schemaLocation, resolver);
0273:                }
0274:                return result;
0275:            }
0276:
0277:            /**
0278:             * Factory method to unmarshal (read) a XML content definition instance from a XML document.<p>
0279:             * 
0280:             * This method does additional validation to ensure the document has the required
0281:             * XML structure for a OpenCms content definition schema.<p>
0282:             * 
0283:             * @param document the XML document to generate a XML content definition from
0284:             * @param schemaLocation the location from which the XML schema was read (system id)
0285:             * 
0286:             * @return a XML content definition instance unmarshalled from the XML document
0287:             * 
0288:             * @throws CmsXmlException if something goes wrong
0289:             */
0290:            public static CmsXmlContentDefinition unmarshal(Document document,
0291:                    String schemaLocation) throws CmsXmlException {
0292:
0293:                EntityResolver resolver = document.getEntityResolver();
0294:                CmsXmlContentDefinition result = getCachedContentDefinition(
0295:                        schemaLocation, resolver);
0296:                if (result == null) {
0297:                    // content definition was not found in the cache, unmarshal the XML document
0298:                    result = unmarshalInternal(document, schemaLocation,
0299:                            resolver);
0300:                }
0301:                return result;
0302:            }
0303:
0304:            /**
0305:             * Factory method to unmarshal (read) a XML content definition instance from a XML InputSource.<p>
0306:             * 
0307:             * @param source the XML InputSource to use
0308:             * @param schemaLocation the location from which the XML schema was read (system id)
0309:             * @param resolver the XML entitiy resolver to use
0310:             * 
0311:             * @return a XML content definition instance unmarshalled from the InputSource
0312:             * 
0313:             * @throws CmsXmlException if something goes wrong
0314:             */
0315:            public static CmsXmlContentDefinition unmarshal(InputSource source,
0316:                    String schemaLocation, EntityResolver resolver)
0317:                    throws CmsXmlException {
0318:
0319:                CmsXmlContentDefinition result = getCachedContentDefinition(
0320:                        schemaLocation, resolver);
0321:                if (result == null) {
0322:                    // content definition was not found in the cache, unmarshal the XML document
0323:                    result = unmarshalInternal(CmsXmlUtils.unmarshalHelper(
0324:                            source, resolver), schemaLocation, resolver);
0325:                }
0326:                return result;
0327:            }
0328:
0329:            /**
0330:             * Factory method to unmarshal (read) a XML content definition instance from a given XML schema location.<p>
0331:             * 
0332:             * The XML content definiton data to unmarshal will be read from the provided schema location using
0333:             * an XML InputSource.<p>
0334:             * 
0335:             * @param schemaLocation the location from which to read the XML schema (system id)
0336:             * @param resolver the XML entitiy resolver to use
0337:             * 
0338:             * @return a XML content definition instance unmarshalled from the InputSource
0339:             * 
0340:             * @throws CmsXmlException if something goes wrong
0341:             * @throws SAXException if the XML schema location could not be converted to an XML InputSource
0342:             * @throws IOException if the XML schema location could not be converted to an XML InputSource
0343:             */
0344:            public static CmsXmlContentDefinition unmarshal(
0345:                    String schemaLocation, EntityResolver resolver)
0346:                    throws CmsXmlException, SAXException, IOException {
0347:
0348:                CmsXmlContentDefinition result = getCachedContentDefinition(
0349:                        schemaLocation, resolver);
0350:                if (result == null) {
0351:                    // content definition was not found in the cache, unmarshal the XML document
0352:                    InputSource source = resolver.resolveEntity(null,
0353:                            schemaLocation);
0354:                    result = unmarshalInternal(CmsXmlUtils.unmarshalHelper(
0355:                            source, resolver), schemaLocation, resolver);
0356:                }
0357:                return result;
0358:            }
0359:
0360:            /**
0361:             * Factory method to unmarshal (read) a XML content definition instance from a String
0362:             * that contains XML data.<p>
0363:             * 
0364:             * @param xmlData the XML data in a String
0365:             * @param schemaLocation the location from which the XML schema was read (system id)
0366:             * @param resolver the XML entitiy resolver to use
0367:             * 
0368:             * @return a XML content definition instance unmarshalled from the byte array
0369:             * 
0370:             * @throws CmsXmlException if something goes wrong
0371:             */
0372:            public static CmsXmlContentDefinition unmarshal(String xmlData,
0373:                    String schemaLocation, EntityResolver resolver)
0374:                    throws CmsXmlException {
0375:
0376:                CmsXmlContentDefinition result = getCachedContentDefinition(
0377:                        schemaLocation, resolver);
0378:                if (result == null) {
0379:                    // content definition was not found in the cache, unmarshal the XML document
0380:                    result = unmarshalInternal(CmsXmlUtils.unmarshalHelper(
0381:                            xmlData, resolver), schemaLocation, resolver);
0382:                }
0383:                return result;
0384:            }
0385:
0386:            /**
0387:             * Creates the name of the type attribute from the given content name.<p>
0388:             * 
0389:             * @param name the name to use
0390:             * 
0391:             * @return the name of the type attribute
0392:             */
0393:            protected static String createTypeName(String name) {
0394:
0395:                StringBuffer result = new StringBuffer(32);
0396:                result.append("OpenCms");
0397:                result.append(name.substring(0, 1).toUpperCase());
0398:                if (name.length() > 1) {
0399:                    result.append(name.substring(1));
0400:                }
0401:                return result.toString();
0402:            }
0403:
0404:            /**
0405:             * Validates if a given attribute exists at the given element with an (optional) specified value.<p>
0406:             * 
0407:             * If the required value is not <code>null</code>, the attribute must have excatly this 
0408:             * value set.<p> 
0409:             * 
0410:             * If no value is required, some simple validation is performed on the attribute value,
0411:             * like a check that the value does not have leading or trainling white spaces.<p>
0412:             * 
0413:             * @param element the element to validate
0414:             * @param attributeName the attribute to check for
0415:             * @param requiredValue the required value of the attribute, or <code>null</code> if any value is allowed
0416:             * 
0417:             * @return the value of the attribute
0418:             * 
0419:             * @throws CmsXmlException if the element does not have the required attribute set, or if the validation fails
0420:             */
0421:            protected static String validateAttribute(Element element,
0422:                    String attributeName, String requiredValue)
0423:                    throws CmsXmlException {
0424:
0425:                Attribute attribute = element.attribute(attributeName);
0426:                if (attribute == null) {
0427:                    throw new CmsXmlException(Messages.get().container(
0428:                            Messages.ERR_EL_MISSING_ATTRIBUTE_2,
0429:                            element.getUniquePath(), attributeName));
0430:                }
0431:                String value = attribute.getValue();
0432:
0433:                if (requiredValue == null) {
0434:                    if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)
0435:                            || !value.equals(value.trim())) {
0436:                        throw new CmsXmlException(Messages.get().container(
0437:                                Messages.ERR_EL_BAD_ATTRIBUTE_WS_3,
0438:                                element.getUniquePath(), attributeName, value));
0439:                    }
0440:                } else {
0441:                    if (!requiredValue.equals(value)) {
0442:                        throw new CmsXmlException(Messages.get().container(
0443:                                Messages.ERR_EL_BAD_ATTRIBUTE_VALUE_4,
0444:                                new Object[] { element.getUniquePath(),
0445:                                        attributeName, requiredValue, value }));
0446:                    }
0447:                }
0448:                return value;
0449:            }
0450:
0451:            /**
0452:             * Validates if a gicen element has exactly the required attributes set.<p>
0453:             * 
0454:             * @param element the element to validate
0455:             * @param requiredAttributes the list of required attributes
0456:             * @param optionalAttributes the list of optional attributes
0457:             * 
0458:             * @throws CmsXmlException if the validation fails 
0459:             */
0460:            protected static void validateAttributesExists(Element element,
0461:                    String[] requiredAttributes, String[] optionalAttributes)
0462:                    throws CmsXmlException {
0463:
0464:                if (element.attributeCount() < requiredAttributes.length) {
0465:                    throw new CmsXmlException(Messages.get().container(
0466:                            Messages.ERR_EL_ATTRIBUTE_TOOFEW_3,
0467:                            element.getUniquePath(),
0468:                            new Integer(requiredAttributes.length),
0469:                            new Integer(element.attributeCount())));
0470:                }
0471:
0472:                if (element.attributeCount() > (requiredAttributes.length + optionalAttributes.length)) {
0473:                    throw new CmsXmlException(Messages.get().container(
0474:                            Messages.ERR_EL_ATTRIBUTE_TOOMANY_3,
0475:                            element.getUniquePath(),
0476:                            new Integer(requiredAttributes.length
0477:                                    + optionalAttributes.length),
0478:                            new Integer(element.attributeCount())));
0479:                }
0480:
0481:                List attributes = element.attributes();
0482:
0483:                for (int i = 0; i < requiredAttributes.length; i++) {
0484:                    String attributeName = requiredAttributes[i];
0485:                    if (element.attribute(attributeName) == null) {
0486:                        throw new CmsXmlException(Messages.get().container(
0487:                                Messages.ERR_EL_MISSING_ATTRIBUTE_2,
0488:                                element.getUniquePath(), attributeName));
0489:                    }
0490:                }
0491:
0492:                List rA = Arrays.asList(requiredAttributes);
0493:                List oA = Arrays.asList(optionalAttributes);
0494:
0495:                for (int i = 0; i < attributes.size(); i++) {
0496:                    String attributeName = element.attribute(i).getName();
0497:                    if (!rA.contains(attributeName)
0498:                            && !oA.contains(attributeName)) {
0499:                        throw new CmsXmlException(Messages.get().container(
0500:                                Messages.ERR_EL_INVALID_ATTRIBUTE_2,
0501:                                element.getUniquePath(), attributeName));
0502:                    }
0503:                }
0504:            }
0505:
0506:            /**
0507:             * Validates the given element as a complex type sequence.<p>
0508:             * 
0509:             * @param element the element to validate
0510:             * @param includes the XML schema includes
0511:             * 
0512:             * @return a data structure containing the validated complex type sequence data 
0513:             * 
0514:             * @throws CmsXmlException if the validation fails
0515:             */
0516:            protected static CmsXmlComplexTypeSequence validateComplexTypeSequence(
0517:                    Element element, Set includes) throws CmsXmlException {
0518:
0519:                validateAttributesExists(element,
0520:                        new String[] { XSD_ATTRIBUTE_NAME }, new String[0]);
0521:
0522:                String name = validateAttribute(element, XSD_ATTRIBUTE_NAME,
0523:                        null);
0524:
0525:                // now check the type definition list
0526:                List mainElements = element.elements();
0527:                if ((mainElements.size() != 1) && (mainElements.size() != 2)) {
0528:                    throw new CmsXmlException(Messages.get().container(
0529:                            Messages.ERR_TS_SUBELEMENT_COUNT_2,
0530:                            element.getUniquePath(),
0531:                            new Integer(mainElements.size())));
0532:                }
0533:
0534:                boolean hasLanguageAttribute = false;
0535:                if (mainElements.size() == 2) {
0536:                    // two elements in the master list: the second must be the "language" attribute definition
0537:
0538:                    Element typeAttribute = (Element) mainElements.get(1);
0539:                    if (!XSD_NODE_ATTRIBUTE.equals(typeAttribute.getQName())) {
0540:                        throw new CmsXmlException(Messages.get().container(
0541:                                Messages.ERR_CD_ELEMENT_NAME_3,
0542:                                typeAttribute.getUniquePath(),
0543:                                XSD_NODE_ATTRIBUTE.getQualifiedName(),
0544:                                typeAttribute.getQName().getQualifiedName()));
0545:                    }
0546:                    validateAttribute(typeAttribute, XSD_ATTRIBUTE_NAME,
0547:                            XSD_ATTRIBUTE_VALUE_LANGUAGE);
0548:                    validateAttribute(typeAttribute, XSD_ATTRIBUTE_TYPE,
0549:                            CmsXmlLocaleValue.TYPE_NAME);
0550:                    try {
0551:                        validateAttribute(typeAttribute, XSD_ATTRIBUTE_USE,
0552:                                XSD_ATTRIBUTE_VALUE_REQUIRED);
0553:                    } catch (CmsXmlException e) {
0554:                        validateAttribute(typeAttribute, XSD_ATTRIBUTE_USE,
0555:                                XSD_ATTRIBUTE_VALUE_OPTIONAL);
0556:                    }
0557:                    // no error: then the language attribute is valid
0558:                    hasLanguageAttribute = true;
0559:                }
0560:
0561:                // check the main element type sequence
0562:                Element typeSequence = (Element) mainElements.get(0);
0563:                if (!XSD_NODE_SEQUENCE.equals(typeSequence.getQName())) {
0564:                    throw new CmsXmlException(Messages.get().container(
0565:                            Messages.ERR_CD_ELEMENT_NAME_3,
0566:                            typeSequence.getUniquePath(),
0567:                            XSD_NODE_SEQUENCE.getQualifiedName(),
0568:                            typeSequence.getQName().getQualifiedName()));
0569:                }
0570:
0571:                // check the type definition sequence
0572:                List typeSequenceElements = typeSequence.elements();
0573:                if (typeSequenceElements.size() < 1) {
0574:                    throw new CmsXmlException(Messages.get().container(
0575:                            Messages.ERR_TS_SUBELEMENT_TOOFEW_3,
0576:                            typeSequence.getUniquePath(), new Integer(1),
0577:                            new Integer(typeSequenceElements.size())));
0578:                }
0579:
0580:                // now add all type definitions from the schema
0581:                List sequence = new ArrayList();
0582:
0583:                if (hasLanguageAttribute) {
0584:                    // only generate types for sequence node with language attribute
0585:
0586:                    CmsXmlContentTypeManager typeManager = OpenCms
0587:                            .getXmlContentTypeManager();
0588:                    Iterator i = typeSequenceElements.iterator();
0589:                    while (i.hasNext()) {
0590:                        sequence.add(typeManager.getContentType((Element) i
0591:                                .next(), includes));
0592:                    }
0593:                } else {
0594:                    // generate a nested content definition for the main type sequence
0595:
0596:                    Element e = (Element) typeSequenceElements.get(0);
0597:                    String typeName = validateAttribute(e, XSD_ATTRIBUTE_NAME,
0598:                            null);
0599:                    String minOccurs = validateAttribute(e,
0600:                            XSD_ATTRIBUTE_MIN_OCCURS, XSD_ATTRIBUTE_VALUE_ZERO);
0601:                    String maxOccurs = validateAttribute(e,
0602:                            XSD_ATTRIBUTE_MAX_OCCURS,
0603:                            XSD_ATTRIBUTE_VALUE_UNBOUNDED);
0604:                    validateAttribute(e, XSD_ATTRIBUTE_TYPE,
0605:                            createTypeName(typeName));
0606:
0607:                    CmsXmlNestedContentDefinition cd = new CmsXmlNestedContentDefinition(
0608:                            null, typeName, minOccurs, maxOccurs);
0609:                    sequence.add(cd);
0610:                }
0611:
0612:                // return a data structure with the collected values
0613:                return new CmsXmlComplexTypeSequence(name, sequence,
0614:                        hasLanguageAttribute);
0615:            }
0616:
0617:            /**
0618:             * Looks up the given XML content definition system id in the internal content definition cache.<p> 
0619:             * 
0620:             * @param schemaLocation the system id of the XML content definition to look up
0621:             * @param resolver the XML entitiy resolver to use (contains the cache)
0622:             * 
0623:             * @return the XML content definition found, or null if no definition is cached for the given system id
0624:             */
0625:            private static CmsXmlContentDefinition getCachedContentDefinition(
0626:                    String schemaLocation, EntityResolver resolver) {
0627:
0628:                if (resolver instanceof  CmsXmlEntityResolver) {
0629:                    // check for a cached version of this content definition
0630:                    CmsXmlEntityResolver cmsResolver = (CmsXmlEntityResolver) resolver;
0631:                    return cmsResolver
0632:                            .getCachedContentDefinition(schemaLocation);
0633:                }
0634:                return null;
0635:            }
0636:
0637:            /**
0638:             * Internal method to unmarshal (read) a XML content definition instance from a XML document.<p>
0639:             * 
0640:             * It is assumed that the XML content definition cache has already been tested and the document 
0641:             * has not been found in the cache. After the XML content definition has been successfully created, 
0642:             * it is placed in the cache.<p>
0643:             * 
0644:             * @param document the XML document to generate a XML content definition from
0645:             * @param schemaLocation the location from which the XML schema was read (system id)
0646:             * @param resolver the XML entitiy resolver used by the given XML document
0647:             * 
0648:             * @return a XML content definition instance unmarshalled from the XML document
0649:             * 
0650:             * @throws CmsXmlException if something goes wrong
0651:             */
0652:            private static CmsXmlContentDefinition unmarshalInternal(
0653:                    Document document, String schemaLocation,
0654:                    EntityResolver resolver) throws CmsXmlException {
0655:
0656:                // analyze the document and generate the XML content type definition        
0657:                Element root = document.getRootElement();
0658:                if (!XSD_NODE_SCHEMA.equals(root.getQName())) {
0659:                    // schema node is required
0660:                    throw new CmsXmlException(Messages.get().container(
0661:                            Messages.ERR_CD_NO_SCHEMA_NODE_0));
0662:                }
0663:
0664:                List includes = root.elements(XSD_NODE_INCLUDE);
0665:                if (includes.size() < 1) {
0666:                    // one include is required
0667:                    throw new CmsXmlException(Messages.get().container(
0668:                            Messages.ERR_CD_ONE_INCLUDE_REQUIRED_0));
0669:                }
0670:
0671:                Element include = (Element) includes.get(0);
0672:                String target = validateAttribute(include,
0673:                        XSD_ATTRIBUTE_SCHEMA_LOCATION, null);
0674:                if (!XSD_INCLUDE_OPENCMS.equals(target)) {
0675:                    // the first include must point to the default OpenCms standard schema include
0676:                    throw new CmsXmlException(Messages.get().container(
0677:                            Messages.ERR_CD_FIRST_INCLUDE_2,
0678:                            XSD_INCLUDE_OPENCMS, target));
0679:                }
0680:
0681:                Set nestedDefinitions = new HashSet();
0682:                if (includes.size() > 1) {
0683:                    // resolve additional, nested include calls
0684:                    for (int i = 1; i < includes.size(); i++) {
0685:
0686:                        Element inc = (Element) includes.get(i);
0687:                        String schemaLoc = validateAttribute(inc,
0688:                                XSD_ATTRIBUTE_SCHEMA_LOCATION, null);
0689:                        InputSource source = null;
0690:                        try {
0691:                            source = resolver.resolveEntity(null, schemaLoc);
0692:                        } catch (Exception e) {
0693:                            throw new CmsXmlException(Messages.get().container(
0694:                                    Messages.ERR_CD_BAD_INCLUDE_1, schemaLoc));
0695:                        }
0696:                        CmsXmlContentDefinition xmlContentDefinition = unmarshal(
0697:                                source, schemaLoc, resolver);
0698:                        nestedDefinitions.add(xmlContentDefinition);
0699:                    }
0700:                }
0701:
0702:                List elements = root.elements(XSD_NODE_ELEMENT);
0703:                if (elements.size() != 1) {
0704:                    // only one root element is allowed
0705:                    throw new CmsXmlException(Messages.get().container(
0706:                            Messages.ERR_CD_ROOT_ELEMENT_COUNT_1,
0707:                            XSD_INCLUDE_OPENCMS, new Integer(elements.size())));
0708:                }
0709:
0710:                // collect the data from the root element node
0711:                Element main = (Element) elements.get(0);
0712:                String name = validateAttribute(main, XSD_ATTRIBUTE_NAME, null);
0713:
0714:                // now process the complex types
0715:                List complexTypes = root.elements(XSD_NODE_COMPLEXTYPE);
0716:                if (complexTypes.size() != 2) {
0717:                    // exactly two complex types are required
0718:                    throw new CmsXmlException(Messages.get().container(
0719:                            Messages.ERR_CD_COMPLEX_TYPE_COUNT_1,
0720:                            new Integer(complexTypes.size())));
0721:                }
0722:
0723:                // generate the result XML content definition
0724:                CmsXmlContentDefinition result = new CmsXmlContentDefinition(
0725:                        name, null, schemaLocation);
0726:
0727:                // set the nested definitions
0728:                result.m_includes = nestedDefinitions;
0729:
0730:                List complexTypeData = new ArrayList();
0731:                Iterator ct = complexTypes.iterator();
0732:                while (ct.hasNext()) {
0733:                    Element e = (Element) ct.next();
0734:                    CmsXmlComplexTypeSequence sequence = validateComplexTypeSequence(
0735:                            e, nestedDefinitions);
0736:                    complexTypeData.add(sequence);
0737:                }
0738:
0739:                // get the outer element sequence, this must be the first element 
0740:                CmsXmlComplexTypeSequence outerSequence = (CmsXmlComplexTypeSequence) complexTypeData
0741:                        .get(0);
0742:                CmsXmlNestedContentDefinition outer = (CmsXmlNestedContentDefinition) outerSequence.m_sequence
0743:                        .get(0);
0744:
0745:                // make sure the inner and outer element names are as required
0746:                String outerTypeName = createTypeName(name);
0747:                String innerTypeName = createTypeName(outer.getName());
0748:                validateAttribute((Element) complexTypes.get(0),
0749:                        XSD_ATTRIBUTE_NAME, outerTypeName);
0750:                validateAttribute((Element) complexTypes.get(1),
0751:                        XSD_ATTRIBUTE_NAME, innerTypeName);
0752:                validateAttribute(main, XSD_ATTRIBUTE_TYPE, outerTypeName);
0753:
0754:                // the inner name is the element name set in the outer sequence
0755:                result.setInnerName(outer.getName());
0756:
0757:                // get the inner element sequence, this must be the second element 
0758:                CmsXmlComplexTypeSequence innerSequence = (CmsXmlComplexTypeSequence) complexTypeData
0759:                        .get(1);
0760:
0761:                // add the types from the main sequence node
0762:                Iterator it = innerSequence.m_sequence.iterator();
0763:                while (it.hasNext()) {
0764:                    result.addType((I_CmsXmlSchemaType) it.next());
0765:                }
0766:
0767:                // resolve the XML content handler information
0768:                List annotations = root.elements(XSD_NODE_ANNOTATION);
0769:                I_CmsXmlContentHandler contentHandler = null;
0770:                Element appInfoElement = null;
0771:
0772:                if (annotations.size() > 0) {
0773:                    List appinfos = ((Element) annotations.get(0))
0774:                            .elements(XSD_NODE_APPINFO);
0775:
0776:                    if (appinfos.size() > 0) {
0777:                        // the first appinfo node contains the specific XML content data 
0778:                        appInfoElement = (Element) appinfos.get(0);
0779:
0780:                        // check for a special content handler in the appinfo node
0781:                        Element handlerElement = appInfoElement
0782:                                .element("handler");
0783:                        if (handlerElement != null) {
0784:                            String className = handlerElement
0785:                                    .attributeValue("class");
0786:                            if (className != null) {
0787:                                contentHandler = OpenCms
0788:                                        .getXmlContentTypeManager()
0789:                                        .getContentHandler(className,
0790:                                                schemaLocation);
0791:                            }
0792:                        }
0793:                    }
0794:                }
0795:
0796:                if (contentHandler == null) {
0797:                    // if no content handler is defined, the default handler is used
0798:                    contentHandler = OpenCms
0799:                            .getXmlContentTypeManager()
0800:                            .getContentHandler(
0801:                                    CmsDefaultXmlContentHandler.class.getName(),
0802:                                    name);
0803:                }
0804:
0805:                // analyze the app info node with the selected XML content handler
0806:                contentHandler.initialize(appInfoElement, result);
0807:                result.m_contentHandler = contentHandler;
0808:
0809:                result.freeze();
0810:
0811:                if (resolver instanceof  CmsXmlEntityResolver) {
0812:                    // put the generated content definition in the cache
0813:                    ((CmsXmlEntityResolver) resolver).cacheContentDefinition(
0814:                            schemaLocation, result);
0815:                }
0816:
0817:                return result;
0818:            }
0819:
0820:            /**
0821:             * Adds the missing default XML according to this content definition to the given document element.<p>  
0822:             * 
0823:             * In case the root element already contains subnodes, only missing subnodes are added.<p>
0824:             * 
0825:             * @param cms the current users OpenCms context
0826:             * @param document the document where the XML is added in (required for default XML generation)
0827:             * @param root the root node to add the missing XML for
0828:             * @param locale the locale to add the XML for
0829:             * 
0830:             * @return the given root element with the missing content added
0831:             */
0832:            public Element addDefaultXml(CmsObject cms,
0833:                    I_CmsXmlDocument document, Element root, Locale locale) {
0834:
0835:                Iterator i = m_typeSequence.iterator();
0836:                int currentPos = 0;
0837:                List allElements = root.elements();
0838:
0839:                while (i.hasNext()) {
0840:                    I_CmsXmlSchemaType type = (I_CmsXmlSchemaType) i.next();
0841:
0842:                    // check how many elements of this type already exist in the XML
0843:                    String elementName = type.getName();
0844:                    List elements = root.elements(elementName);
0845:
0846:                    currentPos += elements.size();
0847:                    for (int j = elements.size(); j < type.getMinOccurs(); j++) {
0848:                        // append the missing elements
0849:                        Element typeElement = type.generateXml(cms, document,
0850:                                root, locale);
0851:                        // need to check for default value again because the of appinfo "mappings" node
0852:                        I_CmsXmlContentValue value = type.createValue(document,
0853:                                typeElement, locale);
0854:                        String defaultValue = document.getContentDefinition()
0855:                                .getContentHandler().getDefault(cms, value,
0856:                                        locale);
0857:                        if (defaultValue != null) {
0858:                            // only if there is a default value available use it to overwrite the initial default
0859:                            value.setStringValue(cms, defaultValue);
0860:                        }
0861:
0862:                        // re-sort elements as they have been appended to the end of the XML root, not at the correct position
0863:                        typeElement.detach();
0864:                        allElements.add(currentPos, typeElement);
0865:                        currentPos++;
0866:                    }
0867:                }
0868:
0869:                return root;
0870:            }
0871:
0872:            /**
0873:             * Adds a nested (included) XML content definition.<p>
0874:             * 
0875:             * @param nestedSchema the nested (included) XML content definition to add
0876:             */
0877:            public void addInclude(CmsXmlContentDefinition nestedSchema) {
0878:
0879:                m_includes.add(nestedSchema);
0880:            }
0881:
0882:            /**
0883:             * Adds the given content type.<p>
0884:             * 
0885:             * @param type the content type to add
0886:             * 
0887:             * @throws CmsXmlException in case an unregistered type is added
0888:             */
0889:            public void addType(I_CmsXmlSchemaType type) throws CmsXmlException {
0890:
0891:                // check if the type to add actually exists in the type manager
0892:                CmsXmlContentTypeManager typeManager = OpenCms
0893:                        .getXmlContentTypeManager();
0894:                if (type.isSimpleType()
0895:                        && (typeManager.getContentType(type.getTypeName()) == null)) {
0896:                    throw new CmsXmlException(Messages.get().container(
0897:                            Messages.ERR_UNREGISTERED_TYPE_1,
0898:                            type.getTypeName()));
0899:                }
0900:
0901:                // add the type to the internal type sequence and lookup table
0902:                m_typeSequence.add(type);
0903:                m_types.put(type.getName(), type);
0904:
0905:                // store reference to the content definition in the type
0906:                type.setContentDefinition(this );
0907:            }
0908:
0909:            /**
0910:             * Creates a clone of this XML content definition.<p> 
0911:             * 
0912:             * @return a clone of this XML content definition
0913:             */
0914:            public Object clone() {
0915:
0916:                CmsXmlContentDefinition result = new CmsXmlContentDefinition();
0917:                result.m_innerName = m_innerName;
0918:                result.m_schemaLocation = m_schemaLocation;
0919:                result.m_typeSequence = m_typeSequence;
0920:                result.m_types = m_types;
0921:                result.m_contentHandler = m_contentHandler;
0922:                result.m_typeName = m_typeName;
0923:                result.m_includes = m_includes;
0924:                return result;
0925:            }
0926:
0927:            /**
0928:             * Generates the default XML content for this content definition, and append it to the given root element.<p>
0929:             * 
0930:             * Please note: The default values for the annotations are read from the content definition of the given
0931:             * document. For a nested content definitions, this means that all defaults are set in the annotations of the 
0932:             * "outer" or "main" content defintition.<p>
0933:             * 
0934:             * @param cms the current users OpenCms context
0935:             * @param document the OpenCms XML document the XML is created for
0936:             * @param root the node of the document where to append the generated XML to
0937:             * @param locale the locale to create the default element in the document with
0938:             * 
0939:             * @return the default XML content for this content definition, and append it to the given root element
0940:             */
0941:            public Element createDefaultXml(CmsObject cms,
0942:                    I_CmsXmlDocument document, Element root, Locale locale) {
0943:
0944:                Iterator i = m_typeSequence.iterator();
0945:                while (i.hasNext()) {
0946:                    I_CmsXmlSchemaType type = (I_CmsXmlSchemaType) i.next();
0947:                    for (int j = 0; j < type.getMinOccurs(); j++) {
0948:                        Element typeElement = type.generateXml(cms, document,
0949:                                root, locale);
0950:                        // need to check for default value again because of the appinfo "mappings" node
0951:                        I_CmsXmlContentValue value = type.createValue(document,
0952:                                typeElement, locale);
0953:                        String defaultValue = document.getContentDefinition()
0954:                                .getContentHandler().getDefault(cms, value,
0955:                                        locale);
0956:                        if (defaultValue != null) {
0957:                            // only if there is a default value available use it to overwrite the initial default
0958:                            value.setStringValue(cms, defaultValue);
0959:                        }
0960:                    }
0961:                }
0962:
0963:                return root;
0964:            }
0965:
0966:            /**
0967:             * Generates a valid XML document according to the XML schema of this content definition.<p>
0968:             * 
0969:             * @param cms the current users OpenCms context
0970:             * @param document the OpenCms XML document the XML is created for
0971:             * @param locale the locale to create the default element in the document with
0972:             * 
0973:             * @return a valid XML document according to the XML schema of this content definition
0974:             */
0975:            public Document createDocument(CmsObject cms,
0976:                    I_CmsXmlDocument document, Locale locale) {
0977:
0978:                Document doc = DocumentHelper.createDocument();
0979:
0980:                Element root = doc.addElement(getOuterName());
0981:
0982:                root.add(I_CmsXmlSchemaType.XSI_NAMESPACE);
0983:                root
0984:                        .addAttribute(
0985:                                I_CmsXmlSchemaType.XSI_NAMESPACE_ATTRIBUTE_NO_SCHEMA_LOCATION,
0986:                                getSchemaLocation());
0987:
0988:                createLocale(cms, document, root, locale);
0989:                return doc;
0990:            }
0991:
0992:            /**
0993:             * Generates a valid locale (language) element for the XML schema of this content definition.<p>
0994:             * 
0995:             * @param cms the current users OpenCms context
0996:             * @param document the OpenCms XML document the XML is created for
0997:             * @param root the root node of the document where to append the locale to
0998:             * @param locale the locale to create the default element in the document with
0999:             * 
1000:             * @return a valid XML element for the locale according to the XML schema of this content definition
1001:             */
1002:            public Element createLocale(CmsObject cms,
1003:                    I_CmsXmlDocument document, Element root, Locale locale) {
1004:
1005:                // add an element with a "locale" attribute to the given root node
1006:                Element element = root.addElement(getInnerName());
1007:                element.addAttribute(XSD_ATTRIBUTE_VALUE_LANGUAGE, locale
1008:                        .toString());
1009:
1010:                // now generate the default XML for the element
1011:                return createDefaultXml(cms, document, element, locale);
1012:            }
1013:
1014:            /**
1015:             * @see java.lang.Object#equals(java.lang.Object)
1016:             */
1017:            public boolean equals(Object obj) {
1018:
1019:                if (obj == this ) {
1020:                    return true;
1021:                }
1022:                if (!(obj instanceof  CmsXmlContentDefinition)) {
1023:                    return false;
1024:                }
1025:                CmsXmlContentDefinition other = (CmsXmlContentDefinition) obj;
1026:                if (!getInnerName().equals(other.getInnerName())) {
1027:                    return false;
1028:                }
1029:                if (!getOuterName().equals(other.getOuterName())) {
1030:                    return false;
1031:                }
1032:                return m_typeSequence.equals(other.m_typeSequence);
1033:            }
1034:
1035:            /**
1036:             * Freezes this content definition, making all internal data structures
1037:             * unmodifiable.<p>
1038:             * 
1039:             * This is required to prevent modification of a cached content definition.<p>
1040:             */
1041:            public void freeze() {
1042:
1043:                m_types = Collections.unmodifiableMap(m_types);
1044:                m_typeSequence = Collections.unmodifiableList(m_typeSequence);
1045:            }
1046:
1047:            /**
1048:             * Returns the selected XML content handler for this XML content definition.<p>
1049:             *
1050:             * If no specific XML content handler was provided in the "appinfo" node of the
1051:             * XML schema, the default XML content handler <code>{@link CmsDefaultXmlContentHandler}</code> is used.<p>
1052:             *
1053:             * @return the contentHandler
1054:             */
1055:            public I_CmsXmlContentHandler getContentHandler() {
1056:
1057:                return m_contentHandler;
1058:            }
1059:
1060:            /**
1061:             * Returns the set of nested (included) XML content definitions.<p>
1062:             * 
1063:             * @return the set of nested (included) XML content definitions
1064:             */
1065:            public Set getIncludes() {
1066:
1067:                return m_includes;
1068:            }
1069:
1070:            /**
1071:             * Returns the inner element name of this content definition.<p>
1072:             *
1073:             * @return the inner element name of this content definition
1074:             */
1075:            public String getInnerName() {
1076:
1077:                return m_innerName;
1078:            }
1079:
1080:            /**
1081:             * Returns the outer element name of this content definition.<p>
1082:             *
1083:             * @return the outer element name of this content definition
1084:             */
1085:            public String getOuterName() {
1086:
1087:                return m_outerName;
1088:            }
1089:
1090:            /**
1091:             * Generates an XML schema for the content definition.<p>
1092:             * 
1093:             * @return the generated XML schema
1094:             */
1095:            public Document getSchema() {
1096:
1097:                Document schema = DocumentHelper.createDocument();
1098:
1099:                Element root = schema.addElement(XSD_NODE_SCHEMA);
1100:                root.addAttribute(XSD_ATTRIBUTE_ELEMENT_FORM_DEFAULT,
1101:                        XSD_ATTRIBUTE_VALUE_QUALIFIED);
1102:
1103:                Element include = root.addElement(XSD_NODE_INCLUDE);
1104:                include.addAttribute(XSD_ATTRIBUTE_SCHEMA_LOCATION,
1105:                        XSD_INCLUDE_OPENCMS);
1106:
1107:                if (m_includes.size() > 0) {
1108:                    Iterator i = m_includes.iterator();
1109:                    while (i.hasNext()) {
1110:                        CmsXmlContentDefinition definition = (CmsXmlContentDefinition) i
1111:                                .next();
1112:                        root.addElement(XSD_NODE_INCLUDE).addAttribute(
1113:                                XSD_ATTRIBUTE_SCHEMA_LOCATION,
1114:                                definition.m_schemaLocation);
1115:                    }
1116:                }
1117:
1118:                String outerTypeName = createTypeName(getOuterName());
1119:                String innerTypeName = createTypeName(getInnerName());
1120:
1121:                Element content = root.addElement(XSD_NODE_ELEMENT);
1122:                content.addAttribute(XSD_ATTRIBUTE_NAME, getOuterName());
1123:                content.addAttribute(XSD_ATTRIBUTE_TYPE, outerTypeName);
1124:
1125:                Element list = root.addElement(XSD_NODE_COMPLEXTYPE);
1126:                list.addAttribute(XSD_ATTRIBUTE_NAME, outerTypeName);
1127:
1128:                Element listSequence = list.addElement(XSD_NODE_SEQUENCE);
1129:                Element listElement = listSequence.addElement(XSD_NODE_ELEMENT);
1130:                listElement.addAttribute(XSD_ATTRIBUTE_NAME, getInnerName());
1131:                listElement.addAttribute(XSD_ATTRIBUTE_TYPE, innerTypeName);
1132:                listElement.addAttribute(XSD_ATTRIBUTE_MIN_OCCURS,
1133:                        XSD_ATTRIBUTE_VALUE_ZERO);
1134:                listElement.addAttribute(XSD_ATTRIBUTE_MAX_OCCURS,
1135:                        XSD_ATTRIBUTE_VALUE_UNBOUNDED);
1136:
1137:                Element main = root.addElement(XSD_NODE_COMPLEXTYPE);
1138:                main.addAttribute(XSD_ATTRIBUTE_NAME, innerTypeName);
1139:
1140:                Element mainSequence = main.addElement(XSD_NODE_SEQUENCE);
1141:
1142:                Iterator i = m_typeSequence.iterator();
1143:                while (i.hasNext()) {
1144:                    I_CmsXmlSchemaType schemaType = (I_CmsXmlSchemaType) i
1145:                            .next();
1146:                    schemaType.appendXmlSchema(mainSequence);
1147:                }
1148:
1149:                Element language = main.addElement(XSD_NODE_ATTRIBUTE);
1150:                language.addAttribute(XSD_ATTRIBUTE_NAME,
1151:                        XSD_ATTRIBUTE_VALUE_LANGUAGE);
1152:                language.addAttribute(XSD_ATTRIBUTE_TYPE,
1153:                        CmsXmlLocaleValue.TYPE_NAME);
1154:                language.addAttribute(XSD_ATTRIBUTE_USE,
1155:                        XSD_ATTRIBUTE_VALUE_REQUIRED);
1156:
1157:                return schema;
1158:            }
1159:
1160:            /**
1161:             * Returns the location from which the XML schema was read (XML system id).<p>
1162:             *
1163:             * @return the location from which the XML schema was read (XML system id)
1164:             */
1165:            public String getSchemaLocation() {
1166:
1167:                return m_schemaLocation;
1168:            }
1169:
1170:            /**
1171:             * Returns the scheme type for the given element name, or <code>null</code> if no 
1172:             * node is defined with this name.<p>
1173:             * 
1174:             * @param elementPath the element path to look up the type for
1175:             * @return the type for the given element name, or <code>null</code> if no 
1176:             *      node is defined with this name
1177:             */
1178:            public I_CmsXmlSchemaType getSchemaType(String elementPath) {
1179:
1180:                String path = CmsXmlUtils.getFirstXpathElement(elementPath);
1181:
1182:                I_CmsXmlSchemaType type = (I_CmsXmlSchemaType) m_types
1183:                        .get(path);
1184:                if (type == null) {
1185:                    // no node with the given path defined in schema
1186:                    return null;
1187:                }
1188:
1189:                // check if recursion is required to get value from a nested schema
1190:                if (type.isSimpleType()
1191:                        || !CmsXmlUtils.isDeepXpath(elementPath)) {
1192:                    // no recursion required
1193:                    return type;
1194:                }
1195:
1196:                // recursion required since the path is an xpath and the type must be a nested content definition
1197:                CmsXmlNestedContentDefinition nestedDefinition = (CmsXmlNestedContentDefinition) type;
1198:                path = CmsXmlUtils.removeFirstXpathElement(elementPath);
1199:                return nestedDefinition.getNestedContentDefinition()
1200:                        .getSchemaType(path);
1201:            }
1202:
1203:            /**
1204:             * Returns the internal set of schema type names.<p>
1205:             * 
1206:             * @return the internal set of schema type names
1207:             */
1208:            public Set getSchemaTypes() {
1209:
1210:                return m_types.keySet();
1211:            }
1212:
1213:            /**
1214:             * Returns the main type name of this XML content definition.<p>
1215:             * 
1216:             * @return the main type name of this XML content definition
1217:             */
1218:            public String getTypeName() {
1219:
1220:                return m_typeName;
1221:            }
1222:
1223:            /**
1224:             * Returns the type sequence, contains instances of {@link I_CmsXmlSchemaType}.<p>
1225:             *
1226:             * @return the type sequence, contains instances of {@link I_CmsXmlSchemaType}
1227:             */
1228:            public List getTypeSequence() {
1229:
1230:                return m_typeSequence;
1231:            }
1232:
1233:            /**
1234:             * @see java.lang.Object#hashCode()
1235:             */
1236:            public int hashCode() {
1237:
1238:                return getInnerName().hashCode();
1239:            }
1240:
1241:            /**
1242:             * Sets the inner element name to use for the content definition.<p>
1243:             *
1244:             * @param innerName the inner element name to set
1245:             */
1246:            protected void setInnerName(String innerName) {
1247:
1248:                m_innerName = innerName;
1249:                if (m_innerName != null) {
1250:                    m_typeName = createTypeName(innerName);
1251:                }
1252:            }
1253:
1254:            /**
1255:             * Sets the outer element name to use for the content definition.<p>
1256:             *
1257:             * @param outerName the outer element name to set
1258:             */
1259:            protected void setOuterName(String outerName) {
1260:
1261:                m_outerName = outerName;
1262:            }
1263:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.