package fitnesse.wiki.fs;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import fitnesse.ConfigurationParameter;
import fitnesse.components.ComponentFactory;
import fitnesse.wiki.PathParser;
import fitnesse.wiki.WikiPage;
import fitnesse.wiki.WikiPageFactory;
import fitnesse.wiki.WikiPageFactoryRegistry;
import fitnesse.wikitext.parser.Maybe;
import fitnesse.wikitext.parser.VariableSource;
/**
* This is the general factory used to load and create wiki pages.
*
* For historic reasons it's still called FileSystemPageFactory, although it deals with all
* file based page types (FileSystemPage, WikiFilePage, ExternalSuitePage).
*/
public class FileSystemPageFactory implements WikiPageFactory, WikiPageFactoryRegistry {
private final FileSystem fileSystem;
private final VersionsController versionsController;
private final List<WikiPageFactory> wikiPageFactories = new ArrayList<>();
private final WikiPageFactory fallbackPageFactory;
public FileSystemPageFactory() {
this(new DiskFileSystem(), new ZipFileVersionsController());
}
public FileSystemPageFactory(Properties properties) {
this(new DiskFileSystem(), new ComponentFactory(properties).createComponent(
ConfigurationParameter.VERSIONS_CONTROLLER_CLASS, ZipFileVersionsController.class));
}
public FileSystemPageFactory(FileSystem fileSystem, VersionsController versionsController) {
this(fileSystem, versionsController, RootWikiFilePageFactory.class);
}
protected FileSystemPageFactory(FileSystem fileSystem, VersionsController versionsController, Class<? extends WikiPageFactory> fallbackPageFactoryClass) {
this.fileSystem = fileSystem;
this.versionsController = versionsController;
this.fallbackPageFactory = instantiateFallbackPageFactory(fallbackPageFactoryClass);
initializeWikiPageFactories();
}
private WikiPageFactory instantiateFallbackPageFactory(Class<? extends WikiPageFactory> fallbackPageFactoryClass) {
try {
Constructor<? extends WikiPageFactory> ctor = fallbackPageFactoryClass.getDeclaredConstructor(FileSystemPageFactory.class);
return ctor.newInstance(this);
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) {
throw new IllegalStateException("Cannot instantiate wiki page factory", e);
}
}
private void initializeWikiPageFactories() {
registerWikiPageFactory(new InnerFileSystemPageFactory());
registerWikiPageFactory(new WikiFilePageFactory());
registerWikiPageFactory(new ChildWikiFilePageFactory());
registerWikiPageFactory(new RootWikiFilePageFactory());
// Note: ExternalSuitePageFactory should be last in line: it traverses the remainder of the tree looking for .html files.
registerWikiPageFactory(new ExternalSuitePageFactory(fileSystem));
}
@Override // from WikiPageFactoryRegistry
public void registerWikiPageFactory(WikiPageFactory wikiPageFactory) {
wikiPageFactories.add(wikiPageFactory);
}
@Override // from WikiPageFactory
public boolean supports(File path) {
for (WikiPageFactory factory : wikiPageFactories) {
if (factory.supports(path)) {
return true;
}
}
return false;
}
@Override // from WikiPageFactory
public WikiPage makePage(File path, String pageName, WikiPage parent, VariableSource variableSource) {
for (WikiPageFactory factory : wikiPageFactories) {
if (factory.supports(path)) {
return factory.makePage(path, pageName, parent, variableSource);
}
}
// Treat top level and intermediate empty directories as valid pages
if (parent == null || (parent instanceof FileBasedWikiPage && isWikiWordDirectory(path)))
return fallbackPageFactory.makePage(path, pageName, parent, variableSource);
return null;
}
private boolean isWikiWordDirectory(final File path) {
return fileSystem.isDirectory(path) && PathParser.isSingleWikiWord(path.getName());
}
VersionsController getVersionsController() {
return versionsController;
}
/**
* This is the class that does the sole handling of FileSystemPages
*/
protected class InnerFileSystemPageFactory implements WikiPageFactory {
@Override
public WikiPage makePage(final File path, final String pageName, final WikiPage parent, final VariableSource variableSource) {
Maybe<String> rootPath = variableSource.findVariable("FITNESSE_ROOTPATH");
return new FileSystemPage(path, pageName, parent, null, versionsController,
new FileSystemSubWikiPageFactory(new File(rootPath.getValue()), fileSystem, variableSource, FileSystemPageFactory.this),
variableSource);
}
@Override
public boolean supports(File path) {
String[] children = fileSystem.list(path);
for (String child : children) {
if (child.equals(FileSystemPage.contentFilename)) return true;
}
return false;
}
}
protected class WikiFilePageFactory implements WikiPageFactory {
@Override
public WikiPage makePage(final File path, final String pageName, final WikiPage parent, final VariableSource variableSource) {
Maybe<String> rootPath = variableSource.findVariable("FITNESSE_ROOTPATH");
return new WikiFilePage(path, pageName.substring(0, pageName.length() - WikiFilePage.FILE_EXTENSION.length()), parent, null, versionsController,
new FileSystemSubWikiPageFactory(new File(rootPath.getValue()), fileSystem, variableSource, FileSystemPageFactory.this),
variableSource);
}
@Override
public boolean supports(File path) {
return path.getPath().endsWith(WikiFilePage.FILE_EXTENSION) &&
!WikiFilePage.ROOT_FILE_NAME.equals(path.getName()) &&
fileSystem.exists(path) &&
!fileSystem.isDirectory(path);
}
}
protected class ChildWikiFilePageFactory implements WikiPageFactory {
@Override
public WikiPage makePage(final File path, final String pageName, final WikiPage parent, final VariableSource variableSource) {
Maybe<String> rootPath = variableSource.findVariable("FITNESSE_ROOTPATH");
return new WikiFilePage(wikiFile(path), pageName, parent, null, versionsController,
new FileSystemSubWikiPageFactory(new File(rootPath.getValue()), fileSystem, variableSource, FileSystemPageFactory.this),
variableSource);
}
private File wikiFile(final File path) {
return new File(path.getPath() + WikiFilePage.FILE_EXTENSION);
}
@Override
public boolean supports(File path) {
File wikiFile = wikiFile(path);
return fileSystem.exists(wikiFile) && !fileSystem.isDirectory(wikiFile);
}
}
protected class RootWikiFilePageFactory implements WikiPageFactory {
@Override
public WikiPage makePage(final File path, final String pageName, final WikiPage parent, final VariableSource variableSource) {
Maybe<String> rootPath = variableSource.findVariable("FITNESSE_ROOTPATH");
return new WikiFilePage(new File(path, WikiFilePage.ROOT_FILE_NAME), pageName, parent, null, versionsController,
new FileSystemSubWikiPageFactory(new File(rootPath.getValue()), fileSystem, variableSource, FileSystemPageFactory.this),
variableSource);
}
@Override
public boolean supports(File path) {
File rootWikiFile = new File(path, WikiFilePage.ROOT_FILE_NAME);
return fileSystem.exists(rootWikiFile) && !fileSystem.isDirectory(rootWikiFile);
}
}
}