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


001:        /*
002:         * File   : $Source: /usr/local/cvs/opencms/src/org/opencms/xml/content/CmsXmlContent.java,v $
003:         * Date   : $Date: 2008-02-27 12:05:36 $
004:         * Version: $Revision: 1.42 $
005:         *
006:         * This library is part of OpenCms -
007:         * the Open Source Content Management System
008:         *
009:         * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
010:         *
011:         * This library is free software; you can redistribute it and/or
012:         * modify it under the terms of the GNU Lesser General Public
013:         * License as published by the Free Software Foundation; either
014:         * version 2.1 of the License, or (at your option) any later version.
015:         *
016:         * This library is distributed in the hope that it will be useful,
017:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
018:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019:         * Lesser General Public License for more details.
020:         *
021:         * For further information about Alkacon Software GmbH, please see the
022:         * company website: http://www.alkacon.com
023:         *
024:         * For further information about OpenCms, please see the
025:         * project website: http://www.opencms.org
026:         * 
027:         * You should have received a copy of the GNU Lesser General Public
028:         * License along with this library; if not, write to the Free Software
029:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
030:         */
031:
032:        package org.opencms.xml.content;
033:
034:        import org.opencms.file.CmsFile;
035:        import org.opencms.file.CmsObject;
036:        import org.opencms.file.CmsResource;
037:        import org.opencms.file.CmsResourceFilter;
038:        import org.opencms.i18n.CmsEncoder;
039:        import org.opencms.i18n.CmsLocaleManager;
040:        import org.opencms.main.CmsException;
041:        import org.opencms.main.CmsIllegalArgumentException;
042:        import org.opencms.main.CmsLog;
043:        import org.opencms.main.CmsRuntimeException;
044:        import org.opencms.staticexport.CmsLinkProcessor;
045:        import org.opencms.staticexport.CmsLinkTable;
046:        import org.opencms.util.CmsMacroResolver;
047:        import org.opencms.xml.A_CmsXmlDocument;
048:        import org.opencms.xml.CmsXmlContentDefinition;
049:        import org.opencms.xml.CmsXmlException;
050:        import org.opencms.xml.CmsXmlUtils;
051:        import org.opencms.xml.I_CmsXmlDocument;
052:        import org.opencms.xml.types.CmsXmlNestedContentDefinition;
053:        import org.opencms.xml.types.I_CmsXmlContentValue;
054:        import org.opencms.xml.types.I_CmsXmlSchemaType;
055:
056:        import java.io.IOException;
057:        import java.util.ArrayList;
058:        import java.util.Collections;
059:        import java.util.HashMap;
060:        import java.util.HashSet;
061:        import java.util.Iterator;
062:        import java.util.List;
063:        import java.util.Locale;
064:        import java.util.Set;
065:
066:        import org.apache.commons.logging.Log;
067:
068:        import org.dom4j.Document;
069:        import org.dom4j.Element;
070:        import org.dom4j.Node;
071:        import org.xml.sax.EntityResolver;
072:        import org.xml.sax.SAXException;
073:
074:        /**
075:         * Implementation of a XML content object,
076:         * used to access and manage structured content.<p>
077:         *
078:         * Use the {@link org.opencms.xml.content.CmsXmlContentFactory} to generate an
079:         * instance of this class.<p>
080:         *
081:         * @author Alexander Kandzior 
082:         * 
083:         * @version $Revision: 1.42 $ 
084:         * 
085:         * @since 6.0.0 
086:         */
087:        public class CmsXmlContent extends A_CmsXmlDocument implements 
088:                I_CmsXmlDocument {
089:
090:            /** The name of the XML content auto correction runtime attribute, this must always be a Boolean. */
091:            public static final String AUTO_CORRECTION_ATTRIBUTE = CmsXmlContent.class
092:                    .getName()
093:                    + ".autoCorrectionEnabled";
094:
095:            /** The property to set to enable xerces schema validation. */
096:            public static final String XERCES_SCHEMA_PROPERTY = "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
097:
098:            /** The log object for this class. */
099:            private static final Log LOG = CmsLog.getLog(CmsXmlContent.class);
100:
101:            /** Flag to control if auto correction is enabled when saving this XML content. */
102:            protected boolean m_autoCorrectionEnabled;
103:
104:            /** The XML content definition object (i.e. XML schema) used by this content. */
105:            protected CmsXmlContentDefinition m_contentDefinition;
106:
107:            /**
108:             * Hides the public constructor.<p>
109:             */
110:            protected CmsXmlContent() {
111:
112:                // noop
113:            }
114:
115:            /**
116:             * Creates a new XML content based on the provided XML document.<p>
117:             * 
118:             * The given encoding is used when marshalling the XML again later.<p>
119:             * 
120:             * @param cms the cms context, if <code>null</code> no link validation is performed 
121:             * @param document the document to create the xml content from
122:             * @param encoding the encoding of the xml content
123:             * @param resolver the XML entitiy resolver to use
124:             */
125:            protected CmsXmlContent(CmsObject cms, Document document,
126:                    String encoding, EntityResolver resolver) {
127:
128:                // must set document first to be able to get the content definition
129:                m_document = document;
130:                // for the next line to work the document must already be available
131:                m_contentDefinition = getContentDefinition(resolver);
132:                // initialize the XML content structure
133:                initDocument(cms, m_document, encoding, m_contentDefinition);
134:            }
135:
136:            /**
137:             * Create a new XML content based on the given default content,
138:             * that will have all language nodes of the default content and ensures the presence of the given locale.<p> 
139:             * 
140:             * The given encoding is used when marshalling the XML again later.<p>
141:             * 
142:             * @param cms the current users OpenCms content
143:             * @param locale the locale to generate the default content for
144:             * @param modelUri the absolute path to the XML content file acting as model
145:             * 
146:             * @throws CmsException in case the model file is not found or not valid
147:             */
148:            protected CmsXmlContent(CmsObject cms, Locale locale,
149:                    String modelUri) throws CmsException {
150:
151:                // init model from given modelUri
152:                CmsFile modelFile = cms.readFile(modelUri,
153:                        CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
154:                CmsXmlContent model = CmsXmlContentFactory.unmarshal(cms,
155:                        modelFile);
156:
157:                // initialize macro resolver to use on model file values
158:                CmsMacroResolver macroResolver = CmsMacroResolver.newInstance()
159:                        .setCmsObject(cms);
160:
161:                // content defition must be set here since it's used during document creation
162:                m_contentDefinition = model.getContentDefinition();
163:                // get the document from the default content
164:                Document document = (Document) model.m_document.clone();
165:                // initialize the XML content structure
166:                initDocument(cms, document, model.getEncoding(),
167:                        m_contentDefinition);
168:                // resolve eventual macros in the nodes
169:                visitAllValuesWith(new CmsXmlContentMacroVisitor(cms,
170:                        macroResolver));
171:                if (!hasLocale(locale)) {
172:                    // required locale not present, add it
173:                    try {
174:                        addLocale(cms, locale);
175:                    } catch (CmsXmlException e) {
176:                        // this can not happen since the locale does not exist
177:                    }
178:                }
179:            }
180:
181:            /**
182:             * Create a new XML content based on the given content definiton,
183:             * that will have one language node for the given locale all initialized with default values.<p> 
184:             * 
185:             * The given encoding is used when marshalling the XML again later.<p>
186:             * 
187:             * @param cms the current users OpenCms content
188:             * @param locale the locale to generate the default content for
189:             * @param encoding the encoding to use when marshalling the XML content later
190:             * @param contentDefinition the content definiton to create the content for
191:             */
192:            protected CmsXmlContent(CmsObject cms, Locale locale,
193:                    String encoding, CmsXmlContentDefinition contentDefinition) {
194:
195:                // content defition must be set here since it's used during document creation
196:                m_contentDefinition = contentDefinition;
197:                // create the XML document according to the content definition
198:                Document document = m_contentDefinition.createDocument(cms,
199:                        this , locale);
200:                // initialize the XML content structure
201:                initDocument(cms, document, encoding, m_contentDefinition);
202:            }
203:
204:            /**
205:             * @see org.opencms.xml.I_CmsXmlDocument#addLocale(org.opencms.file.CmsObject, java.util.Locale)
206:             */
207:            public void addLocale(CmsObject cms, Locale locale)
208:                    throws CmsXmlException {
209:
210:                if (hasLocale(locale)) {
211:                    throw new CmsXmlException(
212:                            org.opencms.xml.page.Messages
213:                                    .get()
214:                                    .container(
215:                                            org.opencms.xml.page.Messages.ERR_XML_PAGE_LOCALE_EXISTS_1,
216:                                            locale));
217:                }
218:                // add element node for Locale
219:                m_contentDefinition.createLocale(cms, this , m_document
220:                        .getRootElement(), locale);
221:                // re-initialize the bookmarks
222:                initDocument(cms, m_document, m_encoding, m_contentDefinition);
223:            }
224:
225:            /**
226:             * Adds a new XML content value for the given element name and locale at the given index position
227:             * to this XML content document.<p> 
228:             * 
229:             * @param cms the current users OpenCms context
230:             * @param path the path to the XML content value element
231:             * @param locale the locale where to add the new value 
232:             * @param index the index where to add the value (relative to all other values of this type)
233:             * 
234:             * @return the created XML content value 
235:             * 
236:             * @throws CmsIllegalArgumentException if the given path is invalid
237:             * @throws CmsRuntimeException if the element identified by the path already occured {@link I_CmsXmlSchemaType#getMaxOccurs()}  
238:             *         or the given <code>index</code> is invalid (too high).
239:             */
240:            public I_CmsXmlContentValue addValue(CmsObject cms, String path,
241:                    Locale locale, int index)
242:                    throws CmsIllegalArgumentException, CmsRuntimeException {
243:
244:                // get the schema type of the requested path           
245:                I_CmsXmlSchemaType type = m_contentDefinition
246:                        .getSchemaType(path);
247:                if (type == null) {
248:                    throw new CmsIllegalArgumentException(
249:                            Messages
250:                                    .get()
251:                                    .container(
252:                                            Messages.ERR_XMLCONTENT_UNKNOWN_ELEM_PATH_SCHEMA_1,
253:                                            path));
254:                }
255:
256:                Element parentElement;
257:                String elementName;
258:                CmsXmlContentDefinition contentDefinition;
259:                if (CmsXmlUtils.isDeepXpath(path)) {
260:                    // this is a nested content definition, so the parent element must be in the bookmarks
261:                    String parentPath = CmsXmlUtils
262:                            .removeLastXpathElement(path);
263:                    Object o = getBookmark(parentPath, locale);
264:                    if (o == null) {
265:                        throw new CmsIllegalArgumentException(
266:                                Messages
267:                                        .get()
268:                                        .container(
269:                                                Messages.ERR_XMLCONTENT_UNKNOWN_ELEM_PATH_1,
270:                                                path));
271:                    }
272:                    CmsXmlNestedContentDefinition parentValue = (CmsXmlNestedContentDefinition) o;
273:                    parentElement = parentValue.getElement();
274:                    elementName = CmsXmlUtils.getLastXpathElement(path);
275:                    contentDefinition = parentValue
276:                            .getNestedContentDefinition();
277:                } else {
278:                    // the parent element is the locale element
279:                    parentElement = getLocaleNode(locale);
280:                    elementName = CmsXmlUtils.removeXpathIndex(path);
281:                    contentDefinition = m_contentDefinition;
282:                }
283:
284:                // read the XML siblings from the parent node
285:                List siblings = parentElement.elements(elementName);
286:
287:                int insertIndex;
288:                if (siblings.size() > 0) {
289:
290:                    if (siblings.size() >= type.getMaxOccurs()) {
291:                        // must not allow adding an element if max occurs would be violated
292:                        throw new CmsRuntimeException(Messages.get().container(
293:                                Messages.ERR_XMLCONTENT_ELEM_MAXOCCURS_2,
294:                                elementName, new Integer(type.getMaxOccurs())));
295:                    }
296:
297:                    if (index > siblings.size()) {
298:                        // index position behind last element of the list
299:                        throw new CmsRuntimeException(Messages.get().container(
300:                                Messages.ERR_XMLCONTENT_ADD_ELEM_INVALID_IDX_3,
301:                                new Integer(index),
302:                                new Integer(siblings.size())));
303:                    }
304:
305:                    // check for offset required to append beyond last position
306:                    int offset = (index == siblings.size()) ? 1 : 0;
307:                    // get the element from the parent at the selected position
308:                    Element sibling = (Element) siblings.get(index - offset);
309:                    // check position of the node in the parent node content
310:                    insertIndex = sibling.getParent().content()
311:                            .indexOf(sibling)
312:                            + offset;
313:                } else {
314:
315:                    if (index > 0) {
316:                        // since the element does not occur, index must be 0
317:                        throw new CmsRuntimeException(Messages.get().container(
318:                                Messages.ERR_XMLCONTENT_ADD_ELEM_INVALID_IDX_2,
319:                                new Integer(index), elementName));
320:                    }
321:
322:                    // check where in the type sequence the type should appear
323:                    int typeIndex = contentDefinition.getTypeSequence()
324:                            .indexOf(type);
325:                    if (typeIndex == 0) {
326:                        // this is the first type, so we just add at the very first position
327:                        insertIndex = 0;
328:                    } else {
329:
330:                        // create a list of all element names that should occur before the selected type
331:                        List previousTypeNames = new ArrayList();
332:                        for (int i = 0; i < typeIndex; i++) {
333:                            I_CmsXmlSchemaType t = (I_CmsXmlSchemaType) contentDefinition
334:                                    .getTypeSequence().get(i);
335:                            previousTypeNames.add(t.getName());
336:                        }
337:
338:                        // iterate all elements of the parent node
339:                        Iterator i = parentElement.content().iterator();
340:                        int pos = 0;
341:                        while (i.hasNext()) {
342:                            Node node = (Node) i.next();
343:                            if (node instanceof  Element) {
344:                                if (!previousTypeNames.contains(node.getName())) {
345:                                    // the element name is NOT in the list of names that occure before the selected type, 
346:                                    // so it must be an element that occurs AFTER the type
347:                                    break;
348:                                }
349:                            }
350:                            pos++;
351:                        }
352:                        insertIndex = pos;
353:                    }
354:                }
355:
356:                // append the new element at the calculated position
357:                I_CmsXmlContentValue newValue = addValue(cms, parentElement,
358:                        type, locale, insertIndex);
359:
360:                // re-initialize this XML content 
361:                initDocument(m_document, m_encoding, m_contentDefinition);
362:
363:                // return the value instance that was stored in the bookmarks 
364:                // just returning "newValue" isn't enough since this instance is NOT stored in the bookmarks
365:                return (I_CmsXmlContentValue) getBookmark(getBookmarkName(
366:                        newValue.getPath(), locale));
367:            }
368:
369:            /**
370:             * @see org.opencms.xml.I_CmsXmlDocument#getContentDefinition()
371:             */
372:            public CmsXmlContentDefinition getContentDefinition() {
373:
374:                return m_contentDefinition;
375:            }
376:
377:            /**
378:             * @see org.opencms.xml.A_CmsXmlDocument#getLinkProcessor(org.opencms.file.CmsObject, org.opencms.staticexport.CmsLinkTable)
379:             */
380:            public CmsLinkProcessor getLinkProcessor(CmsObject cms,
381:                    CmsLinkTable linkTable) {
382:
383:                // initialize link processor
384:                String relativeRoot = null;
385:                if (m_file != null) {
386:                    relativeRoot = CmsResource.getParentFolder(cms
387:                            .getSitePath(m_file));
388:                }
389:                return new CmsLinkProcessor(cms, linkTable, getEncoding(),
390:                        relativeRoot);
391:            }
392:
393:            /**
394:             * Returns the value sequence for the selected element name in this XML content.<p>
395:             * 
396:             * If the given element name is not valid according to the schema of this XML content,
397:             * <code>null</code> is returned.<p>
398:             * 
399:             * @param name the element name (XML node name) to the the value sequence for
400:             * @param locale the locale to get the value sequence for
401:             * 
402:             * @return the value sequence for the selected element name in this XML content
403:             */
404:            public CmsXmlContentValueSequence getValueSequence(String name,
405:                    Locale locale) {
406:
407:                I_CmsXmlSchemaType type = m_contentDefinition
408:                        .getSchemaType(name);
409:                if (type == null) {
410:                    return null;
411:                }
412:                return new CmsXmlContentValueSequence(name, type, locale, this );
413:            }
414:
415:            /**
416:             * @see org.opencms.xml.A_CmsXmlDocument#isAutoCorrectionEnabled()
417:             */
418:            public boolean isAutoCorrectionEnabled() {
419:
420:                return m_autoCorrectionEnabled;
421:            }
422:
423:            /**
424:             * Removes an existing XML content value of the given element name and locale at the given index position
425:             * from this XML content document.<p> 
426:             * 
427:             * @param name the name of the XML content value element
428:             * @param locale the locale where to remove the value 
429:             * @param index the index where to remove the value (relative to all other values of this type)
430:             */
431:            public void removeValue(String name, Locale locale, int index) {
432:
433:                // first get the value from the selected locale and index
434:                I_CmsXmlContentValue value = getValue(name, locale, index);
435:
436:                // check for the min / max occurs constrains
437:                List values = getValues(name, locale);
438:                if (values.size() <= value.getMinOccurs()) {
439:                    // must not allow removing an element if min occurs would be violated
440:                    throw new CmsRuntimeException(Messages.get().container(
441:                            Messages.ERR_XMLCONTENT_ELEM_MINOCCURS_2, name,
442:                            new Integer(value.getMinOccurs())));
443:                }
444:
445:                // detach the value node from the XML document
446:                value.getElement().detach();
447:
448:                // re-initialize this XML content 
449:                initDocument(m_document, m_encoding, m_contentDefinition);
450:            }
451:
452:            /**
453:             * Resolves the mappings for all values of this XML content.<p>
454:             * 
455:             * @param cms the current users OpenCms context
456:             */
457:            public void resolveMappings(CmsObject cms) {
458:
459:                // iterate through all initialized value nodes in this XML content
460:                CmsXmlContentMappingVisitor visitor = new CmsXmlContentMappingVisitor(
461:                        cms, this );
462:                visitAllValuesWith(visitor);
463:            }
464:
465:            /**
466:             * Sets the flag to control if auto correction is enabled when saving this XML content.<p>
467:             *
468:             * @param value the flag to control if auto correction is enabled when saving this XML content
469:             */
470:            public void setAutoCorrectionEnabled(boolean value) {
471:
472:                m_autoCorrectionEnabled = value;
473:            }
474:
475:            /**
476:             * @see org.opencms.xml.I_CmsXmlDocument#validate(org.opencms.file.CmsObject)
477:             */
478:            public CmsXmlContentErrorHandler validate(CmsObject cms) {
479:
480:                // iterate through all initialized value nodes in this XML content
481:                CmsXmlContentValidationVisitor visitor = new CmsXmlContentValidationVisitor(
482:                        cms);
483:                visitAllValuesWith(visitor);
484:
485:                return visitor.getErrorHandler();
486:            }
487:
488:            /**
489:             * Visits all values of this XML content with the given value visitor.<p>
490:             * 
491:             * Please note that the order in which the values are visited may NOT be the
492:             * order they apper in the XML document. It is ensured that the the parent 
493:             * of a nested value is visited before the element it contains.<p>
494:             * 
495:             * @param visitor the value visitor implementation to visit the values with
496:             */
497:            public void visitAllValuesWith(I_CmsXmlContentValueVisitor visitor) {
498:
499:                List bookmarks = new ArrayList(getBookmarks());
500:                Collections.sort(bookmarks);
501:
502:                for (int i = 0; i < bookmarks.size(); i++) {
503:
504:                    String key = (String) bookmarks.get(i);
505:                    I_CmsXmlContentValue value = (I_CmsXmlContentValue) getBookmark(key);
506:                    visitor.visit(value);
507:                }
508:            }
509:
510:            /**
511:             * @see org.opencms.xml.A_CmsXmlDocument#getBookmark(java.lang.String)
512:             */
513:            protected Object getBookmark(String bookmark) {
514:
515:                // allows package classes to directly access the bookmark information of the XML content 
516:                return super .getBookmark(bookmark);
517:            }
518:
519:            /**
520:             * @see org.opencms.xml.A_CmsXmlDocument#getBookmarks()
521:             */
522:            protected Set getBookmarks() {
523:
524:                // allows package classes to directly access the bookmark information of the XML content 
525:                return super .getBookmarks();
526:            }
527:
528:            /**
529:             * Returns the XML root element node for the given locale.<p>
530:             * 
531:             * @param locale the locale to get the root element for
532:             * 
533:             * @return the XML root element node for the given locale
534:             * 
535:             * @throws CmsRuntimeException if no language element is found in the document
536:             */
537:            protected Element getLocaleNode(Locale locale)
538:                    throws CmsRuntimeException {
539:
540:                String localeStr = locale.toString();
541:                Iterator i = m_document.getRootElement().elements().iterator();
542:                while (i.hasNext()) {
543:                    Element element = (Element) i.next();
544:                    if (localeStr
545:                            .equals(element
546:                                    .attributeValue(CmsXmlContentDefinition.XSD_ATTRIBUTE_VALUE_LANGUAGE))) {
547:                        // language element found, return it
548:                        return element;
549:                    }
550:                }
551:
552:                // language element was not found
553:                throw new CmsRuntimeException(Messages.get().container(
554:                        Messages.ERR_XMLCONTENT_MISSING_LOCALE_1, locale));
555:            }
556:
557:            /**
558:             * Initializes an XML document based on the provided document, encoding and content definition.<p>
559:             * 
560:             * Checks the links and removes invalid ones in the initialized document.<p>
561:             * 
562:             * @param cms the current users OpenCms content
563:             * @param document the base XML document to use for initializing
564:             * @param encoding the encoding to use when marshalling the document later
565:             * @param definition the content definition to use
566:             */
567:            protected void initDocument(CmsObject cms, Document document,
568:                    String encoding, CmsXmlContentDefinition definition) {
569:
570:                initDocument(document, encoding, definition);
571:                // check invalid links
572:                if (cms != null) {
573:                    // this will remove all invalid links
574:                    getContentDefinition().getContentHandler()
575:                            .invalidateBrokenLinks(cms, this );
576:                }
577:            }
578:
579:            /**
580:             * @see org.opencms.xml.A_CmsXmlDocument#initDocument(org.dom4j.Document, java.lang.String, org.opencms.xml.CmsXmlContentDefinition)
581:             */
582:            protected void initDocument(Document document, String encoding,
583:                    CmsXmlContentDefinition definition) {
584:
585:                m_document = document;
586:                m_contentDefinition = definition;
587:                m_encoding = CmsEncoder.lookupEncoding(encoding, encoding);
588:                m_elementLocales = new HashMap();
589:                m_elementNames = new HashMap();
590:                m_locales = new HashSet();
591:                clearBookmarks();
592:
593:                // initialize the bookmarks
594:                for (Iterator i = m_document.getRootElement().elementIterator(); i
595:                        .hasNext();) {
596:                    Element node = (Element) i.next();
597:                    try {
598:                        Locale locale = CmsLocaleManager
599:                                .getLocale(node
600:                                        .attribute(
601:                                                CmsXmlContentDefinition.XSD_ATTRIBUTE_VALUE_LANGUAGE)
602:                                        .getValue());
603:
604:                        addLocale(locale);
605:                        processSchemaNode(node, null, locale, definition);
606:                    } catch (NullPointerException e) {
607:                        LOG.error(Messages.get().getBundle().key(
608:                                Messages.LOG_XMLCONTENT_INIT_BOOKMARKS_0), e);
609:                    }
610:                }
611:
612:            }
613:
614:            /**
615:             * Sets the file this XML content is written to.<p> 
616:             * 
617:             * @param file the file this XML content content is written to
618:             */
619:            protected void setFile(CmsFile file) {
620:
621:                m_file = file;
622:            }
623:
624:            /**
625:             * Adds a new XML schema type with the default value to the given parent node.<p>
626:             * 
627:             * @param cms the cms context
628:             * @param parent the XML parent element to add the new value to
629:             * @param type the type of the value to add
630:             * @param locale the locale to add the new value for
631:             * @param insertIndex the index in the XML document where to add the XML node
632:             * 
633:             * @return the created XML content value
634:             */
635:            private I_CmsXmlContentValue addValue(CmsObject cms,
636:                    Element parent, I_CmsXmlSchemaType type, Locale locale,
637:                    int insertIndex) {
638:
639:                // first generate the XML element for the new value
640:                Element element = type.generateXml(cms, this , parent, locale);
641:                // detatch the XML element from the appended position in order to insert it at the required position
642:                element.detach();
643:                // add the XML element at the required position in the parent XML node 
644:                parent.content().add(insertIndex, element);
645:                // create the type and return it
646:                I_CmsXmlContentValue value = type.createValue(this , element,
647:                        locale);
648:                // generate the default value again - required for nested mappings because only now the full path is available  
649:                String defaultValue = m_contentDefinition.getContentHandler()
650:                        .getDefault(cms, value, locale);
651:                if (defaultValue != null) {
652:                    // only if there is a default value available use it to overwrite the initial default
653:                    value.setStringValue(cms, defaultValue);
654:                }
655:                // finally return the value        
656:                return value;
657:            }
658:
659:            /**
660:             * Returns the content definition object for this xml content object.<p>
661:             * 
662:             * @param resolver the XML entity resolver to use, required for VFS access
663:             * 
664:             * @return the content definition object for this xml content object
665:             * 
666:             * @throws CmsRuntimeException if the schema location attribute (<code>systemId</code>)cannot be found, 
667:             *         parsing of the schema fails, an underlying IOException occurs or unmarshalling fails
668:             *           
669:             */
670:            private CmsXmlContentDefinition getContentDefinition(
671:                    EntityResolver resolver) throws CmsRuntimeException {
672:
673:                String schemaLocation = m_document
674:                        .getRootElement()
675:                        .attributeValue(
676:                                I_CmsXmlSchemaType.XSI_NAMESPACE_ATTRIBUTE_NO_SCHEMA_LOCATION);
677:                // Note regarding exception handling:
678:                // Since this object already is a valid XML content object,
679:                // it must have a valid schema, otherwise it would not exist.
680:                // Therefore the exceptions should never be really thrown.
681:                if (schemaLocation == null) {
682:                    throw new CmsRuntimeException(Messages.get().container(
683:                            Messages.ERR_XMLCONTENT_MISSING_SCHEMA_0));
684:                }
685:
686:                try {
687:                    return CmsXmlContentDefinition.unmarshal(schemaLocation,
688:                            resolver);
689:                } catch (SAXException e) {
690:                    throw new CmsRuntimeException(Messages.get().container(
691:                            Messages.ERR_XML_SCHEMA_PARSE_0), e);
692:                } catch (IOException e) {
693:                    throw new CmsRuntimeException(Messages.get().container(
694:                            Messages.ERR_XML_SCHEMA_IO_0), e);
695:                } catch (CmsXmlException e) {
696:                    throw new CmsRuntimeException(Messages.get().container(
697:                            Messages.ERR_XMLCONTENT_UNMARSHAL_0), e);
698:                }
699:            }
700:
701:            /**
702:             * Processes a document node and extracts the values of the node according to the provided XML
703:             * content definition.<p> 
704:             * 
705:             * @param root the root node element to process
706:             * @param rootPath the Xpath of the root node in the document
707:             * @param locale the locale 
708:             * @param definition the XML content definition to use for processing the values
709:             */
710:            private void processSchemaNode(Element root, String rootPath,
711:                    Locale locale, CmsXmlContentDefinition definition) {
712:
713:                int count = 1;
714:                String previousName = null;
715:
716:                // first remove all non-element node (i.e. white space text nodes)
717:                List content = root.content();
718:                for (int i = content.size() - 1; i >= 0; i--) {
719:                    Node node = (Node) content.get(i);
720:                    if (!(node instanceof  Element)) {
721:                        // this node is not an element, so it must be a white space text node, remove it
722:                        content.remove(i);
723:                    }
724:                }
725:
726:                // iterate all elements again
727:                for (Iterator i = root.content().iterator(); i.hasNext();) {
728:
729:                    // node must be an element since all non-elements were removed
730:                    Element element = (Element) i.next();
731:
732:                    // check if this is a new node, if so reset the node counter
733:                    String name = element.getName();
734:                    if ((previousName == null) || !previousName.equals(name)) {
735:                        previousName = name;
736:                        count = 1;
737:                    }
738:
739:                    // build the Xpath expression for the current node
740:                    String path;
741:                    if (rootPath != null) {
742:                        StringBuffer b = new StringBuffer(rootPath.length()
743:                                + name.length() + 6);
744:                        b.append(rootPath);
745:                        b.append('/');
746:                        b.append(CmsXmlUtils.createXpathElement(name, count));
747:                        path = b.toString();
748:                    } else {
749:                        path = CmsXmlUtils.createXpathElement(name, count);
750:                    }
751:
752:                    // create a XML content value element
753:                    I_CmsXmlSchemaType schemaType = definition
754:                            .getSchemaType(name);
755:
756:                    if (schemaType != null) {
757:                        // directly add simple type to schema
758:                        I_CmsXmlContentValue value = schemaType.createValue(
759:                                this , element, locale);
760:                        addBookmark(path, locale, true, value);
761:
762:                        if (!schemaType.isSimpleType()) {
763:                            // recurse for nested schema
764:                            CmsXmlNestedContentDefinition nestedSchema = (CmsXmlNestedContentDefinition) schemaType;
765:                            processSchemaNode(element, path, locale,
766:                                    nestedSchema.getNestedContentDefinition());
767:                        }
768:                    } else {
769:                        // unknown XML node name according to schema
770:                        if (LOG.isWarnEnabled()) {
771:                            LOG.warn(Messages.get().getBundle().key(
772:                                    Messages.LOG_XMLCONTENT_INVALID_ELEM_2,
773:                                    name, definition.getSchemaLocation()));
774:                        }
775:                    }
776:
777:                    // increase the node counter
778:                    count++;
779:                }
780:            }
781:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.