PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/atlassian/uwc/exporters/liferay/digester/LrWikiTree.java

https://bitbucket.org/atlassianlabs/universal-wiki-connector
Java | 511 lines | 280 code | 83 blank | 148 comment | 61 complexity | d62fc46fc11293dc286f0fb18b08274c MD5 | raw file
  1. package com.atlassian.uwc.exporters.liferay.digester;
  2. import java.io.BufferedWriter;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.OutputStreamWriter;
  8. import java.nio.channels.FileChannel;
  9. import java.util.ArrayList;
  10. import java.util.Collections;
  11. import org.apache.log4j.Logger;
  12. /**
  13. * Liferay (LR) wiki page processor.
  14. *
  15. * @author Developer
  16. *
  17. */
  18. public class LrWikiTree {
  19. public static final String FRONTPAGE = "FrontPage";
  20. private ArrayList<WikiPage> pageList = new ArrayList<WikiPage>();
  21. private static Logger _log = Logger.getLogger(LrWikiTree.class);
  22. /**
  23. * Adds pages to the internal page list. We only keep the current page and discard historical pages.
  24. *
  25. * @param page
  26. */
  27. public void addPage(WikiPage page) {
  28. // if we have an existing page check the version and discard ancient pages
  29. WikiPage wp = findPage(page.get__title());
  30. if (wp != null) {
  31. Double version = wp.getVersion();
  32. // only keep latest version of the page
  33. if (page.getVersion() > version) {
  34. pageList.remove(wp);
  35. pageList.add(page);
  36. }
  37. } else {
  38. // no previous version so add the page
  39. // _log.debug("Adding Page: " + page.get__title());
  40. pageList.add(page);
  41. }
  42. }
  43. /**
  44. * Finds pages that don't have parents and are not named Frontpage.
  45. *
  46. * @return
  47. */
  48. public ArrayList<WikiPage> findOrphans() {
  49. ArrayList<WikiPage> retval = new ArrayList<WikiPage>();
  50. for (WikiPage page : pageList) {
  51. String parentTitle = page.get__parentTitle();
  52. if (parentTitle.isEmpty() && !page.get__title().equals(FRONTPAGE)) {
  53. retval.add(page);
  54. } else if (!page.get__redirectTitle().isEmpty()) {
  55. retval.add(page);
  56. }
  57. }
  58. return retval;
  59. }
  60. /**
  61. * Creates a page in the home directory that will hold all the orphans. Also creates the directory structure on disk
  62. * for the pages.
  63. *
  64. * @param outputDir
  65. * @throws IOException
  66. */
  67. public void createUncategorizedChildPage(String outputDir, String orphanPage) throws IOException {
  68. String uncategorizedPage = "== Overview ==\r\n\r\nPages that don't have parents are placed here after transfering the Wiki into Confluence.";
  69. File dir = new File(outputDir);
  70. dir.mkdirs();
  71. File unCat = new File(outputDir + File.separator + orphanPage);
  72. write(unCat, uncategorizedPage);
  73. }
  74. /**
  75. * Copies the page content of the files in the list to the output directory.
  76. *
  77. * @param list
  78. * @param outputDir
  79. * @throws IOException
  80. */
  81. public void saveOrphanList(ArrayList<WikiPage> list, String outputDir, boolean original) throws IOException {
  82. for (WikiPage page : list) {
  83. page.setDepth(0); // page is an orphan so reset it's place to the root in the hierarchy
  84. recursePages(page);
  85. page.setPath("");
  86. page.setOutDir(new File(outputDir));
  87. saveOrphanRecursive(page, original);
  88. }
  89. }
  90. /**
  91. * Writes the content of the orphaned pages onto the Uncategorized directory. Child pages are written maintaining
  92. * the hierarchy in the file system.
  93. *
  94. * @param frontPage
  95. * @param copyOriginal
  96. * true to copy the original xml file to the destination
  97. * @throws IOException
  98. */
  99. public void saveOrphanRecursive(WikiPage frontPage, boolean copyOriginal) throws IOException {
  100. String padding = "";
  101. for (int i = 0; i < frontPage.getDepth(); i++) {
  102. padding += " ";
  103. }
  104. _log.info(padding + frontPage.get__title());
  105. File dir = new File(frontPage.getOutDir() + File.separator + frontPage.getPath());
  106. dir.mkdirs();
  107. // _log.info("++" + dir.getCanonicalPath());
  108. // _log.debug("Create Dir: " + dir);
  109. if (copyOriginal) {
  110. copyFile(frontPage.getFile(), new File(dir, frontPage.get__title() + ".xml"));
  111. } else {
  112. File filePage = new File(dir, frontPage.get__title());
  113. write(filePage, frontPage.get__content());
  114. }
  115. if (!frontPage.getAttachments().isEmpty()) {
  116. _log.info(padding + " " + frontPage.getAttachments().size() + "-Attachments " + frontPage.getAttachments());
  117. }
  118. for (WikiPage page : frontPage.getChildren()) {
  119. page.setPath(frontPage.getPath());
  120. page.setOutDir(frontPage.getOutDir());
  121. saveRecursive(page, copyOriginal);
  122. }
  123. }
  124. /**
  125. * Removes the parent child relationship for the given pages.
  126. *
  127. * @param pages
  128. */
  129. public void unlinkChildren(ArrayList<WikiPage> pages) {
  130. for (WikiPage page : pages) {
  131. _log.debug("Removing page '" + page.get__title() + "'");
  132. if (!pageList.remove(page)) {
  133. _log.error("Can't remove: " + page.get__title());
  134. }
  135. // We also need to remove the child from the parent child relationship
  136. WikiPage parent = findPage(page.get__parentTitle());
  137. if (parent != null) {
  138. if (!parent.removeChild(page)) {
  139. _log.error("Can't remove child from parent: " + page.get__parentTitle());
  140. }
  141. }
  142. }
  143. }
  144. public WikiPage findPage(String title) {
  145. WikiPage retval = null;
  146. for (WikiPage page : pageList) {
  147. if (page.get__title().equals(title)) {
  148. retval = page;
  149. break;
  150. }
  151. }
  152. return retval;
  153. }
  154. /**
  155. * Creates a parent child relationship with the internal pages.
  156. *
  157. * @param sort
  158. */
  159. public void linkChildren(boolean sort) {
  160. if (sort) {
  161. Collections.sort(pageList);
  162. }
  163. for (WikiPage page : pageList) {
  164. String parentTitle = page.get__parentTitle();
  165. if (!parentTitle.isEmpty()) {
  166. WikiPage parent = findPage(parentTitle);
  167. if (parent != null) {
  168. parent.addChildPage(page);
  169. } else {
  170. _log.debug("!!!Error finding Parent!!! " + parentTitle);
  171. }
  172. }
  173. }
  174. }
  175. /**
  176. * copies all the attachments for all the pages into the given directory.
  177. *
  178. * @param larDirectory
  179. * @param destDirName
  180. * @throws IOException
  181. */
  182. public void saveAttachments(String larDirectory, String destDirName) throws IOException {
  183. File destDir = new File(destDirName);
  184. destDir.mkdirs();
  185. _log.info("Copying attachments to: " + destDirName);
  186. for (WikiPage page : pageList) {
  187. ArrayList<Attachment> files = page.getAttachments();
  188. for (Attachment attachment : files) {
  189. String name = attachment.getBinPath();
  190. copyFile(new File(larDirectory, name), new File(destDir, attachment.getName()));
  191. }
  192. }
  193. }
  194. /**
  195. * Attachments in the LR export are indistinguishable from links. The function looks for [[xxx]], where xxx is an
  196. * attachment and changes the download link to [^xxx]. This makes the UWC
  197. * com.atlassian.uwc.hierarchies.FilepathHierarchy class upload the attachment.
  198. *
  199. * Image conversion {{image.jpg}} -> !image.jpg! is also handled here for the same reason as above.
  200. *
  201. */
  202. public void reformatAttachments() {
  203. for (WikiPage page : pageList) {
  204. ArrayList<Attachment> files = page.getAttachments();
  205. for (Attachment attachment : files) {
  206. String name = attachment.getName();
  207. String content = page.get__content();
  208. if (content.indexOf(name) > 0) {
  209. String replace = convertAttachLink(content, name);
  210. replace = convertImageLink(replace, name);
  211. page.set__content(replace);
  212. }
  213. }
  214. }
  215. }
  216. /**
  217. * [[link]] converts to [^link] and [[link|link name]] converts to [^link]
  218. *
  219. * Linking to an attachment in LR stopped working after the SP2 upgrade but we still use this mechanism to mark
  220. * attachments for inclusion in Confluence.
  221. *
  222. * @param content
  223. * @param name
  224. * @return
  225. */
  226. public String convertAttachLink(String content, String name) {
  227. String retval = content;
  228. // [[attach] -> [^attach]
  229. retval = content.replaceAll("\\[\\[" + name + "\\]\\]", "[^" + name + "]");
  230. // [[attach|attach name]] -> [^attach]
  231. // // "\\[\\[" + // opening left brackets
  232. // // name is captured by replaceAll
  233. // // "\\|" + // until a pipe
  234. // // "[^\\]|]+" + // anything but a right bracket or | until
  235. // // "\\]\\]"; // right brackets
  236. retval = retval.replaceAll("\\[\\[" + name + "\\|[^\\]|]*]]", "[^" + name + "]");
  237. return retval;
  238. }
  239. /**
  240. * {{image.jpg}} is display image in LR - in Confluence its !image.jpg! We do this here as we can find out if it's
  241. * an image by looking at the attachments.
  242. *
  243. * @param content
  244. * @param name
  245. * @return
  246. */
  247. public String convertImageLink(String content, String name) {
  248. return content.replaceFirst("\\{\\{" + name + "\\}\\}", "!" + name + "!");
  249. }
  250. /**
  251. * Html formatted pages need to be surrounded with {html}
  252. *
  253. * @param noHtml
  254. * if true encloses the html fragment inside a code block this disables HTML rendering in Confluence
  255. */
  256. public void reformatHtmlPages(boolean noHtml) {
  257. for (WikiPage page : pageList) {
  258. String format = page.get__format();
  259. if (format.equalsIgnoreCase("html")) {
  260. if (noHtml) {
  261. _log.debug("Disabling html formatting for page: " + page.get__title());
  262. String content = page.get__content();
  263. page.set__content("{code} " + content + "{code}");
  264. } else {
  265. _log.debug("Adding html formatting for page: " + page.get__title());
  266. String content = page.get__content();
  267. page.set__content("{html} " + content + "{html}");
  268. }
  269. } else if (format.equalsIgnoreCase("creole")) {
  270. // This is the stuff we are expecting
  271. } else {
  272. _log.warn("Unsupported format detected: " + format);
  273. }
  274. }
  275. }
  276. /**
  277. * Sets the depth value for the pages in the hierarchy.
  278. *
  279. * @param frontPage
  280. */
  281. public void recursePages(WikiPage frontPage) {
  282. for (WikiPage page : frontPage.getChildren()) {
  283. // if(page.get__title().contains("Admin")){
  284. // _log.debug("!break " );
  285. // }
  286. page.setDepth(frontPage.getDepth() + 1);
  287. recursePages(page);
  288. }
  289. }
  290. /**
  291. * Prints out the current tree structure.
  292. *
  293. * @param frontPage
  294. */
  295. public void showRecursive(WikiPage frontPage) {
  296. String padding = "";
  297. for (int i = 0; i < frontPage.getDepth(); i++) {
  298. padding += " ";
  299. }
  300. _log.info(padding + frontPage.get__title());
  301. if (!frontPage.getAttachments().isEmpty()) {
  302. _log.info(padding + " " + frontPage.getAttachments().size() + "-Attachments " + frontPage.getAttachments());
  303. }
  304. for (WikiPage page : frontPage.getChildren()) {
  305. showRecursive(page);
  306. }
  307. }
  308. /**
  309. * Copy the current pagelist original files into the given directory.
  310. *
  311. * @param dir
  312. * @throws IOException
  313. */
  314. public void copyTo(String dir) throws IOException {
  315. File destDir = new File(dir);
  316. destDir.mkdir();
  317. _log.info("Copying " + pageList.size() + " current pages to: " + dir);
  318. for (WikiPage page : pageList) {
  319. _log.info("XML Path: " + page.getFile().getAbsolutePath());
  320. copyFile(page.getFile(), new File(destDir, page.get__title() + ".xml"));
  321. }
  322. }
  323. /**
  324. * Copy the source file to the destination overwriting the file if it exists.
  325. *
  326. * @param sourceFile
  327. * @param destFile
  328. * @throws IOException
  329. */
  330. public static void copyFile(File sourceFile, File destFile) throws IOException {
  331. copyFile(sourceFile, destFile, true);
  332. }
  333. /**
  334. * Copy the source file to the destination.
  335. *
  336. * @param sourceFile
  337. * @param destFile
  338. * @param overwrite
  339. * overwrite the file if true.
  340. * @throws IOException
  341. */
  342. public static void copyFile(File sourceFile, File destFile, boolean overwrite) throws IOException {
  343. if (!destFile.exists()) {
  344. destFile.createNewFile();
  345. } else {
  346. if (!overwrite) {
  347. throw new IOException("Destination file exists! " + destFile);
  348. }
  349. _log.trace("Destination file exists: " + destFile);
  350. }
  351. FileChannel source = null;
  352. FileChannel destination = null;
  353. try {
  354. source = new FileInputStream(sourceFile).getChannel();
  355. destination = new FileOutputStream(destFile).getChannel();
  356. destination.transferFrom(source, 0, source.size());
  357. } finally {
  358. if (source != null) {
  359. source.close();
  360. }
  361. if (destination != null) {
  362. destination.close();
  363. }
  364. }
  365. }
  366. /**
  367. * Writes the content of the pages of the Wiki onto the directory, maintaining the hierarchy structure in the file
  368. * system.
  369. *
  370. * @param frontPage
  371. * @param copyOriginal
  372. * true to copy the original xml file to the destination
  373. * @throws IOException
  374. */
  375. public void saveRecursive(WikiPage frontPage, boolean copyOriginal) throws IOException {
  376. String padding = "";
  377. for (int i = 0; i < frontPage.getDepth(); i++) {
  378. padding += " ";
  379. }
  380. _log.info(padding + frontPage.get__title());
  381. File dir = new File(frontPage.getOutDir() + File.separator + frontPage.getPath(), frontPage.get__title());
  382. dir.mkdirs();
  383. // _log.debug("Create Dir: " + dir);
  384. if (copyOriginal) {
  385. copyFile(frontPage.getFile(), new File(dir, frontPage.get__title() + ".xml"));
  386. } else {
  387. File filePage = new File(dir, frontPage.get__title());
  388. write(filePage, frontPage.get__content());
  389. }
  390. if (!frontPage.getAttachments().isEmpty()) {
  391. _log.info(padding + " " + frontPage.getAttachments().size() + "-Attachments " + frontPage.getAttachments());
  392. }
  393. for (WikiPage page : frontPage.getChildren()) {
  394. page.setPath(frontPage.getPath() + File.separator + frontPage.get__title());
  395. page.setOutDir(frontPage.getOutDir());
  396. saveRecursive(page, copyOriginal);
  397. }
  398. }
  399. protected void write(File file, String content) {
  400. try {
  401. FileOutputStream fw = new FileOutputStream(file);
  402. OutputStreamWriter outstream = new OutputStreamWriter(fw, "utf-8");
  403. BufferedWriter out = new BufferedWriter(outstream);
  404. out.write(content);
  405. out.close();
  406. } catch (IOException e) {
  407. _log.error("Problem writing to file: " + file.getAbsolutePath());
  408. e.printStackTrace();
  409. }
  410. }
  411. public void showPages() {
  412. _log.debug("---------Pages-----------");
  413. for (WikiPage page : pageList) {
  414. _log.info(page);
  415. if (!page.showChildren().isEmpty()) {
  416. _log.info(page.showChildren());
  417. }
  418. }
  419. }
  420. public void showPagesNoParentTitle() {
  421. _log.info("---------showPagesNoParentTitle-----------");
  422. for (WikiPage page : pageList) {
  423. if (page.get__parentTitle().isEmpty()) {
  424. _log.debug(page);
  425. }
  426. }
  427. }
  428. }