fitnesse.wiki.FileSystemPage.java Source code

Java tutorial

Introduction

Here is the source code for fitnesse.wiki.FileSystemPage.java

Source

// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.wiki;

import com.google.inject.Injector;
import fitnesse.wikitext.WikiWordUtil;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.*;

import java.io.*;
import java.lang.reflect.Method;
import java.util.Date;

import static org.apache.commons.lang.StringUtils.isEmpty;

public class FileSystemPage extends CachingPage {
    private static final Logger logger = LoggerFactory.getLogger(FileSystemPage.class);
    private static final long serialVersionUID = 1L;

    public static final String contentFilename = "/content.txt";
    public static final String propertiesFilename = "/properties.xml";

    private final String path;
    private final VersionsController versionsController;
    private final CmSystem cmSystem = new CmSystem();
    private transient final Clock clock;

    public static WikiPage makeRoot(Injector injector, String rootPath, String rootPageName) throws IOException {
        return new FileSystemPage(rootPath, rootPageName, injector.getInstance(FileSystem.class),
                injector.getInstance(VersionsController.class), injector, injector.getInstance(Clock.class));
    }

    private FileSystemPage(final String path, final String name, final FileSystem fileSystem,
            final VersionsController versionsController, Injector injector, Clock clock) throws IOException {
        super(name, null, injector);
        this.path = path;
        this.versionsController = versionsController;
        createDirectoryIfNewPage(fileSystem);
        this.clock = clock;
    }

    public FileSystemPage(final String name, final FileSystemPage parent, final FileSystem fileSystem, Clock clock,
            Injector injector) throws IOException {
        super(name, parent, injector);
        path = parent.getFileSystemPath();
        versionsController = parent.versionsController;
        createDirectoryIfNewPage(fileSystem);
        this.clock = clock;
    }

    @Override
    public void removeChildPage(final String name) {
        super.removeChildPage(name);
        String pathToDelete = getFileSystemPath() + "/" + name;
        final File fileToBeDeleted = new File(pathToDelete);
        cmSystem.preDelete(pathToDelete);
        FileUtil.deleteFileSystemDirectory(fileToBeDeleted);
        cmSystem.delete(pathToDelete);
    }

    @Override
    public boolean hasChildPage(final String pageName) throws IOException {
        final File f = new File(getFileSystemPath() + "/" + pageName);
        if (f.exists()) {
            addChildPage(pageName);
            return true;
        }
        return false;
    }

    protected synchronized void saveContent(String content) throws IOException {
        if (content == null) {
            return;
        }

        final String separator = System.getProperty("line.separator");

        if (content.endsWith("|")) {
            content += separator;
        }

        //First replace every windows style to unix
        content = content.replaceAll("\r\n", "\n");
        //Then do the replace to match the OS.  This works around
        //a strange behavior on windows.
        content = content.replaceAll("\n", separator);

        String contentPath = getFileSystemPath() + contentFilename;
        final File output = new File(contentPath);
        OutputStreamWriter writer = null;
        try {
            if (output.exists())
                cmSystem.edit(contentPath);
            writer = new OutputStreamWriter(new FileOutputStream(output), "UTF-8");
            writer.write(content);
        } catch (UnsupportedEncodingException e) {
            throw new ImpossibleException("UTF-8 is a supported encoding", e);
        } finally {
            if (writer != null) {
                IOUtils.closeQuietly(writer);
                cmSystem.update(contentPath);
            }
        }
    }

    protected synchronized void saveAttributes(final WikiPageProperties attributes) throws IOException {
        OutputStream output = null;
        String propertiesFilePath = "<unknown>";
        try {
            propertiesFilePath = getFileSystemPath() + propertiesFilename;
            File propertiesFile = new File(propertiesFilePath);
            if (propertiesFile.exists())
                cmSystem.edit(propertiesFilePath);
            output = new FileOutputStream(propertiesFile);
            WikiPageProperties propertiesToSave = new WikiPageProperties(attributes);
            removeAlwaysChangingProperties(propertiesToSave);
            propertiesToSave.save(output);
        } catch (final IOException e) {
            logger.error("Failed to save properties file: \"" + propertiesFilePath, e);
            throw e;
        } catch (final RuntimeException e) {
            logger.error("Failed to save properties file: \"" + propertiesFilePath, e);
            throw e;
        } finally {
            if (output != null) {
                output.close();
                cmSystem.update(propertiesFilePath);
            }
        }
    }

    private void removeAlwaysChangingProperties(WikiPageProperties properties) {
        properties.remove(PageData.PropertyLAST_MODIFIED);
    }

    @Override
    protected WikiPage createChildPage(final String name) throws IOException {
        //return new FileSystemPage(getFileSystemPath(), name, this, this.versionsController);
        return new PageRepository(new DiskFileSystem()).makeChildPage(name, this);
    }

    private void loadContent(final PageData data) throws IOException {
        final File input = new File(getFileSystemPath() + contentFilename);
        data.setContent(input.exists() ? readContent(input) : "");
    }

    @Override
    protected void loadChildren() throws IOException {
        final File thisDir = new File(getFileSystemPath());
        if (thisDir.exists()) {
            final String[] subFiles = thisDir.list();
            for (final String subFile : subFiles) {
                if (fileIsValid(subFile, thisDir) && !this.children.containsKey(subFile)) {
                    this.children.put(subFile, getChildPage(subFile));
                }
            }
        }
    }

    private String readContent(final File input) throws IOException {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(input);
            return IOUtils.toString(inputStream, "UTF-8");
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    private boolean fileIsValid(final String filename, final File dir) {
        if (WikiWordUtil.isWikiWord(filename)) {
            final File f = new File(dir, filename);
            if (f.isDirectory()) {
                return true;
            }
        }
        return false;
    }

    private String getParentFileSystemPath() {
        return this.parent != null ? ((FileSystemPage) this.parent).getFileSystemPath() : this.path;
    }

    public String getFileSystemPath() {
        return getParentFileSystemPath() + "/" + getName();
    }

    private void loadAttributes(final PageData data) {
        final File file = new File(getFileSystemPath() + propertiesFilename);
        if (file.exists()) {
            try {
                long lastModifiedTime = getLastModifiedTime();
                attemptToReadPropertiesFile(file, data, lastModifiedTime);
            } catch (final Exception e) {
                logger.error("Could not read properties file: " + file.getPath(), e);
            }
        }
    }

    private long getLastModifiedTime() throws Exception {
        long lastModifiedTime;

        final File file = new File(getFileSystemPath() + contentFilename);
        if (file.exists()) {
            lastModifiedTime = file.lastModified();
        } else {
            lastModifiedTime = getClock().currentClockTimeInMillis();
        }
        return lastModifiedTime;
    }

    private void attemptToReadPropertiesFile(File file, PageData data, long lastModifiedTime) throws Exception {
        InputStream input = null;
        try {
            final WikiPageProperties props = new WikiPageProperties();
            input = new FileInputStream(file);
            props.loadFromXmlStream(input);
            props.setLastModificationTime(new Date(lastModifiedTime));
            data.setProperties(props);
        } finally {
            if (input != null)
                input.close();
        }
    }

    @Override
    public void doCommit(final PageData data) throws IOException {
        saveContent(data.getContent());
        saveAttributes(data.getProperties());
        this.versionsController.prune(this);
    }

    @Override
    protected PageData makePageData() throws IOException {
        final PageData pagedata = new PageData(this);
        loadContent(pagedata);
        loadAttributes(pagedata);
        pagedata.addVersions(this.versionsController.history(this));
        return pagedata;
    }

    public PageData getDataVersion(final String versionName) {
        return this.versionsController.getRevisionData(this, versionName);
    }

    private void createDirectoryIfNewPage(FileSystem fileSystem) throws IOException {
        String pagePath = getFileSystemPath();
        if (!fileSystem.exists(pagePath)) {
            fileSystem.makeDirectory(pagePath);
            cmSystem.update(pagePath);
        }
    }

    @Override
    protected VersionInfo makeVersion() throws IOException {
        final PageData data = getData();
        return makeVersion(data);
    }

    protected VersionInfo makeVersion(final PageData data) {
        return this.versionsController.makeVersion(this, data);
    }

    protected void removeVersion(final String versionName) {
        this.versionsController.removeVersion(this, versionName);
    }

    @Override
    public String toString() {
        try {
            return getClass().getName() + " at " + this.getFileSystemPath();
        } catch (final Exception e) {
            return super.toString();
        }
    }

    public Clock getClock() {
        return clock;
    }

    class CmSystem {
        public void update(String fileName) {
            invokeCmMethod("cmUpdate", fileName);
        }

        public void edit(String fileName) {
            invokeCmMethod("cmEdit", fileName);
        }

        public void delete(String fileToBeDeleted) {
            invokeCmMethod("cmDelete", fileToBeDeleted);
        }

        public void preDelete(String fileToBeDeleted) {
            invokeCmMethod("cmPreDelete", fileToBeDeleted);
        }

        private void invokeCmMethod(String method, String newPagePath) {
            String cmSystemClassName = null;
            try {
                cmSystemClassName = getCmSystemClassName();
                if (cmSystemClassName != null) {
                    Class<?> cmSystem = Class.forName(getCmSystemClassName());
                    Method updateMethod = cmSystem.getMethod(method, String.class, String.class);
                    updateMethod.invoke(null, newPagePath, getCmSystemVariable());
                }
            } catch (Exception e) {
                System.err.println("Could not invoke static " + method + "(path,payload) of " + cmSystemClassName);
                e.printStackTrace();
            }
        }

        private String getCmSystemClassName() throws Exception {
            String cmSystemVariable = getCmSystemVariable();
            if (cmSystemVariable == null)
                return null;
            String cmSystemClassName = cmSystemVariable.split(" ")[0].trim();
            if (isEmpty(cmSystemClassName))
                return null;

            return cmSystemClassName;
        }

        private String getCmSystemVariable() throws IOException {
            return getData().getVariable("CM_SYSTEM");
        }
    }
}