KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > outerj > daisy > books > publisher > impl > publicationprocess > AddIndexTask


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.books.publisher.impl.publicationprocess;
17
18 import org.xml.sax.ContentHandler JavaDoc;
19 import org.xml.sax.Attributes JavaDoc;
20 import org.xml.sax.SAXException JavaDoc;
21 import org.xml.sax.InputSource JavaDoc;
22 import org.outerj.daisy.books.publisher.impl.util.AbstractContentHandler;
23 import org.outerj.daisy.books.publisher.impl.BookInstanceLayout;
24 import org.outerj.daisy.books.store.BookInstance;
25 import org.outerj.daisy.xmlutil.XmlSerializer;
26 import org.outerj.daisy.xmlutil.LocalSAXParserFactory;
27 import org.apache.cocoon.xml.AttributesImpl;
28 import org.apache.cocoon.transformation.I18nTransformer;
29
30 import javax.xml.parsers.SAXParser JavaDoc;
31 import java.util.*;
32 import java.util.regex.Pattern JavaDoc;
33 import java.util.regex.Matcher JavaDoc;
34 import java.text.Collator JavaDoc;
35 import java.io.InputStream JavaDoc;
36 import java.io.OutputStream JavaDoc;
37
38 public class AddIndexTask implements PublicationProcessTask {
39     private final String JavaDoc input;
40     private final String JavaDoc output;
41
42     public AddIndexTask(String JavaDoc input, String JavaDoc output) {
43         this.input = input;
44         this.output = output;
45     }
46
47     public void run(PublicationContext context) throws Exception JavaDoc {
48         context.getPublicationLog().info("Running add index task.");
49         BookInstance bookInstance = context.getBookInstance();
50         String JavaDoc publicationOutputPath = BookInstanceLayout.getPublicationOutputPath(context.getPublicationOutputName());
51         InputStream JavaDoc is = null;
52         OutputStream JavaDoc os = null;
53         try {
54             is = bookInstance.getResource(publicationOutputPath + input);
55             os = bookInstance.getResourceOutputStream(publicationOutputPath + output);
56             SAXParser JavaDoc parser = LocalSAXParserFactory.getSAXParserFactory().newSAXParser();
57             XmlSerializer serializer = new XmlSerializer(os);
58             AddIndexHandler addIndexHandler = new AddIndexHandler(serializer, context.getLocale());
59             parser.getXMLReader().setContentHandler(addIndexHandler);
60             parser.getXMLReader().parse(new InputSource JavaDoc(is));
61         } finally {
62             if (is != null)
63                 try { is.close(); } catch (Exception JavaDoc e) {
64                     context.getPublicationLog().error("Error closing input stream.", e);
65                 }
66             if (os != null)
67                 try { os.close(); } catch (Exception JavaDoc e) {
68                     context.getPublicationLog().error("Error closing output stream.", e);
69                 }
70         }
71     }
72
73     static class AddIndexHandler extends AbstractContentHandler {
74         private Index index = new Index();
75         private StringBuffer JavaDoc indexEntryBuffer = new StringBuffer JavaDoc();
76         private int indexEntryNesting = -1;
77         private String JavaDoc indexEntryId = null;
78         private int nesting = 0;
79         private int indexNameCounter = 1;
80         private Locale locale;
81
82         public AddIndexHandler(ContentHandler JavaDoc consumer, Locale locale) {
83             super(consumer);
84             this.locale = locale;
85         }
86
87         public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc atts) throws SAXException JavaDoc {
88             nesting++;
89             // note: the indexEntryNesting == -1 test is to ignore nested indexentry-spans.
90
if (indexEntryNesting == -1 && namespaceURI.equals("") && localName.equals("span")) {
91                 String JavaDoc className = atts.getValue("class");
92                 if ("indexentry".equals(className)) {
93                     indexEntryBuffer.setLength(0);
94                     indexEntryNesting = nesting;
95
96                     String JavaDoc id = atts.getValue("id");
97                     if (id == null) {
98                         id = "dsy_idx_" + indexNameCounter++;
99                         AttributesImpl newAttrs = new AttributesImpl(atts);
100                         newAttrs.addCDATAAttribute("id", id);
101                         atts = newAttrs;
102                     }
103                     indexEntryId = id;
104                 }
105             }
106             super.startElement(namespaceURI, localName, qName, atts);
107         }
108
109         public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName) throws SAXException JavaDoc {
110             if (indexEntryNesting == nesting) {
111                 // end of index entry
112
String JavaDoc entry = indexEntryBuffer.toString();
113                 IndexEntry indexEntry = index.getEntry(entry);
114                 if (indexEntry != null)
115                     indexEntry.addId(indexEntryId);
116
117                 // cleanup
118
indexEntryNesting = -1;
119                 indexEntryId = null;
120             } else if (nesting == 2 && namespaceURI.equals("") && localName.equals("body")) {
121                 // closing body tag, insert index if not empty
122
index.generateSaxFragment(consumer, locale);
123             }
124             nesting--;
125             super.endElement(namespaceURI, localName, qName);
126         }
127
128         public void characters(char ch[], int start, int length) throws SAXException JavaDoc {
129             if (indexEntryNesting != -1)
130                 indexEntryBuffer.append(ch, start, length);
131             super.characters(ch, start, length);
132         }
133     }
134
135     static class Index {
136         private Map entries = new HashMap();
137
138         public IndexEntry getEntry(String JavaDoc name) {
139             Pattern JavaDoc subentryPattern = Pattern.compile("([^:]+)");
140             Matcher JavaDoc subentryMatcher = subentryPattern.matcher(name);
141             IndexEntry indexEntry = null;
142             while (subentryMatcher.find()) {
143                 String JavaDoc subentry = subentryMatcher.group(1).trim();
144                 if (subentry.length() == 0)
145                     continue;
146                 if (indexEntry == null) {
147                     indexEntry = (IndexEntry)entries.get(subentry);
148                     if (indexEntry == null) {
149                         indexEntry = new IndexEntry(subentry);
150                         entries.put(subentry, indexEntry);
151                     }
152                 } else {
153                     indexEntry = indexEntry.getSubEntry(subentry);
154                 }
155             }
156             return indexEntry;
157         }
158
159         public void generateSaxFragment(ContentHandler JavaDoc contentHandler, Locale locale) throws SAXException JavaDoc {
160             if (entries.size() == 0)
161                 return;
162
163             contentHandler.characters(new char[] {'\n'}, 0, 1);
164             AttributesImpl indexHeaderAttrs = new AttributesImpl();
165             indexHeaderAttrs.addCDATAAttribute("id", "index");
166             contentHandler.startElement("", "h1", "h1", indexHeaderAttrs);
167
168             AttributesImpl indexTitleAttrs = new AttributesImpl();
169             indexTitleAttrs.addCDATAAttribute("key", "index");
170             contentHandler.startPrefixMapping("i18n", I18nTransformer.I18N_NAMESPACE_URI);
171             contentHandler.startElement(I18nTransformer.I18N_NAMESPACE_URI, "text", "i18n:text", indexTitleAttrs);
172             contentHandler.endElement(I18nTransformer.I18N_NAMESPACE_URI, "text", "i18n:text");
173             contentHandler.endPrefixMapping("i18n");
174
175             contentHandler.endElement("", "h1", "h1");
176
177             contentHandler.characters(new char[] {'\n'}, 0, 1);
178             contentHandler.startElement("", "index", "index", new AttributesImpl());
179
180             IndexEntry[] entries = (IndexEntry[])this.entries.values().toArray(new IndexEntry[0]);
181             IndexEntryComparator comparator = new IndexEntryComparator(locale);
182             Arrays.sort(entries, comparator);
183
184             IndexEntry prevEntry = null;
185             for (int i = 0; i < entries.length; i++) {
186                 if (prevEntry == null || isDifferentGroup(prevEntry, entries[i])) {
187                     if (prevEntry != null) {
188                         contentHandler.characters(new char[] {'\n'}, 0, 1);
189                         contentHandler.endElement("", "indexGroup", "indexGroup");
190                     }
191                     AttributesImpl indexGroupAtrrs = new AttributesImpl();
192                     if (Character.isLetter(entries[i].getName().charAt(0)))
193                         indexGroupAtrrs.addCDATAAttribute("name", String.valueOf(Character.toUpperCase(entries[i].getName().charAt(0))));
194                     contentHandler.characters(new char[] {'\n'}, 0, 1);
195                     contentHandler.startElement("", "indexGroup", "indexGroup", indexGroupAtrrs);
196                 }
197                 entries[i].generateSaxFragment(contentHandler, comparator);
198                 prevEntry = entries[i];
199             }
200
201             if (prevEntry != null) {
202                 contentHandler.characters(new char[] {'\n'}, 0, 1);
203                 contentHandler.endElement("", "indexGroup", "indexGroup");
204             }
205
206             contentHandler.characters(new char[] {'\n'}, 0, 1);
207             contentHandler.endElement("", "index", "index");
208         }
209
210         public boolean isDifferentGroup(IndexEntry entry1, IndexEntry entry2) {
211             char c1 = Character.toUpperCase(entry1.getName().charAt(0));
212             char c2 = Character.toUpperCase(entry2.getName().charAt(0));
213             return c1 != c2 && Character.isLetter(c2);
214         }
215     }
216
217     static class IndexEntry {
218         private String JavaDoc name;
219         private List ids = new ArrayList();
220         private Map children;
221
222         public IndexEntry(String JavaDoc name) {
223             this.name = name;
224         }
225
226         public void addId(String JavaDoc id) {
227             this.ids.add(id);
228         }
229
230         public String JavaDoc getName() {
231             return name;
232         }
233
234         public void addChild(IndexEntry entry) {
235             if (children == null)
236                 children = new HashMap();
237             children.put(entry.getName(), entry);
238         }
239
240         public IndexEntry getSubEntry(String JavaDoc name) {
241             IndexEntry indexEntry = children == null ? null : (IndexEntry)children.get(name);
242             if (indexEntry == null) {
243                 indexEntry = new IndexEntry(name);
244                 addChild(indexEntry);
245             }
246             return indexEntry;
247         }
248
249         public void generateSaxFragment(ContentHandler JavaDoc contentHandler, IndexEntryComparator comparator) throws SAXException JavaDoc {
250             AttributesImpl entryAttrs = new AttributesImpl();
251             entryAttrs.addAttribute("", "name", "name", "CDATA", getName());
252             contentHandler.characters(new char[] {'\n'}, 0, 1);
253             contentHandler.startElement("", "indexEntry", "indexEntry", entryAttrs);
254             Iterator entriesIt = ids.iterator();
255             while (entriesIt.hasNext()) {
256                 String JavaDoc id = (String JavaDoc)entriesIt.next();
257                 contentHandler.characters(new char[] {'\n'}, 0, 1);
258                 contentHandler.startElement("", "id", "id", new AttributesImpl());
259                 contentHandler.characters(id.toCharArray(), 0, id.length());
260                 contentHandler.endElement("", "id", "id");
261             }
262             if (children != null) {
263                 IndexEntry[] entries = (IndexEntry[])children.values().toArray(new IndexEntry[0]);
264                 Arrays.sort(entries, comparator);
265                 for (int i = 0; i < entries.length; i++) {
266                     entries[i].generateSaxFragment(contentHandler, comparator);
267                 }
268             }
269             contentHandler.characters(new char[] {'\n'}, 0, 1);
270             contentHandler.endElement("", "indexEntry", "indexEntry");
271         }
272     }
273
274     static class IndexEntryComparator implements Comparator {
275         private final Collator JavaDoc collator;
276
277         public IndexEntryComparator(Locale locale) {
278             this.collator = Collator.getInstance(locale);
279         }
280
281         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
282             String JavaDoc entry1 = ((IndexEntry)o1).getName();
283             String JavaDoc entry2 = ((IndexEntry)o2).getName();
284             return collator.compare(entry1, entry2);
285         }
286     }
287 }
288
Popular Tags