fitnesse.wiki.fs.WikiFilePage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fitnesse Show documentation
Show all versions of fitnesse Show documentation
The fully integrated standalone wiki, and acceptance testing framework.
package fitnesse.wiki.fs;
import fitnesse.wiki.*;
import fitnesse.wikitext.parser.*;
import org.apache.commons.lang3.StringUtils;
import util.FileUtil;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import static fitnesse.util.StringUtils.isBlank;
import static java.lang.String.format;
/**
* With this page all content is saved in one file: WikiPageName.wiki.
* Sub wiki's are stored as WikiPageMame/SubWiki.wiki.
* This format should eventually replace the {@link FileSystemPage}.
*/
public class WikiFilePage extends BaseWikitextPage implements FileBasedWikiPage {
public static final String FILE_EXTENSION = ".wiki";
public static final String ROOT_FILE_NAME = "_root" + FILE_EXTENSION;
private static final SymbolProvider WIKI_FILE_PARSING_PROVIDER = new SymbolProvider( new SymbolType[] {
FrontMatter.symbolType, SymbolType.Text});
private final File path;
private final VersionsController versionsController;
private final SubWikiPageFactory subWikiPageFactory;
private final String versionName;
private PageData pageData;
protected WikiFilePage(final File path, final String name, final WikiPage parent,
final String versionName, final VersionsController versionsController,
final SubWikiPageFactory subWikiPageFactory, final VariableSource variableSource) {
super(name, parent, variableSource);
this.path = path;
this.versionsController = versionsController;
this.subWikiPageFactory = subWikiPageFactory;
this.versionName = versionName;
}
private WikiFilePage(WikiFilePage page, String versionName) {
this(page.path, page.getName(), (page.isRoot() ? null : page.getParent()), versionName,
page.versionsController, page.subWikiPageFactory, page.getVariableSource());
}
@Override
public WikiPage addChildPage(final String childName) {
return new WikiFilePage(new File(getFileSystemPath(), childName + FILE_EXTENSION), childName, this, null, this.versionsController, this.subWikiPageFactory, this.getVariableSource());
}
private File getSubWikiFolder() {
return path;
}
@Override
public WikiPage getChildPage(final String childName) {
return subWikiPageFactory.getChildPage(this, childName);
}
@Override
public void removeChildPage(final String name) {
final WikiPage childPage = getChildPage(name);
if (childPage != null) {
childPage.remove();
}
}
@Override
public void remove() {
try {
versionsController.delete(path, getFileSystemPath());
} catch (IOException e) {
throw new WikiPageLoadException(format("Could not remove page %s", new WikiPagePath(this).toString()), e);
}
}
@Override
public List getChildren() {
return subWikiPageFactory.getChildren(this);
}
@Override
public PageData getData() {
if (pageData == null) {
try {
pageData = getDataVersion();
} catch (IOException e) {
throw new WikiPageLoadException("Could not load page data for page " + path.getPath(), e);
}
}
return new PageData(pageData);
}
@Override
public Collection getVersions() {
return versionsController.history(path);
}
@Override
public WikiPage getVersion(final String versionName) {
try {
versionsController.getRevisionData(versionName, path);
} catch (IOException e) {
throw new WikiPageLoadException(format("Could not load version %s for page at %s", versionName, path.getPath()), e);
}
return new WikiFilePage(this, versionName);
}
@Override
public VersionInfo commit(final PageData data) {
resetCache();
try {
return versionsController.makeVersion(new WikiFilePageVersion(data));
} catch (IOException e) {
throw new WikiPageLoadException(e);
}
}
@Override
public File getFileSystemPath() {
if (ROOT_FILE_NAME.equals(path.getName())) {
return path.getParentFile();
} else {
String pathStr = this.path.getPath();
return new File(pathStr.substring(0, pathStr.length() - FILE_EXTENSION.length()));
}
}
@Override
protected void resetCache() {
super.resetCache();
pageData = null;
}
private PageData getDataVersion() throws IOException {
FileVersion[] versions = versionsController.getRevisionData(versionName, path);
FileVersion fileVersion = versions[0];
String content = "";
WikiPageProperty properties = defaultPageProperties();
if (fileVersion != null) {
try {
String fileContent = loadContent(fileVersion);
final ParsingPage parsingPage = makeParsingPage(this);
final Symbol syntaxTree = Parser.make(parsingPage, fileContent, WIKI_FILE_PARSING_PROVIDER).parse();
if (!syntaxTree.getChildren().isEmpty()) {
final Symbol maybeFrontMatter = syntaxTree.getChildren().get(0);
if (maybeFrontMatter.isType(FrontMatter.symbolType)) {
properties = mergeWikiPageProperties(properties, maybeFrontMatter);
if (syntaxTree.getChildren().size() > 1) {
content = fileContent.substring(maybeFrontMatter.getEndOffset());
}
} else {
content = fileContent;
}
}
properties.setLastModificationTime(fileVersion.getLastModificationTime());
} catch (IOException e) {
throw new WikiPageLoadException(e);
}
}
pageData = new PageData(content, properties);
return pageData;
}
private WikiPageProperty mergeWikiPageProperties(final WikiPageProperty properties, final Symbol frontMatter) {
for (Symbol keyValue : frontMatter.getChildren()) {
if (keyValue.isType(FrontMatter.keyValueSymbolType)) {
String key = keyValue.getChildren().get(0).getContent();
String value = keyValue.getChildren().get(1).getContent();
if (isBooleanProperty(key)) {
if (isBlank(value) || isTruthy(value)) {
properties.set(key, value);
} else if (isFalsy(value)) {
properties.remove(key);
}
} else {
WikiPageProperty symLinks = properties.set(key, value);
for (int i = 2; i < keyValue.getChildren().size(); i++) {
final Symbol subProperty = keyValue.getChildren().get(i);
assert subProperty.isType(FrontMatter.keyValueSymbolType);
String linkName = subProperty.getChildren().get(0).getContent();
String linkPath = subProperty.getChildren().get(1).getContent();
symLinks.set(linkName, linkPath);
}
}
}
}
return properties;
}
private boolean isBooleanProperty(final String key) {
return qualifiesAs(key, PageData.PAGE_TYPE_ATTRIBUTES) ||
qualifiesAs(key, PageData.NON_SECURITY_ATTRIBUTES) ||
qualifiesAs(key, PageData.SECURITY_ATTRIBUTES);
}
private boolean isTruthy(final String value) {
return qualifiesAs(value.toLowerCase(), new String[]{"y", "yes", "t", "true", "1"});
}
private boolean isFalsy(final String value) {
return qualifiesAs(value.toLowerCase(), new String[]{"n", "no", "f", "false", "0"});
}
private boolean qualifiesAs(final String value, final String[] qualifiers) {
for (String q : qualifiers) {
if (q.equals(value)) return true;
}
return false;
}
private String loadContent(final FileVersion fileVersion) throws IOException {
try (InputStream content = fileVersion.getContent()) {
return FileUtil.toString(content);
}
}
private String propertiesYaml(final WikiPageProperty pageProperties) {
final WikiPageProperty defaultProperties = defaultPageProperties();
final List lines = new ArrayList<>();
for (String key : pageProperties.keySet()) {
if (isBooleanProperty(key)) {
if (!defaultProperties.has(key)) {
lines.add(key);
}
} else if (!WikiPageProperty.LAST_MODIFIED.equals(key)) {
final StringBuilder builder = new StringBuilder();
builder.append(key);
if (!isBlank(pageProperties.get(key))) {
builder.append(": ").append(pageProperties.get(key));
}
final WikiPageProperty subProperty = pageProperties.getProperty(key);
for (String pageName: subProperty.keySet()) {
builder.append("\n ").append(pageName).append(": ").append(subProperty.get(pageName));
}
lines.add(builder.toString());
}
}
for (String key : defaultProperties.keySet()) {
if (isBooleanProperty(key) && !pageProperties.has(key)) {
lines.add(key + ": no");
}
}
Collections.sort(lines);
return lines.isEmpty() ? "" : "---\n" + StringUtils.join(lines, '\n') + "\n---\n";
}
private class WikiFilePageVersion implements FileVersion {
private final PageData data;
public WikiFilePageVersion(final PageData data) {
this.data = new PageData(data);
}
@Override
public File getFile() {
return path;
}
@Override
public InputStream getContent() throws IOException {
String yaml = propertiesYaml(data.getProperties());
final String content = yaml + data.getContent();
return new ByteArrayInputStream(content.getBytes(FileUtil.CHARENCODING));
}
@Override
public String getAuthor() {
return data.getAttribute(WikiPageProperty.LAST_MODIFYING_USER);
}
@Override
public Date getLastModificationTime() {
return data.getProperties().getLastModificationTime();
}
}
}