KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openharmonise > rm > resources > content > Document


1 /*
2  * The contents of this file are subject to the
3  * Mozilla Public License Version 1.1 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
6  *
7  * Software distributed under the License is distributed on an "AS IS"
8  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
9  * See the License for the specific language governing rights and
10  * limitations under the License.
11  *
12  * The Initial Developer of the Original Code is Simulacra Media Ltd.
13  * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
14  *
15  * All Rights Reserved.
16  *
17  * Contributor(s):
18  */

19 package org.openharmonise.rm.resources.content;
20
21 import java.util.Vector JavaDoc;
22 import java.util.logging.*;
23
24 import org.openharmonise.commons.dsi.AbstractDataStoreInterface;
25 import org.openharmonise.commons.xml.*;
26 import org.openharmonise.commons.xml.namespace.NamespaceType;
27 import org.openharmonise.rm.*;
28 import org.openharmonise.rm.dsi.*;
29 import org.openharmonise.rm.factory.*;
30 import org.openharmonise.rm.metadata.Profile;
31 import org.openharmonise.rm.publishing.*;
32 import org.openharmonise.rm.resources.lifecycle.Editable;
33 import org.openharmonise.rm.resources.publishing.*;
34 import org.openharmonise.rm.resources.xml.XMLResource;
35 import org.w3c.dom.*;
36
37
38 /**
39  * The <code>Document</code> class represents a content XML document resource
40  * which generally conform the Harmonise document XML schema.
41  *
42  * @author Michael Bell
43  * @version $Revision: 1.7 $
44  *
45  */

46 public class Document
47     extends XMLResource
48     implements DataStoreObject, Publishable, Editable, Cloneable JavaDoc, Comparable JavaDoc {
49
50     //DB constants
51
/**
52      * The <code>Document</code> database table name
53      */

54     private static final String JavaDoc TBL_DOCUMENT = "document";
55
56     //XML constants
57
/**
58      * Selections and Index XML attribute name found in the document schema
59      */

60     public static final String JavaDoc ATTRIB_SELECTIONS_AND_INDEX =
61         "selectionsAndIndex";
62     /**
63      * The <code>Document</code> XML tag name
64      */

65     public static final String JavaDoc TAG_DOCUMENT = "Document";
66     
67     /**
68      * The flag index
69      */

70     public static final String JavaDoc FLAG_INDEX = "index";
71     
72     /**
73      * The chapter tag name
74      */

75     public static final String JavaDoc TAG_CHAPTER = "Chapter";
76
77     private static final Logger m_logger = Logger.getLogger(Document.class.getName());
78     
79     //static initialiser block
80
static {
81         DatabaseInfo.getInstance().registerTableName(
82             Document.class.getName(),
83             TBL_DOCUMENT);
84     }
85
86     /**
87      * Constructs an instance with no data store interface and no other details.
88      *
89      */

90     public Document() {
91         super();
92
93     }
94
95     /**
96      * Standard constructor for a new or anonymous resource.
97      *
98      * @param dbintrf the data store to register
99      */

100     public Document(AbstractDataStoreInterface dbintrf) {
101         super(dbintrf);
102
103     }
104
105     /**
106      * Standard constructor for a known resource.
107      *
108      * @param dbintrf the data store to register
109      * @param nId the id of this resource
110      */

111     public Document(AbstractDataStoreInterface dbintrf, int nId) {
112         super(dbintrf, nId);
113     }
114
115     /**
116      * Standard constructor for a known resource which may be historical.
117      *
118      * @param dbintrf the data store interface
119      * @param nId the resource identifier
120      * @param nKey the unique resource key
121      * @param bIsHist <code>true</code> if the resoure is historical, otherwise <code>false</code>
122      */

123     public Document(
124         AbstractDataStoreInterface dbintrf,
125         int nId,
126         int nKey,
127         boolean bIsHist) {
128         super(dbintrf, nId, nKey, bIsHist);
129
130     }
131
132     /** Set method for the <code>Document</code>'s contents.
133      *
134      * @param sContent the contents to set
135      */

136     public void setContent(String JavaDoc sContent) throws PopulateException {
137         super.setContent(sContent);
138
139         try {
140             XMLDocument doc = getDocument();
141             
142             if(doc.getDocumentElement().getLocalName().equals(TAG_CONTENT) == false) {
143                 String JavaDoc sMainContent = sContent;
144                 
145                 if(sContent.startsWith("<?xml") == true) {
146                     int nIndex = sContent.indexOf("?>");
147                     if(nIndex > 0) {
148                         sMainContent = sContent.substring(nIndex+2);
149                     }
150                 }
151                 
152                 StringBuffer JavaDoc sBuf = new StringBuffer JavaDoc();
153                 
154                 sBuf.append("<").append(TAG_CONTENT).append(">");
155                 sBuf.append(sMainContent);
156                 sBuf.append("</").append(TAG_CONTENT).append(">");
157                 
158                 super.setContent(sBuf.toString());
159             }
160         } catch (DataAccessException e) {
161             throw new PopulateException(e);
162         }
163         
164         
165     }
166
167     /* (non-Javadoc)
168      * @see java.lang.Object#toString()
169      */

170     public String JavaDoc toString() {
171         StringBuffer JavaDoc strBuff = new StringBuffer JavaDoc();
172
173         strBuff
174             .append("Document Title:[" + m_sName + "] ")
175             .append("Document Summary:[" + m_sSummary + "] ")
176             .append("Document ID:[" + m_nId + "] ");
177
178         
179         try {
180             Profile prof = getProfile();
181             
182             if(prof != null) {
183                 strBuff.append(
184                         "Document profile:[" + prof.toString() + "]");
185             }
186             
187         } catch (DataAccessException e) {
188             m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
189         }
190         
191
192         return strBuff.toString();
193     }
194
195     /* (non-Javadoc)
196      * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
197      */

198     public Element publish(Element topEl, HarmoniseOutput xmlDoc, State state)
199         throws PublishException {
200
201         Element docEl = null;
202         NodeList nodes = null;
203         Text txt = null;
204         String JavaDoc sTagName = XMLUtils.getElementName(topEl);
205
206         if (sTagName.equals(TAG_CONTENT)) {
207             org.w3c.dom.Document JavaDoc txtDoc;
208             try {
209                 txtDoc = getDocument();
210             } catch (DataAccessException e) {
211                 throw new PublishException(e);
212             }
213             
214             if (txtDoc != null) {
215
216                 Element docRoot = txtDoc.getDocumentElement();
217                 
218                 if (docRoot == null) {
219                     throw new PublishException(
220                         "Parsed document contents return as null :"
221                             + " for document id "
222                             + m_nId
223                             + " contents:"
224                             + m_sContent);
225                 }
226
227                 docEl = publishContents(docRoot, topEl, xmlDoc, state);
228             } else {
229                 docEl = (Element) xmlDoc.copyNode(topEl);
230             }
231         } else {
232             // if we don't know about the tag, pass it up
233
docEl = super.publish(topEl, xmlDoc, state);
234         }
235
236         return docEl;
237     }
238
239
240     /**
241      * Populates the object using data conatined in XML element
242      * and with the specified text for this <code>Document</code>'s
243      * content.
244      *
245      * @param xmlElement the XML element
246      * @param sDocContent the document contents
247      * @throws PopulateException
248      */

249     public void populate(Element xmlElement, String JavaDoc sDocContent)
250         throws PopulateException {
251
252         try {
253             populate(xmlElement, new State(this.m_dsi));
254         } catch (StateException e) {
255             throw new PopulateException("Error creating new State", e);
256         }
257
258         m_sContent = sDocContent;
259     }
260
261     /* (non-Javadoc)
262      * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
263      */

264     public String JavaDoc getDBTableName() {
265
266         return TBL_DOCUMENT;
267     }
268
269     /* (non-Javadoc)
270      * @see org.openharmonise.rm.resources.AbstractChildObject#getParentObjectClassName()
271      */

272     public String JavaDoc getParentObjectClassName() {
273         return Section.class.getName();
274     }
275
276     /* (non-Javadoc)
277      * @see org.openharmonise.rm.publishing.Publishable#getTagName()
278      */

279     public String JavaDoc getTagName() {
280         return TAG_DOCUMENT;
281     }
282
283     /*----------------------------------------------------------------------------
284     Private methods
285     -----------------------------------------------------------------------------*/

286
287     /**
288      * Publishes the contents of a document to XML.
289      *
290      * @param contentsEl the element containing the full contents
291      * @param templateEl the element containing any templates to be published to
292      * @param xmlDoc the owner XML <code>Document</code>
293      * @param state the context/state for this operation
294      * @return the resultant XML element
295      * @throws PublishException if any errors occur
296      */

297     private Element publishContents(
298         Element contentsEl,
299         Element templateEl,
300         HarmoniseOutput xmlDoc,
301         State state)
302         throws PublishException {
303             
304         String JavaDoc sTagName = XMLUtils.getElementName(contentsEl);
305             
306         if (sTagName.equals(TAG_CONTENT) == false) {
307             throw new InvalidXMLElementException(TAG_CONTENT + " tag needed");
308         }
309
310         /* There are three cases:
311         1. Publish the entire contents
312         2. Publish the parts of the contents identified by the templateEl and the state
313         3. Publish the parts of the contents identified by the state in full and the rest
314         using a Template that should be contained in templateEl
315         */

316         Element elReturn = null;
317         String JavaDoc sFlag = templateEl.getAttribute(ATTRIB_SELECTIONS_AND_INDEX);
318
319         if ((sFlag != null) && (sFlag.length() > 0)) {
320             // this is case 3
321
elReturn =
322                 publishSelectionsAndIndex(
323                     contentsEl,
324                     templateEl,
325                     xmlDoc,
326                     state,
327                     sFlag);
328         } else {
329             NodeList nlTest = templateEl.getChildNodes();
330
331             if (nlTest.getLength() > 0) {
332                 // this is case 2
333
elReturn =
334                     publishSelectionsOnly(
335                         contentsEl,
336                         templateEl,
337                         xmlDoc,
338                         state);
339             } else {
340                 // this case 1
341
elReturn = publishFullContents(contentsEl, xmlDoc, state);
342             }
343         }
344
345         return elReturn;
346     }
347
348     /**
349      * Publishes elements under the contents that are in the state in full,
350      * and others using a template.
351      *
352      * @param contentsEl the document contents
353      * @param templateEl the template
354      * @param xmlDoc the owner document
355      * @param state the context/state for this operation
356      * @return the resultant XML element
357      * @throws PublishException if any errors occur
358      */

359     private Element publishSelectionsAndIndex(
360         Element contentsEl,
361         Element templateEl,
362         HarmoniseOutput xmlDoc,
363         State state,
364         String JavaDoc sFlag)
365         throws PublishException {
366         /* This is the only version that doesn't recurse
367         The elements that can be published as an index have to appear at the top level &
368         have to be called 'Chapter'
369         */

370         Element elReturn = null;
371         Element elStateDoc =
372             state.findElement(state.createElement(TAG_DOCUMENT));
373         Vector JavaDoc chapters = new Vector JavaDoc();
374         NodeList nodeChapters = null;
375
376         // the state should contain a list of all the chapters that are to appear in full
377
if (sFlag.equals(FLAG_INDEX) == false) {
378             boolean bFound = false;
379
380             if (elStateDoc != null) {
381                 String JavaDoc sId = elStateDoc.getAttribute(ATTRIB_ID);
382
383                 if (sId != null) {
384                     if (m_nId == Integer.parseInt(sId)) {
385                         bFound = true;
386                     }
387                 } else {
388                     Element elPath =
389                         XMLUtils.getFirstNamedChild(elStateDoc, TAG_PATH);
390
391                     if (elPath != null) {
392                         String JavaDoc sPath = elPath.getFirstChild().getNodeValue();
393
394                         try {
395                             if (sPath.equals(getPath() + "/" + getName())) {
396                                 bFound = true;
397                             }
398                         } catch (DataAccessException e) {
399                             throw new PublishException(
400                                 "Error occured getting name or path",e);
401                         }
402                     }
403                 }
404
405                 if (bFound) {
406                     nodeChapters = elStateDoc.getElementsByTagName(TAG_CHAPTER);
407
408                     for (int i = 0; i < nodeChapters.getLength(); i++) {
409                         Element el = (Element) nodeChapters.item(i);
410                         chapters.add(el.getAttribute(ATTRIB_ID));
411                     }
412                 }
413             }
414
415             if (chapters.size() == 0) {
416                 nodeChapters = contentsEl.getElementsByTagNameNS(NamespaceType.OHRM_DOC.getURI(),TAG_CHAPTER);
417
418                 if (nodeChapters.getLength() > 0) {
419                     Element el = (Element) nodeChapters.item(0);
420                     chapters.add(el.getAttribute(ATTRIB_ID));
421                 }
422
423             }
424         }
425
426         elReturn = xmlDoc.createElement(TAG_CONTENT);
427
428         NodeList nodes = contentsEl.getChildNodes();
429         Element elLinkTemplate =
430             (Element) templateEl.getElementsByTagName(
431                 Template.TAG_TEMPLATE).item(
432                 0);
433         
434         Template template = null;
435         
436         try {
437             template = (Template) HarmoniseObjectFactory.instantiateHarmoniseObject(m_dsi, Template.class.getName(), Integer.parseInt(elLinkTemplate.getAttribute(ATTRIB_ID)));
438         } catch (NumberFormatException JavaDoc e) {
439             throw new PublishException(e);
440         } catch (HarmoniseFactoryException e) {
441             throw new PublishException(e);
442         }
443         
444         int nPageId = 0;
445         NodeList nodesPage =
446             elLinkTemplate.getElementsByTagName(WebPage.TAG_PAGE);
447
448         if (nodesPage.getLength() > 0) {
449             Element elPage = (Element) nodesPage.item(0);
450             nPageId = Integer.parseInt(elPage.getAttribute(ATTRIB_ID));
451         }
452
453         // loop through the top level elements in the contents
454
for (int i = 0; i < nodes.getLength(); i++) {
455             if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) {
456                 continue;
457             }
458
459             Element el = (Element) nodes.item(i);
460
461             if (XMLUtils.getElementName(el).equals(TAG_CHAPTER)) {
462                 String JavaDoc sId = el.getAttribute(ATTRIB_ID);
463
464                 if (chapters.contains(sId)) {
465                     // a chapter that is in the state, publish it in full
466
elReturn.appendChild(
467                         publishFullContents(el, xmlDoc, state));
468                 } else {
469                     // a chapter that isn't in the state, publish with the supplied template
470
// first create a new state that contains a reference to this chapter and no other
471
try {
472                         State stateNew = null;
473
474                         stateNew =
475                             new State((org.w3c.dom.Document JavaDoc) state, m_dsi);
476
477                         Element elNewStateDoc =
478                             stateNew.findElement(
479                                 state.createElement(TAG_DOCUMENT));
480
481                         if (elNewStateDoc != null) {
482                             NodeList children = elNewStateDoc.getChildNodes();
483
484                             for (int j = 0; j < children.getLength(); j++) {
485                                 elNewStateDoc.removeChild(children.item(j));
486                             }
487                         } else {
488                             elNewStateDoc =
489                                 stateNew.createElement(TAG_DOCUMENT);
490                             elNewStateDoc.setAttribute(
491                                 ATTRIB_ID,
492                                 Integer.toString(getId()));
493                             stateNew.getDocumentElement().appendChild(
494                                 elNewStateDoc);
495                         }
496
497                         Element elThisChapter =
498                             stateNew.createElement(TAG_CHAPTER);
499                         elThisChapter.setAttribute(ATTRIB_ID, sId);
500                         elNewStateDoc.appendChild(elThisChapter);
501
502                         // publish the whole document with the template
503
Element elPublish =
504                             template.publishObjectToElement(
505                                 this,
506                                 xmlDoc,
507                                 stateNew);
508
509                         if (nPageId != 0) {
510                             xmlDoc.addPageIdToLinkNode(
511                                 state.getLoggedInUser(),
512                                 elPublish,
513                                 nPageId);
514                         }
515
516                         elReturn.appendChild(elPublish);
517                     } catch (StateException e) {
518                         throw new PublishException(
519                             "Error creating new State",
520                             e);
521                     }
522                 }
523             } else {
524                 // a non-chapter element, publish in full
525
elReturn.appendChild(publishFullContents(el, xmlDoc, state));
526             }
527         }
528
529         return elReturn;
530     }
531
532     /**
533      * Publishes only the parts of an element in the contents that are
534      * present in a template.
535      *
536      * @param contentsEl the element to be published
537      * @param templateEl the template to use
538      * @param xmlDoc the output document
539      * @param state the context/state for this operation
540      * @return the published element
541      * @throws PublishException if any errors occur
542      */

543     private Element publishSelectionsOnly(
544         Element contentsEl,
545         Element templateEl,
546         HarmoniseOutput xmlDoc,
547         State state)
548         throws PublishException {
549         // recurses, so can be called at any level within the contents
550
NodeList nodesTemplate = templateEl.getChildNodes();
551         Element elStateDoc =
552             state.findElement(state.createElement(TAG_DOCUMENT));
553
554         // shallow copy the element into the output, the fact that it has got this far means
555
// it should be published, the rest of the function decides which of its children
556
// deserve the same...
557
Element elReturn = null;
558         
559         String JavaDoc sTagname = XMLUtils.getElementName(contentsEl);
560         
561         if(sTagname.equals(TAG_CONTENT)) {
562             elReturn = xmlDoc.createElement(TAG_CONTENT);
563         } else {
564             elReturn = (Element) xmlDoc.importNode(contentsEl.cloneNode(false), false);
565         }
566
567         boolean bFound = false;
568
569         // loop through the children of the template element to see which of the current elements
570
// children should be published
571
for (int i = 0; i < nodesTemplate.getLength(); i++) {
572             if (nodesTemplate.item(i).getNodeType() != Node.ELEMENT_NODE) {
573                 continue;
574             }
575
576             bFound = true;
577
578             Element elNext = (Element) nodesTemplate.item(i);
579             String JavaDoc sTagName = XMLUtils.getElementName(elNext);
580
581             // get all of the children in the contents that match the current child of the template
582
NodeList nodesContents = contentsEl.getElementsByTagNameNS(NamespaceType.OHRM_DOC.getURI(),sTagName);
583
584             // see if an id is specified
585
String JavaDoc sId = elNext.getAttribute(ATTRIB_ID);
586
587             // if not, see if there are any ids on the state for elements of this type
588
if ((sId == null || sId.length() == 0) && (elStateDoc != null)) {
589                 NodeList nodes = elStateDoc.getElementsByTagName(sTagName);
590
591                 if (nodes.getLength() > 0) {
592                     sId = ((Element) nodes.item(0)).getAttribute(ATTRIB_ID);
593                 }
594             }
595
596             // loop through the children of the correct type, deciding which ones to publish
597
for (int j = 0; j < nodesContents.getLength(); j++) {
598                 Element el = (Element) nodesContents.item(j);
599                 String JavaDoc sNextId = null;
600
601                 if ((sId != null) && (sId.length() > 0)) {
602                     sNextId = el.getAttribute(ATTRIB_ID);
603                 }
604
605                 // we publish if:
606
// 1. there is no id specified, i.e. publish all
607
// 2. the ids match
608
if ((sId == null || sId.length() == 0)
609                     || (sNextId != null && sNextId.equals(sId))) {
610                     elReturn.appendChild(
611                         publishSelectionsOnly(el, elNext, xmlDoc, state));
612                 }
613             }
614         }
615
616         // this flag remains unset if the template element had no children
617
// this is taken to mean 'publish all children'
618
if (bFound == false) {
619             xmlDoc.copyChildren(elReturn, contentsEl);
620         }
621
622         return elReturn;
623     }
624
625     /**
626      * Publishes the whole of a XML tag within the <code>Document</code> contents.
627      *
628      * @param contentEl the element within the contents to publish
629      * @param xmlDoc the output documemt
630      * @param state the context/state for this operation
631      * @return the resultant XML document
632      * @throws PublishException if any errors occur
633      */

634     private Element publishFullContents(
635         Element contentEl,
636         HarmoniseOutput xmlDoc,
637         State state)
638         throws PublishException {
639         // recurses, so can be called at any level in the contents XML
640
Element returnEl = null;
641
642         NodeList nlContents = null;
643         String JavaDoc sTagName;
644         int nTemplateId;
645         Template template = null;
646
647         sTagName = XMLUtils.getElementName(contentEl);
648
649         // process templates by publishing the correct object into the contents
650
if (sTagName.equals(Template.TAG_TEMPLATE)) {
651             nTemplateId = Integer.parseInt(contentEl.getAttribute(ATTRIB_ID));
652             Element templRoot = null;
653             
654             try {
655                 template = (Template) HarmoniseObjectFactory.instantiateHarmoniseObject(m_dsi, Template.class.getName(), nTemplateId);
656             
657                 templRoot = template.getTemplateRootElement();
658             } catch (DataAccessException e) {
659                 throw new PublishException(
660                     "Error occured getting root element of template",e);
661             } catch (HarmoniseFactoryException e) {
662                 throw new PublishException(
663                         "Error occured getting root element of template",e);
664             }
665             
666             NodeList children = contentEl.getChildNodes();
667
668             for (int j = 0; j < children.getLength(); j++) {
669                 if (children.item(j).getNodeType() == Node.ELEMENT_NODE) {
670                     Element child = (Element) children.item(j);
671
672                     if (XMLUtils.getElementName(templRoot)
673                         .equalsIgnoreCase(XMLUtils.getElementName(child))) {
674
675                         try {
676                             Publishable pubObj =
677                                 HarmoniseObjectFactory.instantiatePublishableObject(
678                                     m_dsi,
679                                     child,
680                                     state);
681
682                             if (pubObj != null) {
683                                 returnEl =
684                                     template.publishObjectToElement(
685                                         pubObj,
686                                         xmlDoc,
687                                         state);
688                             }
689                         } catch (HarmoniseFactoryException e) {
690                             throw new PublishException(
691                                 "Error occured getting object from factory",e);
692                         }
693
694                     }
695                 }
696             }
697         } else {
698             // all other tags are copied accross & then their children are dealt with below
699

700             if(sTagName.equals(TAG_CONTENT)) {
701                 returnEl = xmlDoc.createElement(TAG_CONTENT);
702             } else {
703                 returnEl = (Element) xmlDoc.importNode(contentEl.cloneNode(false), false);
704             }
705             
706             nlContents = contentEl.getChildNodes();
707         }
708
709         if (nlContents != null) {
710             for (int i = 0; i < nlContents.getLength(); i++) {
711                 // copy text nodes straight accross, this is the end condition for the recursion
712
if (nlContents.item(i).getNodeType() == Node.TEXT_NODE) {
713                     returnEl.appendChild(
714                         xmlDoc.createTextNode(
715                             nlContents.item(i).getNodeValue()));
716                 }
717                 // recurse for all child elements
718
else if (
719                     nlContents.item(i).getNodeType() == Node.ELEMENT_NODE) {
720                     contentEl = (Element) nlContents.item(i);
721                     Element publishEl =
722                         publishFullContents(contentEl, xmlDoc, state);
723
724                     if (publishEl != null) {
725                         returnEl.appendChild(publishEl);
726                     }
727                 }
728             }
729         }
730
731         return returnEl;
732     }
733
734 }
Popular Tags