blob: 2672ac3beacd0227a88f6064ae631044475947f8 [file] [log] [blame]
package com.atlassian.uwc.exporters.liferay.digester;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.log4j.Logger;
/**
* Liferay (LR) wiki page processor.
*
* @author Developer
*
*/
public class LrWikiTree {
public static final String FRONTPAGE = "FrontPage";
private ArrayList<WikiPage> pageList = new ArrayList<WikiPage>();
private static Logger _log = Logger.getLogger(LrWikiTree.class);
/**
* Adds pages to the internal page list. We only keep the current page and discard historical pages.
*
* @param page
*/
public void addPage(WikiPage page) {
// if we have an existing page check the version and discard ancient pages
WikiPage wp = findPage(page.get__title());
if (wp != null) {
Double version = wp.getVersion();
// only keep latest version of the page
if (page.getVersion() > version) {
pageList.remove(wp);
pageList.add(page);
}
} else {
// no previous version so add the page
// _log.debug("Adding Page: " + page.get__title());
pageList.add(page);
}
}
/**
* Finds pages that don't have parents and are not named Frontpage.
*
* @return
*/
public ArrayList<WikiPage> findOrphans() {
ArrayList<WikiPage> retval = new ArrayList<WikiPage>();
for (WikiPage page : pageList) {
String parentTitle = page.get__parentTitle();
if (parentTitle.isEmpty() && !page.get__title().equals(FRONTPAGE)) {
retval.add(page);
} else if (!page.get__redirectTitle().isEmpty()) {
retval.add(page);
}
}
return retval;
}
/**
* Creates a page in the home directory that will hold all the orphans. Also creates the directory structure on disk
* for the pages.
*
* @param outputDir
* @throws IOException
*/
public void createUncategorizedChildPage(String outputDir, String orphanPage) throws IOException {
String uncategorizedPage = "== Overview ==\r\n\r\nPages that don't have parents are placed here after transfering the Wiki into Confluence.";
File dir = new File(outputDir);
dir.mkdirs();
File unCat = new File(outputDir + File.separator + orphanPage);
write(unCat, uncategorizedPage);
}
/**
* Copies the page content of the files in the list to the output directory.
*
* @param list
* @param outputDir
* @throws IOException
*/
public void saveOrphanList(ArrayList<WikiPage> list, String outputDir, boolean original) throws IOException {
for (WikiPage page : list) {
page.setDepth(0); // page is an orphan so reset it's place to the root in the hierarchy
recursePages(page);
page.setPath("");
page.setOutDir(new File(outputDir));
saveOrphanRecursive(page, original);
}
}
/**
* Writes the content of the orphaned pages onto the Uncategorized directory. Child pages are written maintaining
* the hierarchy in the file system.
*
* @param frontPage
* @param copyOriginal
* true to copy the original xml file to the destination
* @throws IOException
*/
public void saveOrphanRecursive(WikiPage frontPage, boolean copyOriginal) throws IOException {
String padding = "";
for (int i = 0; i < frontPage.getDepth(); i++) {
padding += " ";
}
_log.info(padding + frontPage.get__title());
File dir = new File(frontPage.getOutDir() + File.separator + frontPage.getPath());
dir.mkdirs();
// _log.info("++" + dir.getCanonicalPath());
// _log.debug("Create Dir: " + dir);
if (copyOriginal) {
copyFile(frontPage.getFile(), new File(dir, frontPage.get__title() + ".xml"));
} else {
File filePage = new File(dir, frontPage.get__title());
write(filePage, frontPage.get__content());
}
if (!frontPage.getAttachments().isEmpty()) {
_log.info(padding + " " + frontPage.getAttachments().size() + "-Attachments " + frontPage.getAttachments());
}
for (WikiPage page : frontPage.getChildren()) {
page.setPath(frontPage.getPath());
page.setOutDir(frontPage.getOutDir());
saveRecursive(page, copyOriginal);
}
}
/**
* Removes the parent child relationship for the given pages.
*
* @param pages
*/
public void unlinkChildren(ArrayList<WikiPage> pages) {
for (WikiPage page : pages) {
_log.debug("Removing page '" + page.get__title() + "'");
if (!pageList.remove(page)) {
_log.error("Can't remove: " + page.get__title());
}
// We also need to remove the child from the parent child relationship
WikiPage parent = findPage(page.get__parentTitle());
if (parent != null) {
if (!parent.removeChild(page)) {
_log.error("Can't remove child from parent: " + page.get__parentTitle());
}
}
}
}
public WikiPage findPage(String title) {
WikiPage retval = null;
for (WikiPage page : pageList) {
if (page.get__title().equals(title)) {
retval = page;
break;
}
}
return retval;
}
/**
* Creates a parent child relationship with the internal pages.
*
* @param sort
*/
public void linkChildren(boolean sort) {
if (sort) {
Collections.sort(pageList);
}
for (WikiPage page : pageList) {
String parentTitle = page.get__parentTitle();
if (!parentTitle.isEmpty()) {
WikiPage parent = findPage(parentTitle);
if (parent != null) {
parent.addChildPage(page);
} else {
_log.debug("!!!Error finding Parent!!! " + parentTitle);
}
}
}
}
/**
* copies all the attachments for all the pages into the given directory.
*
* @param larDirectory
* @param destDirName
* @throws IOException
*/
public void saveAttachments(String larDirectory, String destDirName) throws IOException {
File destDir = new File(destDirName);
destDir.mkdirs();
_log.info("Copying attachments to: " + destDirName);
for (WikiPage page : pageList) {
ArrayList<Attachment> files = page.getAttachments();
for (Attachment attachment : files) {
String name = attachment.getBinPath();
copyFile(new File(larDirectory, name), new File(destDir, attachment.getName()));
}
}
}
/**
* Attachments in the LR export are indistinguishable from links. The function looks for [[xxx]], where xxx is an
* attachment and changes the download link to [^xxx]. This makes the UWC
* com.atlassian.uwc.hierarchies.FilepathHierarchy class upload the attachment.
*
* Image conversion {{image.jpg}} -> !image.jpg! is also handled here for the same reason as above.
*
*/
public void reformatAttachments() {
for (WikiPage page : pageList) {
ArrayList<Attachment> files = page.getAttachments();
for (Attachment attachment : files) {
String name = attachment.getName();
String content = page.get__content();
if (content.indexOf(name) > 0) {
String replace = convertAttachLink(content, name);
replace = convertImageLink(replace, name);
page.set__content(replace);
}
}
}
}
/**
* [[link]] converts to [^link] and [[link|link name]] converts to [^link]
*
* Linking to an attachment in LR stopped working after the SP2 upgrade but we still use this mechanism to mark
* attachments for inclusion in Confluence.
*
* @param content
* @param name
* @return
*/
public String convertAttachLink(String content, String name) {
String retval = content;
// [[attach] -> [^attach]
retval = content.replaceAll("\\[\\[" + name + "\\]\\]", "[^" + name + "]");
// [[attach|attach name]] -> [^attach]
// // "\\[\\[" + // opening left brackets
// // name is captured by replaceAll
// // "\\|" + // until a pipe
// // "[^\\]|]+" + // anything but a right bracket or | until
// // "\\]\\]"; // right brackets
retval = retval.replaceAll("\\[\\[" + name + "\\|[^\\]|]*]]", "[^" + name + "]");
return retval;
}
/**
* {{image.jpg}} is display image in LR - in Confluence its !image.jpg! We do this here as we can find out if it's
* an image by looking at the attachments.
*
* @param content
* @param name
* @return
*/
public String convertImageLink(String content, String name) {
return content.replaceFirst("\\{\\{" + name + "\\}\\}", "!" + name + "!");
}
/**
* Html formatted pages need to be surrounded with {html}
*
* @param noHtml
* if true encloses the html fragment inside a code block this disables HTML rendering in Confluence
*/
public void reformatHtmlPages(boolean noHtml) {
for (WikiPage page : pageList) {
String format = page.get__format();
if (format.equalsIgnoreCase("html")) {
if (noHtml) {
_log.debug("Disabling html formatting for page: " + page.get__title());
String content = page.get__content();
page.set__content("{code} " + content + "{code}");
} else {
_log.debug("Adding html formatting for page: " + page.get__title());
String content = page.get__content();
page.set__content("{html} " + content + "{html}");
}
} else if (format.equalsIgnoreCase("creole")) {
// This is the stuff we are expecting
} else {
_log.warn("Unsupported format detected: " + format);
}
}
}
/**
* Sets the depth value for the pages in the hierarchy.
*
* @param frontPage
*/
public void recursePages(WikiPage frontPage) {
for (WikiPage page : frontPage.getChildren()) {
// if(page.get__title().contains("Admin")){
// _log.debug("!break " );
// }
page.setDepth(frontPage.getDepth() + 1);
recursePages(page);
}
}
/**
* Prints out the current tree structure.
*
* @param frontPage
*/
public void showRecursive(WikiPage frontPage) {
String padding = "";
for (int i = 0; i < frontPage.getDepth(); i++) {
padding += " ";
}
_log.info(padding + frontPage.get__title());
if (!frontPage.getAttachments().isEmpty()) {
_log.info(padding + " " + frontPage.getAttachments().size() + "-Attachments " + frontPage.getAttachments());
}
for (WikiPage page : frontPage.getChildren()) {
showRecursive(page);
}
}
/**
* Copy the current pagelist original files into the given directory.
*
* @param dir
* @throws IOException
*/
public void copyTo(String dir) throws IOException {
File destDir = new File(dir);
destDir.mkdir();
_log.info("Copying " + pageList.size() + " current pages to: " + dir);
for (WikiPage page : pageList) {
_log.info("XML Path: " + page.getFile().getAbsolutePath());
copyFile(page.getFile(), new File(destDir, page.get__title() + ".xml"));
}
}
/**
* Copy the source file to the destination overwriting the file if it exists.
*
* @param sourceFile
* @param destFile
* @throws IOException
*/
public static void copyFile(File sourceFile, File destFile) throws IOException {
copyFile(sourceFile, destFile, true);
}
/**
* Copy the source file to the destination.
*
* @param sourceFile
* @param destFile
* @param overwrite
* overwrite the file if true.
* @throws IOException
*/
public static void copyFile(File sourceFile, File destFile, boolean overwrite) throws IOException {
if (!destFile.exists()) {
destFile.createNewFile();
} else {
if (!overwrite) {
throw new IOException("Destination file exists! " + destFile);
}
_log.trace("Destination file exists: " + destFile);
}
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
/**
* Writes the content of the pages of the Wiki onto the directory, maintaining the hierarchy structure in the file
* system.
*
* @param frontPage
* @param copyOriginal
* true to copy the original xml file to the destination
* @throws IOException
*/
public void saveRecursive(WikiPage frontPage, boolean copyOriginal) throws IOException {
String padding = "";
for (int i = 0; i < frontPage.getDepth(); i++) {
padding += " ";
}
_log.info(padding + frontPage.get__title());
File dir = new File(frontPage.getOutDir() + File.separator + frontPage.getPath(), frontPage.get__title());
dir.mkdirs();
// _log.debug("Create Dir: " + dir);
if (copyOriginal) {
copyFile(frontPage.getFile(), new File(dir, frontPage.get__title() + ".xml"));
} else {
File filePage = new File(dir, frontPage.get__title());
write(filePage, frontPage.get__content());
}
if (!frontPage.getAttachments().isEmpty()) {
_log.info(padding + " " + frontPage.getAttachments().size() + "-Attachments " + frontPage.getAttachments());
}
for (WikiPage page : frontPage.getChildren()) {
page.setPath(frontPage.getPath() + File.separator + frontPage.get__title());
page.setOutDir(frontPage.getOutDir());
saveRecursive(page, copyOriginal);
}
}
protected void write(File file, String content) {
try {
FileOutputStream fw = new FileOutputStream(file);
OutputStreamWriter outstream = new OutputStreamWriter(fw, "utf-8");
BufferedWriter out = new BufferedWriter(outstream);
out.write(content);
out.close();
} catch (IOException e) {
_log.error("Problem writing to file: " + file.getAbsolutePath());
e.printStackTrace();
}
}
public void showPages() {
_log.debug("---------Pages-----------");
for (WikiPage page : pageList) {
_log.info(page);
if (!page.showChildren().isEmpty()) {
_log.info(page.showChildren());
}
}
}
public void showPagesNoParentTitle() {
_log.info("---------showPagesNoParentTitle-----------");
for (WikiPage page : pageList) {
if (page.get__parentTitle().isEmpty()) {
_log.debug(page);
}
}
}
}