001    /**
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.camel.maven;
019    
020    import org.apache.maven.plugin.AbstractMojo;
021    import org.apache.maven.plugin.MojoExecutionException;
022    
023    import java.io.File;
024    import java.io.FileOutputStream;
025    import java.io.IOException;
026    import java.io.BufferedInputStream;
027    import java.io.BufferedOutputStream;
028    import java.io.FileWriter;
029    import java.io.ByteArrayOutputStream;
030    import java.io.InputStream;
031    import java.io.PrintWriter;
032    import java.util.ArrayList;
033    import java.util.Iterator;
034    import java.util.List;
035    import java.util.StringTokenizer;
036    import java.net.URL;
037    import java.net.URLConnection;
038    
039    import javax.xml.transform.Transformer;
040    import javax.xml.transform.TransformerFactory;
041    import javax.xml.transform.dom.DOMSource;
042    import javax.xml.transform.stream.StreamResult;
043    import javax.xml.transform.stream.StreamSource;
044    
045    import org.w3c.dom.Element;
046    import org.w3c.dom.NodeList;
047    import org.w3c.dom.Document;
048    import org.w3c.dom.Node;
049    import org.w3c.dom.NamedNodeMap;
050    
051    import org.w3c.tidy.DOMElementImpl;
052    import org.w3c.tidy.Tidy;
053    
054    /**
055     * Goal which extracts the content of a wiki page and converts it to docbook
056     * format
057     * 
058     * @goal htmlToDocbook
059     * @phase process-sources
060     */
061    public class GenerateDocBookMojo extends AbstractMojo {
062    
063            /**
064             * Base URL.
065             * 
066             * @parameter expression="${baseURL}"
067             *            default-value="http://activemq.apache.org/camel/"
068             * @required
069             */
070            private String baseURL;
071    
072            /**
073             * List of resources
074             * 
075             * @parameter
076             */
077            private String[] resources;
078    
079            /**
080             * List of author's fullname
081             * 
082             * @parameter
083             */
084            private String[] authors;
085    
086            /**
087             * Location of the xsl file.
088             * 
089             * @parameter expression="${configDirectory}"
090             *            default-value="${basedir}/src/styles/docbook.xsl"
091             * @required
092             */
093            private String xslFile;
094    
095            /**
096             * Location of the output directory.
097             * 
098             * @parameter expression="${project.build.directory}/docbkx/docbkx-source"
099             */
100            private String outputPath;
101            
102            /**
103             * Location of the output directory for wiki source.
104             * 
105             * @parameter expression="${project.build.directory}/docbkx/wiki-source"
106             */
107            private String wikiOutputPath;  
108    
109            /**
110             * @parameter expression="${title}"
111             * @required
112             */
113            private String title;
114    
115            /**
116             * @parameter expression="${subtitle}"
117             */
118            private String subtitle;
119            
120            /**
121             * @parameter expression="${mainFilename}" default-value="manual"
122             * @required
123             */
124            private String mainFilename;    
125    
126            /**
127             * @parameter expression="${version}" default-value="${project.version}"
128             */
129            private String version;
130    
131            /**
132             * @parameter expression="${legalNotice}"
133             */
134            private String legalNotice;
135    
136            /**
137             * Location of image files.
138             * 
139             * @parameter expression="${project.build.directory}/site/book/images"
140             *            
141             */
142            private String imageLocation;
143    
144            private String chapterId;
145    
146    
147            public void execute() throws MojoExecutionException {
148                    File outputDir = new File(outputPath);
149                    File wikiOutputDir = new File(wikiOutputPath);
150                    File imageDir = new File(imageLocation);
151                    if (!outputDir.exists()) {
152                            outputDir.mkdirs();
153                            imageDir.mkdirs();
154                            wikiOutputDir.mkdirs();
155                    }
156                    this.createMainXML();
157    
158                    for (int i = 0; i < resources.length; ++i) {
159                            this.setChapterId( removeExtension(resources[i]));
160    
161                            process(resources[i]);
162                    }
163    
164            }
165    
166            
167            /**
168             * Extract the wiki content and tranform it into docbook format
169             * 
170             * @param resource
171             */
172            public void process(String resource) {
173    
174                    Tidy tidy = new Tidy();
175                    ByteArrayOutputStream out = null;
176                    BufferedOutputStream output = null;
177                    BufferedOutputStream wikiOutput = null;
178    
179                    tidy.setXmlOut(true);
180                    try {
181                            out = new ByteArrayOutputStream();
182                            URL u = new URL(baseURL + resource);
183                            Document doc = tidy.parseDOM(
184                                            new BufferedInputStream(u.openStream()), out);
185                            out.close();
186                            // let's extract the div element with class="wiki-content
187                            // maincontent"
188                            NodeList nodeList = doc.getElementsByTagName("div");
189                            for (int i = 0; i < nodeList.getLength(); ++i) {
190                                    Node node = nodeList.item(i);
191    
192                                    NamedNodeMap nm = node.getAttributes();
193                                    Node attr = nm.getNamedItem("class");
194    
195                                    if (attr != null
196                                                    && attr.getNodeValue().equalsIgnoreCase(
197                                                                    "wiki-content maincontent")) {
198                                            downloadImages(node);
199                                            // These attributes will be used by xsl to
200                                            Element element = (Element) node;
201                                            element.setAttribute("chapterId", chapterId);
202                                            element.setAttribute("baseURL", baseURL);
203                                            element.setAttribute("imageLocation", "../images/");
204    
205                                            DOMSource source = new DOMSource(node);
206    
207                                             
208                                            output = new BufferedOutputStream(
209                                                            new FileOutputStream(outputPath + File.separator
210                                                                            + removeExtension(resource) + ".xml"));
211                                            StreamResult result = new StreamResult(output);
212                                            TransformerFactory tFactory = TransformerFactory
213                                                            .newInstance();
214                                            Transformer transformer = tFactory
215                                                            .newTransformer(new StreamSource(xslFile));
216                                            transformer.transform(source, result);
217    
218                                            // generate the wiki source for debugging
219                                            wikiOutput = new BufferedOutputStream(
220                                                            new FileOutputStream(wikiOutputPath + File.separator
221                                                                            + removeExtension(resource) + ".html"));
222                                            result = new StreamResult(wikiOutput);
223                                            transformer = tFactory.newTransformer();
224                                    transformer.transform(source, result);                                  
225    
226                                            break;
227                                    }
228    
229                            }
230    
231                    } catch (Exception e) {
232                            e.printStackTrace();
233                    }finally {
234                            try {
235                                    if(output != null)
236                                            output.close();
237                            } catch (IOException e) {
238                                    // TODO Auto-generated catch block
239                                    e.printStackTrace();
240                            }
241                    }
242            }
243            
244            
245            /*
246             *  create the main docbook xml file 
247             */
248            public void createMainXML() {
249                    try {
250    
251                            PrintWriter out = new PrintWriter(new FileWriter(outputPath
252                                            + File.separator + mainFilename + ".xml"));
253    
254                            out
255                                            .println("<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.4//EN\" \"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd\" ");
256                            out.println("[");
257    
258                            for (int i = 0; i < resources.length; ++i) {
259                                    out.println("<!ENTITY " +  removeExtension(resources[i]) + " SYSTEM \"" +  removeExtension(resources[i])
260                                                    + ".xml\">");
261                            }
262    
263                            out.println("]>");
264                            out.println("<book>");
265                            out.println("<bookinfo>");
266                            out.println("<title>" + title + "</title>");
267                            out.println("<subtitle>" + subtitle + "</subtitle>");
268                            out.println("<releaseinfo>" + version + "</releaseinfo>");
269                            out.println(" <authorgroup>");
270                            if (authors != null) {
271                                    for (int i = 0; i < authors.length; ++i) {
272                                            StringTokenizer name = new StringTokenizer(authors[i]);
273                                            String fname = name.nextToken();
274                                            String lname = "";
275                                            if (name.hasMoreTokens()) {
276                                                    lname = name.nextToken();
277                                            }
278                                            out.println("<author>");
279                                            out.println("<firstname>" + fname + "</firstname>");
280                                            out.println("<surname>" + lname + "</surname>");
281                                            out.println("</author>");
282    
283                                    }
284                            }
285    
286                            out.println("</authorgroup>");
287                            out.println("<legalnotice>");
288                            if (legalNotice != null && legalNotice.length() > 0) {
289                                    out.println("<para>");
290                                    out.println(legalNotice);
291                                    out.println("</para>");
292                            } else {
293                                    out
294                                                    .println("<para>Licensed to the Apache Software Foundation (ASF) under one or more");
295                                    out
296                                                    .println("contributor license agreements. See the NOTICE file distributed with");
297                                    out
298                                                    .println("this work for additional information regarding copyright ownership. The");
299                                    out
300                                                    .println("ASF licenses this file to You under the Apache License, Version 2.0 (the");
301                                    out
302                                                    .println("\"License\"); you may not use this file except in compliance with the");
303                                    out
304                                                    .println("License. You may obtain a copy of the License at</para>");
305                                    out
306                                                    .println("<para>http://www.apache.org/licenses/LICENSE-2.0</para>");
307                                    out
308                                                    .println("<para>Unless required by applicable law or agreed to in writing,");
309                                    out
310                                                    .println(" software distributed under the License is distributed on an \"AS IS\"");
311                                    out
312                                                    .println("BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or");
313                                    out
314                                                    .println("implied. See the License for the specific language governing permissions");
315                                    out.println("and limitations under the License.</para>");
316                            }
317    
318                            out.println("</legalnotice>");
319                            out.println("</bookinfo>");
320                            out.println("<toc></toc>");
321    
322                            for (int i = 0; i < resources.length; ++i) {
323                                    out.println("&" + removeExtension(resources[i]) + ";");
324                            }
325    
326                            out.println("</book>");
327                            out.flush();
328                            out.close();
329    
330                    } catch (IOException e) {
331                            // TODO Auto-generated catch block
332                            e.printStackTrace();
333                    }
334            }
335            
336            
337            public void downloadImages(Node node) {
338            List imageList = getImageUrls(node);
339            Iterator iter = imageList.iterator();
340            while(iter.hasNext()) {
341                    String imageUrl = (String)iter.next();
342                    String imageFile = "imageFile";
343                    
344                    //check if url path is relative
345                    if (imageUrl.indexOf("http://") < 0) {
346                            imageUrl = baseURL +  imageUrl;
347                    }
348                    try {
349                            
350                    URL url = new URL(imageUrl);
351                    StringTokenizer st=new StringTokenizer(url.getFile(), "/");
352                    while (st.hasMoreTokens()) {
353                            imageFile=st.nextToken();
354                    }
355    
356                    URLConnection connection = url.openConnection();
357                    InputStream stream = connection.getInputStream();
358                    BufferedInputStream in = new BufferedInputStream(stream);
359                    FileOutputStream file = new FileOutputStream(imageLocation + File.separator + imageFile);
360                    BufferedOutputStream out = new BufferedOutputStream(file);
361                    int i;
362                    while ((i = in.read()) != -1) {
363                        out.write(i);
364                    }
365                    out.flush();                    
366                    }catch(Exception e) {
367                            e.printStackTrace();
368                    }
369            
370                    
371            }
372            }
373            
374            
375            public List getImageUrls(Node node) {
376                    ArrayList list = new ArrayList();
377                    DOMElementImpl doc = (DOMElementImpl)node;
378                    NodeList imageList = doc.getElementsByTagName("img");
379                    
380                    if (imageList != null) {
381                            for (int i=0; i<imageList.getLength(); ++i) {
382                                    Node imageNode = imageList.item(i);
383                                    
384                                    NamedNodeMap nm = imageNode.getAttributes();
385                                    Node attr = nm.getNamedItem("src");
386                                    if(attr != null) {
387                                            list.add(attr.getNodeValue());
388                                    }
389    
390                            }       
391                    }       
392                    return list;
393            }       
394    
395            public String getChapterId() {
396                    return chapterId;
397            }
398    
399            public void setChapterId(String chapterId) {
400                    this.chapterId = chapterId;
401            }
402    
403    
404            public String removeExtension(String resource) {
405                    int index = resource.indexOf('.');
406                    return resource.substring(0, index);            
407            }
408    }