KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > xml > page > CmsXmlPage


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/xml/page/CmsXmlPage.java,v $
3  * Date : $Date: 2006/07/20 13:51:41 $
4  * Version: $Revision: 1.34 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.xml.page;
33
34 import org.opencms.configuration.CmsConfigurationManager;
35 import org.opencms.file.CmsFile;
36 import org.opencms.file.CmsObject;
37 import org.opencms.file.CmsResource;
38 import org.opencms.i18n.CmsEncoder;
39 import org.opencms.i18n.CmsLocaleManager;
40 import org.opencms.main.CmsIllegalArgumentException;
41 import org.opencms.main.CmsLog;
42 import org.opencms.main.CmsRuntimeException;
43 import org.opencms.staticexport.CmsLinkProcessor;
44 import org.opencms.staticexport.CmsLinkTable;
45 import org.opencms.xml.A_CmsXmlDocument;
46 import org.opencms.xml.CmsXmlContentDefinition;
47 import org.opencms.xml.CmsXmlEntityResolver;
48 import org.opencms.xml.CmsXmlException;
49 import org.opencms.xml.CmsXmlUtils;
50 import org.opencms.xml.content.CmsXmlContentErrorHandler;
51 import org.opencms.xml.types.CmsXmlHtmlValue;
52 import org.opencms.xml.types.I_CmsXmlContentValue;
53 import org.opencms.xml.types.I_CmsXmlSchemaType;
54
55 import java.util.ArrayList JavaDoc;
56 import java.util.Collections JavaDoc;
57 import java.util.HashMap JavaDoc;
58 import java.util.HashSet JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.List JavaDoc;
61 import java.util.Locale JavaDoc;
62 import java.util.Map JavaDoc;
63 import java.util.Set JavaDoc;
64
65 import org.apache.commons.logging.Log;
66
67 import org.dom4j.Attribute;
68 import org.dom4j.Document;
69 import org.dom4j.DocumentHelper;
70 import org.dom4j.Element;
71 import org.xml.sax.InputSource JavaDoc;
72
73 /**
74  * Implementation of a page object used to access and manage xml data.<p>
75  *
76  * This implementation consists of several named elements optionally available for
77  * various languages. The data of each element is accessible via its name and language.
78  *
79  * The content of each element is stored as CDATA, links within the
80  * content are processed and are seperately accessible as entries of a CmsLinkTable.
81  *
82  * @author Carsten Weinholz
83  * @author Alexander Kandzior
84  *
85  * @version $Revision: 1.34 $
86  *
87  * @since 6.0.0
88  */

89 public class CmsXmlPage extends A_CmsXmlDocument {
90
91     /** Name of the name attribute of the elements node. */
92     public static final String JavaDoc ATTRIBUTE_ENABLED = "enabled";
93
94     /** Name of the internal attribute of the link node. */
95     public static final String JavaDoc ATTRIBUTE_INTERNAL = "internal";
96
97     /** Name of the language attribute of the elements node. */
98     public static final String JavaDoc ATTRIBUTE_LANGUAGE = "language";
99
100     /** Name of the name attribute of the elements node. */
101     public static final String JavaDoc ATTRIBUTE_NAME = "name";
102
103     /** Name of the type attribute of the elements node. */
104     public static final String JavaDoc ATTRIBUTE_TYPE = "type";
105
106     /** Name of the anchor node. */
107     public static final String JavaDoc NODE_ANCHOR = "anchor";
108
109     /** Name of the element node. */
110     public static final String JavaDoc NODE_CONTENT = "content";
111
112     /** Name of the elements node. */
113     public static final String JavaDoc NODE_ELEMENTS = "elements";
114
115     /** Name of the link node. */
116     public static final String JavaDoc NODE_LINK = "link";
117
118     /** Name of the links node. */
119     public static final String JavaDoc NODE_LINKS = "links";
120
121     /** Name of the page node. */
122     public static final String JavaDoc NODE_PAGE = "page";
123
124     /** Name of the page node. */
125     public static final String JavaDoc NODE_PAGES = "pages";
126
127     /** Name of the query node. */
128     public static final String JavaDoc NODE_QUERY = "query";
129
130     /** Name of the target node. */
131     public static final String JavaDoc NODE_TARGET = "target";
132
133     /** Property to check if relative links are allowed. */
134     public static final String JavaDoc PROPERTY_ALLOW_RELATIVE = "allowRelativeLinks";
135
136     /** The DTD address of the OpenCms xmlpage. */
137     public static final String JavaDoc XMLPAGE_XSD_SYSTEM_ID = CmsConfigurationManager.DEFAULT_DTD_PREFIX + "xmlpage.xsd";
138
139     /** The log object for this class. */
140     private static final Log LOG = CmsLog.getLog(CmsXmlPage.class);
141
142     /** The XML page content definition is static. */
143     private static CmsXmlContentDefinition m_xmlPageContentDefinition;
144
145     /** Name of the element node. */
146     private static final String JavaDoc NODE_ELEMENT = "element";
147
148     /** Indicates if relative Links are allowed. */
149     private boolean m_allowRelativeLinks;
150
151     /**
152      * Creates a new CmsXmlPage based on the provided document and encoding.<p>
153      *
154      * The encoding is used for marshalling the XML document later.<p>
155      *
156      * @param document the document to create the CmsXmlPage from
157      * @param encoding the encoding of the xml page
158      */

159     public CmsXmlPage(Document document, String JavaDoc encoding) {
160
161         initDocument(document, encoding, getContentDefinition());
162     }
163
164     /**
165      * Creates an empty XML page in the provided locale using
166      * the provided encoding.<p>
167      *
168      * The page is initialized according to the minimal neccessary xml structure.
169      * The encoding is used for marshalling the XML document later.<p>
170      *
171      * @param locale the initial locale of the XML page
172      * @param encoding the encoding of the XML page
173      */

174     public CmsXmlPage(Locale JavaDoc locale, String JavaDoc encoding) {
175
176         initDocument(CmsXmlPageFactory.createDocument(locale), encoding, getContentDefinition());
177     }
178
179     /**
180      * @see org.opencms.xml.I_CmsXmlDocument#addLocale(org.opencms.file.CmsObject, java.util.Locale)
181      */

182     public void addLocale(CmsObject cms, Locale JavaDoc locale) throws CmsXmlException {
183
184         if (hasLocale(locale)) {
185             throw new CmsXmlException(Messages.get().container(Messages.ERR_XML_PAGE_LOCALE_EXISTS_1, locale));
186         }
187         // add element node for Locale
188
getContentDefinition().createLocale(cms, this, m_document.getRootElement(), locale);
189         // re-initialize the bookmarks
190
initDocument(m_document, m_encoding, getContentDefinition());
191     }
192
193     /**
194      * Adds a new, empty value with the given name and locale
195      * to this XML document.<p>
196      *
197      * @param name the name of the value
198      * @param locale the locale of the value
199      *
200      * @throws CmsIllegalArgumentException if the name contains an index ("[&lt;number&gt;]") or the value for the
201      * given locale already exists in the xmlpage.
202      *
203      */

204     public void addValue(String JavaDoc name, Locale JavaDoc locale) throws CmsIllegalArgumentException {
205
206         if (name.indexOf('[') >= 0) {
207             throw new CmsIllegalArgumentException(
208                 Messages.get().container(Messages.ERR_XML_PAGE_CONTAINS_INDEX_1, name));
209         }
210
211         if (hasValue(name, locale)) {
212             throw new CmsIllegalArgumentException(Messages.get().container(
213                 Messages.ERR_XML_PAGE_LANG_ELEM_EXISTS_2,
214                 name,
215                 locale));
216         }
217
218         Element pages = m_document.getRootElement();
219         String JavaDoc localeStr = locale.toString();
220         Element page = null;
221
222         // search if a page for the selected language is already available
223
for (Iterator JavaDoc i = pages.elementIterator(NODE_PAGE); i.hasNext();) {
224             Element nextPage = (Element)i.next();
225             String JavaDoc language = nextPage.attributeValue(ATTRIBUTE_LANGUAGE);
226             if (localeStr.equals(language)) {
227                 // a page for the selected language was found
228
page = nextPage;
229                 break;
230             }
231         }
232
233         // create the new element
234
Element element;
235         if (page != null) {
236             // page for selected language already available
237
element = page.addElement(NODE_ELEMENT).addAttribute(ATTRIBUTE_NAME, name);
238         } else {
239             // no page for the selected language was found
240
element = pages.addElement(NODE_PAGE).addAttribute(ATTRIBUTE_LANGUAGE, localeStr);
241             element = element.addElement(NODE_ELEMENT).addAttribute(ATTRIBUTE_NAME, name);
242         }
243
244         // add empty nodes for link table and content to the element
245
element.addElement(NODE_LINKS);
246         element.addElement(NODE_CONTENT);
247
248         CmsXmlHtmlValue value = new CmsXmlHtmlValue(this, element, locale);
249
250         // bookmark the element
251
addBookmark(CmsXmlUtils.createXpathElement(name, 1), locale, true, value);
252     }
253
254     /**
255      * Returns if relative links are accepted (and left unprocessed).<p>
256      *
257      * @return true if relative links are allowed
258      */

259     public boolean getAllowRelativeLinks() {
260
261         return m_allowRelativeLinks;
262     }
263
264     /**
265      * @see org.opencms.xml.I_CmsXmlDocument#getContentDefinition()
266      */

267     public CmsXmlContentDefinition getContentDefinition() throws CmsRuntimeException {
268
269         if (m_xmlPageContentDefinition == null) {
270             // since XML page schema is cached anyway we don't need an CmsObject instance
271
CmsXmlEntityResolver resolver = new CmsXmlEntityResolver(null);
272             InputSource JavaDoc source;
273             try {
274                 source = resolver.resolveEntity(null, XMLPAGE_XSD_SYSTEM_ID);
275                 // store content definition in static variable
276
m_xmlPageContentDefinition = CmsXmlContentDefinition.unmarshal(source, XMLPAGE_XSD_SYSTEM_ID, resolver);
277             } catch (CmsXmlException e) {
278                 throw new CmsRuntimeException(Messages.get().container(Messages.ERR_XML_PAGE_UNMARSHAL_CONTENDDEF_0), e);
279             }
280         }
281         return m_xmlPageContentDefinition;
282     }
283
284     /**
285      * @see org.opencms.xml.A_CmsXmlDocument#getLinkProcessor(org.opencms.file.CmsObject, org.opencms.staticexport.CmsLinkTable)
286      */

287     public CmsLinkProcessor getLinkProcessor(CmsObject cms, CmsLinkTable linkTable) {
288
289         // initialize link processor
290
String JavaDoc relativeRoot = null;
291         if ((!m_allowRelativeLinks) && (m_file != null)) {
292             relativeRoot = CmsResource.getParentFolder(cms.getSitePath(m_file));
293         }
294         return new CmsLinkProcessor(cms, linkTable, getEncoding(), relativeRoot);
295     }
296
297     /**
298      * Returns the link table of an element.<p>
299      *
300      * @param name name of the element
301      * @param locale locale of the element
302      * @return the link table
303      */

304     public CmsLinkTable getLinkTable(String JavaDoc name, Locale JavaDoc locale) {
305
306         CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale);
307         if (value != null) {
308             return value.getLinkTable();
309         }
310         return new CmsLinkTable();
311     }
312
313     /**
314      * @see org.opencms.xml.A_CmsXmlDocument#getNames(java.util.Locale)
315      */

316     public List JavaDoc getNames(Locale JavaDoc locale) {
317
318         Object JavaDoc o = m_elementNames.get(locale);
319         if (o != null) {
320             List JavaDoc result = new ArrayList JavaDoc(8);
321             Iterator JavaDoc i = ((Set JavaDoc)o).iterator();
322             while (i.hasNext()) {
323                 String JavaDoc path = (String JavaDoc)i.next();
324                 result.add(CmsXmlUtils.removeXpathIndex(path));
325             }
326             return result;
327         }
328         return Collections.EMPTY_LIST;
329     }
330
331     /**
332      * Checks if the element of a page object is enabled.<p>
333      *
334      * @param name the name of the element
335      * @param locale the locale of the element
336      * @return true if the element exists and is not disabled
337      */

338     public boolean isEnabled(String JavaDoc name, Locale JavaDoc locale) {
339
340         CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale);
341
342         if (value != null) {
343             Element element = value.getElement();
344             Attribute enabled = element.attribute(ATTRIBUTE_ENABLED);
345             return (enabled == null || Boolean.valueOf(enabled.getValue()).booleanValue());
346         }
347
348         return false;
349     }
350
351     /**
352      * Removes an existing value with the given name and locale
353      * from this XML document.<p>
354      *
355      * @param name the name of the value
356      * @param locale the locale of the value
357      */

358     public void removeValue(String JavaDoc name, Locale JavaDoc locale) {
359
360         I_CmsXmlContentValue value = removeBookmark(CmsXmlUtils.createXpath(name, 1), locale);
361         if (value != null) {
362             Element element = value.getElement();
363             element.detach();
364         }
365     }
366
367     /**
368      * Renames the page-element value from the old to the new one.<p>
369      *
370      * @param oldValue the old value
371      * @param newValue the new value
372      * @param locale the locale
373      *
374      * @throws CmsIllegalArgumentException if the name contains an index ("[&lt;number&gt;]"), the new value for the
375      * given locale already exists in the xmlpage or the the old value does not exist for the locale in the xmlpage.
376      *
377      */

378     public void renameValue(String JavaDoc oldValue, String JavaDoc newValue, Locale JavaDoc locale) throws CmsIllegalArgumentException {
379
380         CmsXmlHtmlValue oldXmlHtmlValue = (CmsXmlHtmlValue)getValue(oldValue, locale);
381         if (oldXmlHtmlValue == null) {
382             throw new CmsIllegalArgumentException(Messages.get().container(
383                 Messages.ERR_XML_PAGE_NO_ELEM_FOR_LANG_2,
384                 oldValue,
385                 locale));
386         }
387
388         if (hasValue(newValue, locale)) {
389             throw new CmsIllegalArgumentException(Messages.get().container(
390                 Messages.ERR_XML_PAGE_LANG_ELEM_EXISTS_2,
391                 newValue,
392                 locale));
393         }
394         if (newValue.indexOf('[') >= 0) {
395             throw new CmsIllegalArgumentException(Messages.get().container(
396                 Messages.ERR_XML_PAGE_CONTAINS_INDEX_1,
397                 newValue));
398         }
399
400         // get the element
401
Element element = oldXmlHtmlValue.getElement();
402
403         // update value of the element attribute 'NAME'
404
element.addAttribute(ATTRIBUTE_NAME, newValue);
405
406         // re-initialize the document to update the bookmarks
407
initDocument(m_document, m_encoding, getContentDefinition());
408     }
409
410     /**
411      * Sets the enabled flag of an already existing element.<p>
412      *
413      * Note: if isEnabled is set to true, the attribute is removed
414      * since true is the default
415      *
416      * @param name name name of the element
417      * @param locale locale of the element
418      * @param isEnabled enabled flag for the element
419      */

420     public void setEnabled(String JavaDoc name, Locale JavaDoc locale, boolean isEnabled) {
421
422         CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale);
423         Element element = value.getElement();
424         Attribute enabled = element.attribute(ATTRIBUTE_ENABLED);
425
426         if (enabled == null) {
427             if (!isEnabled) {
428                 element.addAttribute(ATTRIBUTE_ENABLED, Boolean.toString(isEnabled));
429             }
430         } else if (isEnabled) {
431             element.remove(enabled);
432         } else {
433             enabled.setValue(Boolean.toString(isEnabled));
434         }
435     }
436
437     /**
438      * Sets the data of an already existing value.<p>
439      *
440      * The data will be enclosed as CDATA within the xml page structure.
441      * When setting the element data, the content of this element will be
442      * processed automatically.<p>
443      *
444      * @param cms the cms object
445      * @param name name of the element
446      * @param locale locale of the element
447      * @param content character data (CDATA) of the element
448      *
449      * @throws CmsXmlException if something goes wrong
450      */

451     public void setStringValue(CmsObject cms, String JavaDoc name, Locale JavaDoc locale, String JavaDoc content) throws CmsXmlException {
452
453         CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale);
454
455         if (value != null) {
456             // set the values
457
value.setStringValue(cms, content);
458         } else {
459             throw new CmsXmlException(Messages.get().container(
460                 Messages.ERR_XML_PAGE_INVALID_ELEM_SELECT_2,
461                 locale,
462                 name));
463         }
464     }
465
466     /**
467      * @see org.opencms.xml.I_CmsXmlDocument#validate(org.opencms.file.CmsObject)
468      */

469     public CmsXmlContentErrorHandler validate(CmsObject cms) {
470
471         // XML pages currently do not support validation
472
return new CmsXmlContentErrorHandler();
473     }
474
475     /**
476      * @see org.opencms.xml.A_CmsXmlDocument#initDocument(org.dom4j.Document, java.lang.String, org.opencms.xml.CmsXmlContentDefinition)
477      */

478     protected void initDocument(Document document, String JavaDoc encoding, CmsXmlContentDefinition definition) {
479
480         m_encoding = CmsEncoder.lookupEncoding(encoding, encoding);
481         m_document = document;
482         m_elementLocales = new HashMap JavaDoc();
483         m_elementNames = new HashMap JavaDoc();
484         m_locales = new HashSet JavaDoc();
485
486         // convert pre 5.3.6 XML page documents
487
if (!NODE_PAGES.equals(m_document.getRootElement().getName())) {
488             convertOldDocument();
489         }
490
491         // initialize the bookmarks
492
clearBookmarks();
493         Element pages = m_document.getRootElement();
494         try {
495             for (Iterator JavaDoc i = pages.elementIterator(NODE_PAGE); i.hasNext();) {
496
497                 Element page = (Element)i.next();
498                 Locale JavaDoc locale = CmsLocaleManager.getLocale(page.attributeValue(ATTRIBUTE_LANGUAGE));
499                 for (Iterator JavaDoc j = page.elementIterator(NODE_ELEMENT); j.hasNext();) {
500
501                     Element element = (Element)j.next();
502                     String JavaDoc name = element.attributeValue(ATTRIBUTE_NAME);
503
504                     String JavaDoc elementEnabled = element.attributeValue(ATTRIBUTE_ENABLED);
505                     boolean enabled = (elementEnabled == null) ? true : Boolean.valueOf(elementEnabled).booleanValue();
506
507                     // create an element type from the XML node
508
CmsXmlHtmlValue value = new CmsXmlHtmlValue(this, element, locale);
509                     value.setContentDefinition(definition);
510
511                     // add the element type bookmark
512
addBookmark(CmsXmlUtils.createXpathElement(name, 1), locale, enabled, value);
513                 }
514                 addLocale(locale);
515             }
516         } catch (NullPointerException JavaDoc e) {
517             LOG.error(Messages.get().getBundle().key(Messages.ERR_XML_PAGE_INIT_BOOKMARKS_0), e);
518         }
519     }
520
521     /**
522      * Sets the parameter that controls the relative link generation.<p>
523      *
524      * @param value the parameter that controls the relative link generation
525      */

526     protected void setAllowRelativeLinks(boolean value) {
527
528         m_allowRelativeLinks = value;
529     }
530
531     /**
532      * Sets the file this XML page content is written to.<p>
533      *
534      * @param file the file this XML page content is written to
535      */

536     protected void setFile(CmsFile file) {
537
538         m_file = file;
539     }
540
541     /**
542      * Converts the XML structure of the pre 5.5.0 development version of
543      * the XML page to the final 6.0 version.<p>
544      */

545     private void convertOldDocument() {
546
547         Document newDocument = DocumentHelper.createDocument();
548         Element root = newDocument.addElement(NODE_PAGES);
549         root.add(I_CmsXmlSchemaType.XSI_NAMESPACE);
550         root.addAttribute(I_CmsXmlSchemaType.XSI_NAMESPACE_ATTRIBUTE_NO_SCHEMA_LOCATION, XMLPAGE_XSD_SYSTEM_ID);
551
552         Map JavaDoc pages = new HashMap JavaDoc();
553
554         for (Iterator JavaDoc i = m_document.getRootElement().element(NODE_ELEMENTS).elementIterator(NODE_ELEMENT); i.hasNext();) {
555
556             Element elem = (Element)i.next();
557             try {
558                 String JavaDoc elementName = elem.attributeValue(ATTRIBUTE_NAME);
559                 String JavaDoc elementLang = elem.attributeValue(ATTRIBUTE_LANGUAGE);
560                 String JavaDoc elementEnabled = elem.attributeValue(ATTRIBUTE_ENABLED);
561                 boolean enabled = (elementEnabled == null) ? true : Boolean.valueOf(elementEnabled).booleanValue();
562
563                 Element page = (Element)pages.get(elementLang);
564                 if (page == null) {
565                     // no page available for the language, add one
566
page = root.addElement(NODE_PAGE).addAttribute(ATTRIBUTE_LANGUAGE, elementLang);
567                     pages.put(elementLang, page);
568                 }
569
570                 Element newElement = page.addElement(NODE_ELEMENT).addAttribute(ATTRIBUTE_NAME, elementName);
571                 if (!enabled) {
572                     newElement.addAttribute(ATTRIBUTE_ENABLED, String.valueOf(enabled));
573                 }
574                 Element links = elem.element(NODE_LINKS);
575                 if (links != null) {
576                     newElement.add(links.createCopy());
577                 }
578                 Element content = elem.element(NODE_CONTENT);
579                 if (content != null) {
580                     newElement.add(content.createCopy());
581                 }
582
583             } catch (NullPointerException JavaDoc e) {
584                 LOG.error(Messages.get().getBundle().key(Messages.ERR_XML_PAGE_CONVERT_CONTENT_0), e);
585             }
586         }
587
588         // now replace the old with the new document
589
m_document = newDocument;
590     }
591 }
Popular Tags