KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > outerj > daisy > publisher > serverimpl > docpreparation > IncludesProcessor


1 /*
2  * Copyright 2004 Outerthought bvba and Schaubroeck nv
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.outerj.daisy.publisher.serverimpl.docpreparation;
17
18 import org.xml.sax.*;
19 import org.xml.sax.helpers.AttributesImpl JavaDoc;
20 import org.outerj.daisy.repository.*;
21 import org.outerj.daisy.xmlutil.SaxBuffer;
22 import org.outerj.daisy.util.Constants;
23 import org.outerj.daisy.publisher.serverimpl.AbstractHandler;
24 import org.outerj.daisy.publisher.serverimpl.PublisherImpl;
25 import org.outerj.daisy.publisher.serverimpl.StripDocumentHandler;
26 import org.outerj.daisy.publisher.serverimpl.requestmodel.PublisherContext;
27 import org.outerj.daisy.publisher.serverimpl.requestmodel.PublisherContextImpl;
28 import org.outerj.daisy.publisher.serverimpl.requestmodel.PublisherVersionMode;
29 import org.outerx.daisy.x10.DocumentDocument;
30
31 import java.util.ArrayList JavaDoc;
32 import java.util.regex.Matcher JavaDoc;
33
34 /**
35  * This ContentHandler handles document includes. These are recognized
36  * by HTML p elements having a class attribute with value "include".
37  * The content should contain either a document id, or a document id
38  * and version id separated by the character '@' (eg "10@3"). By
39  * default the live version is included. The special
40  * version "LAST" can be specified (eg "10@LAST") to include the latest
41  * version. Inclusion processing is done recursively (with detection
42  * of recursive include of the same document).
43  *
44  * <p>The included document is not directly inlined on the location of inclusion,
45  * rather a new publisher request is executed for it, and the result of this
46  * is stored as a separate SaxBuffer in a {@link PreparedDocuments} instance.
47  * The original include tag is replaced by a tag &lt;daisyPreparedInclude&gt; with
48  * an id attribute referring the id under which it is stored in the PreparedDocuments.
49  */

50 public class IncludesProcessor extends AbstractHandler implements ContentHandler {
51     private boolean inInclude;
52     private StringBuffer JavaDoc includeBuffer;
53     private SaxBuffer includeSaxBuffer;
54     private int nestedElementCounter = 0;
55     private int includeElementNesting;
56     private ContentProcessor owner;
57     private long documentBranchId = -1;
58     private long documentLanguageId;
59
60     // the below members contain the details of the include currently happening through this handler
61
private long currentDocumentId;
62     private long currentBranchId;
63     private long currentLanguageId;
64     private long currentVersionId;
65
66     public IncludesProcessor(Document document, ContentHandler consumer, ContentProcessor owner) {
67         super(consumer);
68         this.owner = owner;
69         this.documentBranchId = document.getBranchId();
70         this.documentLanguageId = document.getLanguageId();
71     }
72
73     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName, Attributes atts) throws SAXException {
74         nestedElementCounter++;
75
76         if (!inInclude) {
77             if (localName.equals("pre") && namespaceURI.equals("")) {
78                 String JavaDoc clazz = atts.getValue("class");
79                 if (clazz != null && clazz.equals("include")) {
80                     inInclude = true;
81                     includeBuffer = new StringBuffer JavaDoc();
82                     includeSaxBuffer = new SaxBuffer();
83                     includeElementNesting = nestedElementCounter;
84                 }
85             }
86         }
87
88         if (!inInclude)
89             consumer.startElement(namespaceURI, localName, qName, atts);
90         else
91             includeSaxBuffer.startElement(namespaceURI, localName, qName, atts);
92     }
93
94     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName) throws SAXException {
95         if (!inInclude) {
96             consumer.endElement(namespaceURI, localName, qName);
97         } else {
98             includeSaxBuffer.endElement(namespaceURI, localName, qName);
99         }
100
101         if (inInclude && includeElementNesting == nestedElementCounter) {
102             inInclude = false;
103
104             String JavaDoc url = includeBuffer.toString();
105             url = url.trim();
106
107             if (url.startsWith("daisy:")) {
108                 // everything after the first whitespace is ignored (can be used for info about the include)
109
int spacePos = url.indexOf(' ');
110                 if (spacePos != -1)
111                     url = url.substring(0, spacePos);
112                 processDaisyInclude(url);
113             } else {
114                 // we don't handle it, so stream on the <p> element as if nothing happened
115
includeSaxBuffer.toSAX(consumer);
116             }
117         }
118
119         nestedElementCounter--;
120     }
121
122     /**
123      * Processes an include for an URL starting with "daisy:".
124      */

125     private void processDaisyInclude(String JavaDoc url) throws SAXException {
126         if (documentBranchId == -1)
127             throw new SAXException("Error in " + getClass().getName() + ": documentBranchId was not yet determined when an include was encountered.");
128
129         long documentId;
130         long versionId = owner.getPublisherContext().getVersionMode() == PublisherVersionMode.LAST ? -2 : -1; // -1 = live, -2 = last version
131

132         Matcher JavaDoc matcher = Constants.DAISY_LINK_PATTERN.matcher(url);
133         if (!matcher.matches()) {
134             outputError("Error including document: Invalid document reference: " + url);
135             return;
136         }
137
138         String JavaDoc documentIdString = matcher.group(1);
139         String JavaDoc branch = matcher.group(3);
140         String JavaDoc language = matcher.group(5);
141         String JavaDoc versionString = matcher.group(7);
142
143         try {
144             documentId = Long.parseLong(documentIdString);
145             if (versionString != null) {
146                 if (versionString.equalsIgnoreCase("last")) {
147                     versionId = -2;
148                 } else if (versionString.equalsIgnoreCase("live")) {
149                     versionId = -1;
150                 } else {
151                     versionId = Long.parseLong(versionString);
152                 }
153             }
154         } catch (NumberFormatException JavaDoc e) {
155             outputError("Error including document: Invalid document reference: " + url);
156             return;
157         }
158
159         // If the link doesn't specify branch and language, use the branch and language
160
// of the including document
161
if (branch == null || branch.equals(""))
162             branch = String.valueOf(documentBranchId);
163         if (language == null || language.equals(""))
164             language = String.valueOf(documentLanguageId);
165
166         Document document;
167         Version version;
168         DocumentDocument documentDocument;
169         try {
170             document = owner.getPreparationPipe().getRepository().getDocument(documentId, branch, language, false);
171             if (versionId != -1 && versionId != -2) {
172                 version = document.getVersion(versionId);
173             } else if (versionId == -2) {
174                 version = document.getLastVersion();
175             } else {
176                 version = document.getLiveVersion();
177                 if (version == null) {
178                     outputError("Error including document: no live version available. (document id: " + documentId + ")");
179                     return;
180                 }
181             }
182             documentDocument = document.getXml(version.getId());
183         } catch (Exception JavaDoc e) {
184             StringBuffer JavaDoc error = new StringBuffer JavaDoc("Error including document: ");
185             error.append(e.getMessage());
186             Throwable JavaDoc cause = e.getCause();
187             while (cause != null) {
188                 error.append(": ").append(cause.getMessage());
189             }
190             outputError(error.toString());
191             return;
192         }
193
194         currentDocumentId = documentId;
195         currentBranchId = documentDocument.getDocument().getBranchId();
196         currentLanguageId = documentDocument.getDocument().getLanguageId();
197         currentVersionId = documentDocument.getDocument().getDataVersionId();
198
199         String JavaDoc recursionDescription = detectRecursiveInclude();
200         if (recursionDescription != null) {
201             outputError("Error including document: recursive include detected: " + recursionDescription);
202         } else {
203             PublisherContext publisherContext = owner.getPublisherContext();
204             PreparedDocuments preparedDocuments = publisherContext.getPreparedDocuments();
205             if (preparedDocuments == null)
206                 throw new SAXException("Unexpected error: preparedDocuments is not available in IncludesProcessor.");
207             PublisherImpl publisher = publisherContext.getPublisher();
208             PublisherContextImpl childPublisherContext = new PublisherContextImpl(publisherContext);
209             childPublisherContext.setContentProcessor(owner);
210             childPublisherContext.setDocumentVariant(document.getId(), document.getBranchId(), document.getLanguageId());
211             childPublisherContext.setVersionId(version.getId());
212
213             PreparedDocuments.PreparedDocument preparedDocument = preparedDocuments.getNewPreparedDocument(document.getVariantKey());
214             try {
215                 publisher.performRequest(preparedDocuments.getPubReqSet(), document, version, childPublisherContext,
216                         new StripDocumentHandler(preparedDocument.getSaxBuffer()));
217             } catch (Exception JavaDoc e) {
218                 throw new SAXException(e);
219             }
220
221             AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
222             attrs.addAttribute("", "id", "id", "CDATA", String.valueOf(preparedDocument.getId()));
223             consumer.startElement(PublisherImpl.NAMESPACE, "daisyPreparedInclude", "daisyPreparedInclude", attrs);
224             consumer.endElement(PublisherImpl.NAMESPACE, "daisyPreparedInclude", "daisyPreparedInclude");
225         }
226
227         currentDocumentId = -1;
228         currentBranchId = -1;
229         currentLanguageId = -1;
230         currentVersionId = -1;
231     }
232
233     /**
234      * Detects recursive includes, if none is found null is returned, otherwise
235      * a description of the documents/versions/parts causing the recursive include.
236      */

237     private String JavaDoc detectRecursiveInclude() {
238         ArrayList JavaDoc parents = new ArrayList JavaDoc();
239         parents.add(this);
240
241         ContentProcessor cpParent = owner.getParent();
242         while (cpParent != null) {
243             IncludesProcessor parent = cpParent.getIncludesProcessor();
244             parents.add(parent);
245
246             if (parent.currentDocumentId == this.currentDocumentId
247                     && parent.currentBranchId == this.currentBranchId
248                     && parent.currentLanguageId == this.currentLanguageId
249                     && parent.currentVersionId == this.currentVersionId) {
250
251                 // generate description of recursive include
252
StringBuffer JavaDoc recursionDescription = new StringBuffer JavaDoc();
253                 for (int i = parents.size() - 1; i >=0; i--) {
254                     IncludesProcessor current = (IncludesProcessor)parents.get(i);
255                     if (recursionDescription.length() > 0)
256                         recursionDescription.append(" -> ");
257                     recursionDescription.append("document ").append(current.currentDocumentId).append(", branch ").append(current.currentBranchId).append(", language ").append(current.currentLanguageId).append(", version ").append(current.currentVersionId);
258                 }
259
260                 return recursionDescription.toString();
261             }
262             cpParent = cpParent.getParent();
263         }
264         return null;
265     }
266
267     public void endDocument() throws SAXException {
268         if (!inInclude)
269             consumer.endDocument();
270         else
271             includeSaxBuffer.endDocument();
272     }
273
274     public void startDocument() throws SAXException {
275         if (!inInclude)
276             consumer.startDocument();
277         else
278             includeSaxBuffer.startDocument();
279     }
280
281     public void characters(char ch[], int start, int length) throws SAXException {
282         if (inInclude) {
283             includeBuffer.append(ch, start, length);
284             includeSaxBuffer.characters(ch, start, length);
285         } else {
286             consumer.characters(ch, start, length);
287         }
288     }
289
290     public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
291         if (!inInclude)
292             consumer.ignorableWhitespace(ch, start, length);
293         else
294             includeSaxBuffer.characters(ch, start, length);
295     }
296
297     public void endPrefixMapping(String JavaDoc prefix) throws SAXException {
298         if (!inInclude)
299             consumer.endPrefixMapping(prefix);
300         else
301             includeSaxBuffer.endPrefixMapping(prefix);
302     }
303
304     public void skippedEntity(String JavaDoc name) throws SAXException {
305         if (!inInclude)
306             consumer.skippedEntity(name);
307         else
308             includeSaxBuffer.skippedEntity(name);
309     }
310
311     public void setDocumentLocator(Locator locator) {
312         if (!inInclude)
313             consumer.setDocumentLocator(locator);
314         else
315             includeSaxBuffer.setDocumentLocator(locator);
316     }
317
318     public void processingInstruction(String JavaDoc target, String JavaDoc data) throws SAXException {
319         if (!inInclude)
320             consumer.processingInstruction(target, data);
321         else
322             includeSaxBuffer.processingInstruction(target, data);
323     }
324
325     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri) throws SAXException {
326         if (!inInclude)
327             consumer.startPrefixMapping(prefix, uri);
328         else
329             includeSaxBuffer.startPrefixMapping(prefix, uri);
330     }
331
332 }
333
Popular Tags