// 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 fitnesse.responders.run.ExecutionLog; import static fitnesse.wiki.PageType.*; import fitnesse.wikitext.parser.*; import fitnesse.wikitext.parser.HtmlTranslator; import fitnesse.wikitext.parser.Paths; import util.Clock; import util.Maybe; import util.StringUtil; import java.io.Serializable; import java.util.*; @SuppressWarnings("unchecked") public class PageData implements ReadOnlyPageData, Serializable { private static final long serialVersionUID = 1L; // TODO: Find a better place for us public static final String PropertyLAST_MODIFIED = "LastModified"; public static final String PropertyHELP = "Help"; public static final String PropertyPRUNE = "Prune"; public static final String PropertySEARCH = "Search"; public static final String PropertyRECENT_CHANGES = "RecentChanges"; public static final String PropertyFILES = "Files"; public static final String PropertyWHERE_USED = "WhereUsed"; public static final String PropertyREFACTOR = "Refactor"; public static final String PropertyPROPERTIES = "Properties"; public static final String PropertyVERSIONS = "Versions"; public static final String PropertyEDIT = "Edit"; public static final String PropertySUITES = "Suites"; public static final String PAGE_TYPE_ATTRIBUTE = "PageType"; public static final String[] PAGE_TYPE_ATTRIBUTES = { STATIC.toString(), TEST.toString(), SUITE.toString() }; public static final String[] ACTION_ATTRIBUTES = { PropertyEDIT, PropertyVERSIONS, PropertyPROPERTIES, PropertyREFACTOR, PropertyWHERE_USED }; public static final String[] NAVIGATION_ATTRIBUTES = { PropertyRECENT_CHANGES, PropertyFILES, PropertySEARCH }; public static final String[] NON_SECURITY_ATTRIBUTES = StringUtil .combineArrays(ACTION_ATTRIBUTES, NAVIGATION_ATTRIBUTES); public static final String PropertySECURE_READ = "secure-read"; public static final String PropertySECURE_WRITE = "secure-write"; public static final String PropertySECURE_TEST = "secure-test"; public static final String[] SECURITY_ATTRIBUTES = { PropertySECURE_READ, PropertySECURE_WRITE, PropertySECURE_TEST }; public static final String LAST_MODIFYING_USER = "LastModifyingUser"; public static final String SUITE_SETUP_NAME = "SuiteSetUp"; public static final String SUITE_TEARDOWN_NAME = "SuiteTearDown"; private transient WikiPage wikiPage; private String content; private WikiPageProperties properties = new WikiPageProperties(); private Set<VersionInfo> versions; public static final String COMMAND_PATTERN = "COMMAND_PATTERN"; public static final String TEST_RUNNER = "TEST_RUNNER"; public static final String PATH_SEPARATOR = "PATH_SEPARATOR"; private Symbol contentSyntaxTree = null; private ParsingPage parsingPage; public PageData(WikiPage page) { wikiPage = page; initializeAttributes(); versions = new HashSet<VersionInfo>(); } public PageData(WikiPage page, String content) { this(page); setContent(content); } public PageData(PageData data) { this(data.getWikiPage(), data.content); properties = new WikiPageProperties(data.properties); versions.addAll(data.versions); contentSyntaxTree = data.contentSyntaxTree; parsingPage = data.parsingPage; } public void initializeAttributes() { if (!isErrorLogsPage()) { properties.set(PropertyEDIT, Boolean.toString(true)); properties.set(PropertyPROPERTIES, Boolean.toString(true)); properties.set(PropertyREFACTOR, Boolean.toString(true)); } properties.set(PropertyWHERE_USED, Boolean.toString(true)); properties.set(PropertyRECENT_CHANGES, Boolean.toString(true)); properties.set(PropertyFILES, Boolean.toString(true)); properties.set(PropertyVERSIONS, Boolean.toString(true)); properties.set(PropertySEARCH, Boolean.toString(true)); properties.setLastModificationTime(Clock.currentDate()); initTestOrSuiteProperty(); } private void initTestOrSuiteProperty() { final String pageName = wikiPage.getName(); if (pageName == null) { handleInvalidPageName(wikiPage); return; } if (isErrorLogsPage()) return; PageType pageType = PageType.getPageTypeForPageName(pageName); if (STATIC.equals(pageType)) return; properties.set(pageType.toString(), Boolean.toString(true)); } private boolean isErrorLogsPage() { PageCrawler crawler = wikiPage.getPageCrawler(); String relativePagePath = crawler.getRelativeName( crawler.getRoot(wikiPage), wikiPage); return relativePagePath.startsWith(ExecutionLog.ErrorLogName); } // TODO: Should be written to a real logger, but it doesn't like FitNesse's // logger is // really intended for general logging. private void handleInvalidPageName(WikiPage wikiPage) { try { String msg = "WikiPage " + wikiPage + " does not have a valid name!" + wikiPage.getName(); System.err.println(msg); throw new RuntimeException(msg); } catch (Exception e) { throw new RuntimeException(e); } } public WikiPageProperties getProperties() { return properties; } public String getAttribute(String key) { return properties.get(key); } public void removeAttribute(String key) { properties.remove(key); } public void setAttribute(String key, String value) { properties.set(key, value); } public void setAttribute(String key) { properties.set(key); } public boolean hasAttribute(String attribute) { return properties.has(attribute); } public void setProperties(WikiPageProperties properties) { this.properties = properties; } public String getContent() { return StringUtil.stripCarriageReturns(content); } public void setContent(String content) { this.content = content; contentSyntaxTree = null; parsingPage = null; } /* this is the public entry to page parse and translate */ public String getHtml() { return translateToHtml(getSyntaxTree()); } public String getVariable(String name) { Maybe<String> variable = new VariableFinder(getParsingPage()).findVariable(name); if (variable.isNothing()) return null; return getParsingPage().renderVariableValue(variable.getValue()); } public Symbol getSyntaxTree() { parsePageContent(); return contentSyntaxTree; } public ParsingPage getParsingPage() { parsePageContent(); return parsingPage; } private void parsePageContent() { if (contentSyntaxTree == null) { //long start = Clock.currentTimeInMillis(); parsingPage = new ParsingPage(new WikiSourcePage(wikiPage)); String content = getContent(); contentSyntaxTree = Parser.make(parsingPage, content).parse(); //long elapsed = Clock.currentTimeInMillis() - start; //System.out.println((wikiPage != null && wikiPage.getName() != null ? wikiPage.getName() : "?") + " parse " + elapsed + " " + (content != null ? content.length() : 0)); } } public String translateToHtml(Symbol syntaxTree) { //long start = Clock.currentTimeInMillis(); String result = new HtmlTranslator(new WikiSourcePage(wikiPage), parsingPage).translateTree(syntaxTree); //long elapsed = Clock.currentTimeInMillis() - start; //System.out.println((wikiPage != null ? wikiPage.getName() : "?") + " translate " + elapsed + " " + result.length()); return result; } public void setWikiPage(WikiPage page) { wikiPage = page; } public WikiPage getWikiPage() { return wikiPage; } public List<String> getClasspaths() { Symbol tree = getSyntaxTree(); return new Paths(new HtmlTranslator(new WikiSourcePage(wikiPage), parsingPage)).getPaths(tree); } public List<String> getXrefPages() { final ArrayList<String> xrefPages = new ArrayList<String>(); getSyntaxTree().walkPreOrder(new SymbolTreeWalker() { public boolean visit(Symbol node) { if (node.isType(See.symbolType)) xrefPages.add(node.childAt(0).getContent()); return true; } public boolean visitChildren(Symbol node) { return true; } }); return xrefPages; } public Set<VersionInfo> getVersions() { return versions; } public void addVersions(Collection<VersionInfo> newVersions) { versions.addAll(newVersions); } public boolean isEmpty() { return getContent() == null || getContent().length() == 0; } }