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 }