/*
BEGIN LICENSE BLOCK
Copyright 2010-2011, Heiko Mueller, Sam Lindley, James Cheney and
University of Edinburgh
This file is part of Database Wiki.
Database Wiki is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Database Wiki is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Database Wiki. If not, see <http://www.gnu.org/licenses/>.
END LICENSE BLOCK
*/
package org.dbwiki.web.server;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
import org.dbwiki.data.annotation.Annotation;
import org.dbwiki.data.database.Database;
import org.dbwiki.data.database.DatabaseElementNode;
import org.dbwiki.data.database.DatabaseTextNode;
import org.dbwiki.data.database.NodeUpdate;
import org.dbwiki.data.database.Update;
import org.dbwiki.data.document.DocumentAttributeNode;
import org.dbwiki.data.document.DocumentGroupNode;
import org.dbwiki.data.document.DocumentNode;
import org.dbwiki.data.index.DatabaseContent;
import org.dbwiki.data.io.CopyPasteInputHandler;
import org.dbwiki.data.io.CopyPasteNodeWriter;
import org.dbwiki.data.io.ExportJSONNodeWriter;
import org.dbwiki.data.io.ExportNodeWriter;
import org.dbwiki.data.io.NodeWriter;
import org.dbwiki.data.io.SAXCallbackInputHandler;
import org.dbwiki.data.resource.DatabaseIdentifier;
import org.dbwiki.data.resource.PageIdentifier;
import org.dbwiki.data.schema.AttributeSchemaNode;
import org.dbwiki.data.schema.SchemaNode;
import org.dbwiki.data.schema.GroupSchemaNode;
import org.dbwiki.data.wiki.Wiki;
import org.dbwiki.exception.WikiFatalException;
import org.dbwiki.exception.web.WikiRequestException;
import org.dbwiki.user.UserListing;
import org.dbwiki.web.html.HtmlPage;
import org.dbwiki.web.html.RedirectPage;
import org.dbwiki.web.request.Exchange;
import org.dbwiki.web.request.HttpRequest;
import org.dbwiki.web.request.URLDecodingRules;
import org.dbwiki.web.request.WikiDataRequest;
import org.dbwiki.web.request.WikiPageRequest;
import org.dbwiki.web.request.WikiRequest;
import org.dbwiki.web.request.WikiSchemaRequest;
import org.dbwiki.web.request.parameter.RequestParameter;
import org.dbwiki.web.request.parameter.RequestParameterAction;
import org.dbwiki.web.request.parameter.RequestParameterActionCancel;
import org.dbwiki.web.request.parameter.RequestParameterVersion;
import org.dbwiki.web.request.parameter.RequestParameterVersionSingle;
import org.dbwiki.web.ui.DatabaseWikiContentGenerator;
import org.dbwiki.web.ui.HtmlTemplateDecorator;
import org.dbwiki.web.ui.layout.DatabaseLayouter;
import org.dbwiki.web.ui.printer.CSSLinePrinter;
import org.dbwiki.web.ui.printer.FileEditor;
import org.dbwiki.web.ui.printer.LayoutEditor;
import org.dbwiki.web.ui.printer.ObjectAnnotationPrinter;
import org.dbwiki.web.ui.printer.ObjectProvenancePrinter;
import org.dbwiki.web.ui.printer.SettingsListingPrinter;
import org.dbwiki.web.ui.printer.TimemachinePrinter;
import org.dbwiki.web.ui.printer.VersionIndexPrinter;
import org.dbwiki.web.ui.printer.data.CreateSchemaNodeFormPrinter;
import org.dbwiki.web.ui.printer.data.DataMenuPrinter;
import org.dbwiki.web.ui.printer.data.DataNodePrinter;
import org.dbwiki.web.ui.printer.data.DataUpdateFormPrinter;
import org.dbwiki.web.ui.printer.data.InputFormPrinter;
import org.dbwiki.web.ui.printer.data.NodePathPrinter;
import org.dbwiki.web.ui.printer.index.AZMultiPageIndexPrinter;
import org.dbwiki.web.ui.printer.index.AZSinglePageIndexPrinter;
import org.dbwiki.web.ui.printer.index.FullIndexPrinter;
import org.dbwiki.web.ui.printer.index.MultiColumnIndexPrinter;
import org.dbwiki.web.ui.printer.index.PartialIndexPrinter;
import org.dbwiki.web.ui.printer.index.SearchResultPrinter;
import org.dbwiki.web.ui.printer.page.PageContentPrinter;
import org.dbwiki.web.ui.printer.page.PageHistoryPrinter;
import org.dbwiki.web.ui.printer.page.PageMenuPrinter;
import org.dbwiki.web.ui.printer.page.PageUpdateFormPrinter;
import org.dbwiki.web.ui.printer.schema.SchemaMenuPrinter;
import org.dbwiki.web.ui.printer.schema.SchemaNodePrinter;
import org.dbwiki.web.ui.printer.schema.SchemaPathPrinter;
import org.dbwiki.web.server.DatabaseWikiProperties;
/** Implements the DatabaseWiki functionality for a given database.
*
* @author jcheney
*
*/
public abstract class DatabaseWiki implements Comparable<DatabaseWiki> {
/*
* Public Constants
*/
public static final String ParameterSchemaNodeName = "schema_node_name";
public static final String ParameterSchemaNodeType = "schema_node_type";
public static final String ParameterFileContent = "file_content";
public static final String ParameterFileType = "file_type";
public static final String ParameterDatabaseID = "database_id";
/*
* Private Variables
*/
protected int _autoSchemaChanges;
protected Database _database;
protected int _id;
protected DatabaseLayouter _layouter = null;
protected String _name;
//protected WikiServer _server;
protected String _template = null;
protected String _title;
protected Wiki _wiki;
protected int _authenticationMode;
private CSSLinePrinter _cssLinePrinter;
private int _cssVersion;
private int _templateVersion;
private int _layoutVersion;
private int _urlDecodingVersion;
private URLDecodingRules _urlDecoder;
/*
* Constructors
*/
/*
* Public Methods
*/
/** Comparator. Compare database wikis by title, to sort list of wikis.
*
*/
public int compareTo(DatabaseWiki wiki) {
return this.getTitle().compareTo(wiki.getTitle());
}
/* Getters
*
*/
// TODO: Build properties directly, removing dependence of DatabaseWikiProperties on DatabaseWiki
public DatabaseWikiProperties getProperties() {
return new DatabaseWikiProperties(this);
}
public int getAuthenticationMode() {
return _authenticationMode;
}
public int getAutoSchemaChanges() {
return _autoSchemaChanges;
}
public CSSLinePrinter cssLinePrinter() {
return _cssLinePrinter;
}
public URLDecodingRules urlDecoder() throws org.dbwiki.exception.WikiException {
if (_urlDecoder == null) {
_urlDecoder = new URLDecodingRules(_database.schema(), server().getURLDecoding(this, _urlDecodingVersion));
}
return _urlDecoder;
}
public Database database() {
return _database;
}
/** Gets the string value of a template or stylesheet, for use in the editor form.
*
* @param fileType
* @return
* @throws org.dbwiki.exception.WikiException
*/
public String getContent(int fileType) throws org.dbwiki.exception.WikiException {
if (fileType == WikiServerConstants.RelConfigFileColFileTypeValTemplate) {
return _template;
} else if (fileType == WikiServerConstants.RelConfigFileColFileTypeValCSS) {
return server().getStyleSheet(this, _cssVersion);
} else if (fileType == WikiServerConstants.RelConfigFileColFileTypeValURLDecoding) {
return server().getURLDecoding(this, _urlDecodingVersion);
} else {
throw new WikiFatalException("Unknown configuration file type");
}
}
public String getTitle() {
return _title;
}
public UserListing users() {
return server().users();
}
public Wiki wiki() {
return _wiki;
}
public abstract WikiServer server() ;
/**
* The list of all previous display settings for this wiki. Contains only
* the file version numbers, not the actual data.
* @return Vector<ConfigSetting>
* @throws org.dbwiki.exception.WikiException
*/
public Vector<ConfigSetting> listSettings() throws org.dbwiki.exception.WikiException {
return server().listSettings(this);
}
public String name() {
return _name;
}
public int id() {
return _id;
}
public DatabaseIdentifier identifier() {
return _database.identifier();
}
public DatabaseLayouter layouter() {
return _layouter;
}
/*
* Setters
*/
/** Sets the auto schema changes policy.
*/
public void setAutoSchemaChanges(int autoSchemaChanges) {
assert(autoSchemaChanges == DatabaseWikiProperties.AutoSchemaChangesNever
|| autoSchemaChanges == DatabaseWikiProperties.AutoSchemaChangesIgnore
|| autoSchemaChanges == DatabaseWikiProperties.AutoSchemaChangesAllow);
_autoSchemaChanges = autoSchemaChanges;
}
public void setTitle(String value) {
_title = value;
}
public void setAuthenticationMode(int authMode) {
_authenticationMode = authMode;
}
/*
* Actions
*/
/**
* Reset configuration to the specified file versions.
*/
public void reset(int layoutVersion, int templateVersion, int styleSheetVersion, int urlDecodingVersion) throws org.dbwiki.exception.WikiException {
_cssVersion = styleSheetVersion;
_layoutVersion = layoutVersion;
_templateVersion = templateVersion;
_urlDecodingVersion = urlDecodingVersion;
_template = server().getTemplate(this, _templateVersion);
_cssLinePrinter = new CSSLinePrinter(this.id(), _cssVersion);
_urlDecoder = null;
_layouter = new DatabaseLayouter(server().getLayout(this, _layoutVersion));
}
public int getLayoutVersion() {
return _layoutVersion;
}
public int getTemplateVersion() {
return _templateVersion;
}
public int getCSSVersion() {
return _cssVersion;
}
public int getURLDecodingVersion() {
return _urlDecodingVersion;
}
/*
* Private Methods
*/
/** Gets the document node associated with an insert POST request.
*
* @param request
* @return
* @throws org.dbwiki.exception.WikiException
*/
protected DocumentNode getInsertNode(WikiDataRequest request) throws org.dbwiki.exception.WikiException {
SchemaNode schemaNode = database().schema().get(Integer.parseInt(request.parameters().get(RequestParameter.ActionValueSchemaNode).value()));
if (schemaNode.isAttribute()) {
AttributeSchemaNode attributeSchemaNode = (AttributeSchemaNode)schemaNode;
DocumentAttributeNode attribute = new DocumentAttributeNode(attributeSchemaNode);
RequestParameter parameter = request.parameters().get(RequestParameter.TextFieldIndicator + attributeSchemaNode.id());
if (parameter.hasValue()) {
if (!parameter.value().equals("")) {
attribute.setValue(parameter.value());
}
}
return attribute;
} else {
Hashtable<Integer, DocumentGroupNode> groupIndex = new Hashtable<Integer, DocumentGroupNode>();
DocumentGroupNode root = SchemaNode.createGroupNode((GroupSchemaNode)schemaNode, groupIndex);
for (int iParameter = 0; iParameter < request.parameters().size(); iParameter++) {
RequestParameter parameter = request.parameters().get(iParameter);
if ((parameter.name().startsWith(RequestParameter.TextFieldIndicator)) && (parameter.hasValue())) {
if (!parameter.value().equals("")) {
SchemaNode child = database().schema().get(Integer.parseInt(parameter.name().substring(RequestParameter.TextFieldIndicator.length())));
if (child.isAttribute()) {
DocumentAttributeNode attribute = new DocumentAttributeNode((AttributeSchemaNode)child);
attribute.setValue(parameter.value());
groupIndex.get(new Integer(attribute.schema().parent().id())).children().add(attribute);
}
}
}
}
DocumentGroupNode.removeEmptyNodes(root);
return root;
}
}
/** Collects the node updates associated with the text fields of a POST request generated by a data edit form
*
* @param request
* @return
* @throws org.dbwiki.exception.WikiException
*/
protected Update getNodeUpdates(WikiDataRequest request) throws org.dbwiki.exception.WikiException {
Update updates = new Update();
for (int iParameter = 0; iParameter < request.parameters().size(); iParameter++) {
RequestParameter parameter = request.parameters().get(iParameter);
if (parameter.name().startsWith(RequestParameter.TextFieldIndicator)) {
if (parameter.hasValue()) {
if (!parameter.value().equals("")) {
updates.add(new NodeUpdate(database().getIdentifierForParameterString(parameter.name().substring(RequestParameter.TextFieldIndicator.length())), parameter.value()));
}
}
}
}
return updates;
}
/** Handle a paste action
*
* @param request
* @param url
* @throws org.dbwiki.exception.WikiException
*/
protected void pasteURL(WikiDataRequest request, String url) throws org.dbwiki.exception.WikiException {
if (url != null) {
CopyPasteInputHandler ioHandler = new CopyPasteInputHandler();
String sourceURL = url;
if (sourceURL.indexOf("?") != -1) {
sourceURL = sourceURL + "&" + RequestParameter.ParameterCopyPasteExport;
} else {
sourceURL = sourceURL + "?" + RequestParameter.ParameterCopyPasteExport;
}
try {
new SAXCallbackInputHandler(ioHandler, false).parse(new URL(sourceURL).openStream(), false, false);
} catch (java.io.IOException ioException) {
throw new WikiFatalException(ioException);
} catch (org.xml.sax.SAXException saxException) {
throw new WikiFatalException(saxException);
}
/* TODO: The version parameter may be missing in the source URL when copying from
* an external source.
*/
this.database().paste(request.wri().resourceIdentifier(), ioHandler.getPasteNode(), url, request.user());
} else {
throw new WikiRequestException(WikiRequestException.InvalidUrl, "(null)");
}
}
/** Reset the configuration.
* The value is the parameter value of a ?reset=value request. The format
* currently is expected to be <int>_<int>_<int> and these <int>'s are
* layout file version, template file version, and style sheet file version.
*
* @param value String
* @throws org.dbwiki.exception.WikiException
*/
protected synchronized void resetConfiguration(String value) throws org.dbwiki.exception.WikiException {
ConfigSetting setting = null;
try {
setting = new ConfigSetting(value);
} catch (Exception exception) {
throw new WikiFatalException(exception);
}
server().resetWikiConfiguration(this, setting.getLayoutVersion(), setting.getTemplateVersion(), setting.getStyleSheetVersion(), setting.getURLDecodingRulesVersion());
}
// TODO: Merge XML and JSON export to avoid code duplication
/**
* Handles data export requests (generating XML)
*
* @param request
* @param writer
* @throws org.dbwiki.exception.WikiException
*/
protected void respondToExportXMLRequest(WikiDataRequest request,
NodeWriter writer, Exchange<?> exchange)
throws org.dbwiki.exception.WikiException {
int versionNumber = database().versionIndex().getLastVersion().number();
if (request.parameters()
.hasParameter(RequestParameter.ParameterVersion)) {
versionNumber = ((RequestParameterVersionSingle) RequestParameter
.versionParameter(request.parameters().get(
RequestParameter.ParameterVersion)))
.versionNumber();
}
try {
// if the request is for all the data in a DatabaseWiki, create a
// temporary file.
// Otherwise, do it in memory (ASSUMES each entry is small!).
// TODO: This could probably be done uniformly by streaming instead.
if (request.isRootRequest()) {
File tmpFile = File.createTempFile("dbwiki", "xml");
BufferedWriter out = new BufferedWriter(new FileWriter(tmpFile));
writer.init(out);
database().export(request.wri().resourceIdentifier(),
versionNumber, writer);
out.close();
exchange.sendXML(new FileInputStream(tmpFile));
tmpFile.delete();
} else {
StringWriter buf = new StringWriter();
BufferedWriter out = new BufferedWriter(buf);
writer.init(out);
database().export(request.wri().resourceIdentifier(),
versionNumber, writer);
out.close();
exchange.sendXML(new ByteArrayInputStream(buf
.toString().getBytes("UTF-8")));
}
} catch (java.io.IOException ioException) {
throw new WikiFatalException(ioException);
}
}
/**
* Handles data export requests (generating JSON)
*
* @param request
* @param writer
* @throws org.dbwiki.exception.WikiException
*/
protected void respondToExportJSONRequest(WikiDataRequest request,
NodeWriter writer, Exchange<?> exchange)
throws org.dbwiki.exception.WikiException {
int versionNumber = database().versionIndex().getLastVersion().number();
if (request.parameters()
.hasParameter(RequestParameter.ParameterVersion)) {
versionNumber = ((RequestParameterVersionSingle) RequestParameter
.versionParameter(request.parameters().get(
RequestParameter.ParameterVersion)))
.versionNumber();
}
try {
// if the request is for all the data in a DatabaseWiki, create a
// temporary file.
// Otherwise, do it in memory (ASSUMES each entry is small!).
// TODO: This could probably be done uniformly by streaming instead.
if (request.isRootRequest()) {
File tmpFile = File.createTempFile("dbwiki", "json");
BufferedWriter out = new BufferedWriter(new FileWriter(tmpFile));
writer.init(out);
database().export(request.wri().resourceIdentifier(),
versionNumber, writer);
out.close();
exchange.sendJSON(new FileInputStream(tmpFile));
tmpFile.delete();
} else {
StringWriter buf = new StringWriter();
BufferedWriter out = new BufferedWriter(buf);
writer.init(out);
database().export(request.wri().resourceIdentifier(),
versionNumber, writer);
out.close();
exchange.sendJSON(new ByteArrayInputStream(buf
.toString().getBytes("UTF-8")));
}
} catch (java.io.IOException ioException) {
throw new WikiFatalException(ioException);
}
}
/**
* Handles a request for a data node. First check authentication. Next
* determine whether it's a GET request, or an action. If it's an action,
* perform the action and redirect. If it's a GET request, there are many
* cases depending on the particular content being requested (e.g. the
* current version, past versions, xml, search, file editor, etc.) In each
* case, build appropriate content generator and plug into the template.
*
* @param request
* @throws java.io.IOException
* @throws org.dbwiki.exception.WikiException
*/
protected void respondToDataRequest(WikiDataRequest request,
Exchange<?> exchange) throws java.io.IOException,
org.dbwiki.exception.WikiException {
HtmlPage page = null;
// The following test is just an additional security check in case
// someone
// managed to get past the WikiAuthenticator.
if ((request.user() == null)
&& (getAuthenticationMode() != DatabaseWikiProperties.AuthenticateNever)) {
if ((request.type().isAction()) || (request.type().isActivate())
|| (request.type().isDelete()) || request.type().isPaste()) {
throw new WikiFatalException(
"User login required to perform requested operation");
}
}
// All requests of type .isAction() have to result in .isGet() or
// .isIndex() requests
// which is not recognized/distinguished by the RequestType class. Thus,
// this
// decision has to be taken below (thats why the following variables are
// needed).
boolean isGetRequest = (request.type().isGet() || request.type()
.isActivate());
boolean isIndexRequest = request.type().isIndex();
// This is where all the action happens. Note that .isAction() requests
// result from
// HTTP POST request. The class RequestType currently does not
// distinguish these
// requests further, thus it has to be done here.
if (request.type().isAction()) {
RequestParameterAction action = RequestParameter
.actionParameter(request.parameters().get(
RequestParameter.ParameterAction));
if (action.actionAnnotate()) {
RequestParameter parameter = request.parameters().get(
RequestParameter.ActionValueAnnotation);
if (parameter.hasValue()) {
if (!parameter.value().trim().equals("")) {
database().annotate(
request.wri().resourceIdentifier(),
new Annotation(parameter.value(),
new SimpleDateFormat(
"d MMM yyyy HH:mm:ss")
.format(new Date()), request
.user()));
}
}
// Only objects may be annotated, thus this is a get request
isGetRequest = true;
} else if (action.actionSchemaNode()) {
GroupSchemaNode parent = null;
if (!request.isRootRequest()) {
parent = (GroupSchemaNode) ((DatabaseElementNode) _database
.get(request.wri().resourceIdentifier())).schema();
}
_database.insertSchemaNode(
parent,
request.parameters().get(ParameterSchemaNodeName)
.value(),
Byte.parseByte(request.parameters()
.get(ParameterSchemaNodeType).value()),
request.user());
isGetRequest = !request.isRootRequest();
isIndexRequest = !isGetRequest;
} else if (action.actionInsert()) {
DocumentNode insertNode = this.getInsertNode(request);
page = new RedirectPage(request, database().insertNode(
request.wri().resourceIdentifier(), insertNode,
request.user()));
} else if (action.actionUpdate()) {
if (request.parameters().hasParameter(ParameterDatabaseID)) {
// Updating a configuration file
this.updateConfigurationFile(request);
// Configuration files may be modified either while viewing
// the
// database index or and object. Make sure to display the
// appropriate
// page after the update.
isGetRequest = !request.isRootRequest();
isIndexRequest = !isGetRequest;
} else {
// Updating a data object
Update update = this.getNodeUpdates(request);
if (update != null) {
database().update(request.wri().resourceIdentifier(),
update, request.user());
if (request.node().isText()) {
page = new RedirectPage(request,
((DatabaseTextNode) request.node())
.parent().identifier());
}
}
isGetRequest = true;
}
}
} else if (request.type().isActivate()) {
database().activate(request.wri().resourceIdentifier(),
request.user());
} else if (request.type().isCopy()) {
String sourceURL = "http://localhost" + ":"
+ exchange.getLocalPort()
+ request.wri().getURL();
RequestParameterVersion version = RequestParameter
.versionParameter(request.parameters().get(
RequestParameter.ParameterVersion));
if (version.versionSingle()) {
sourceURL = sourceURL + "?" + version.toURLString();
} else {
sourceURL = sourceURL
+ "?"
+ new RequestParameterVersionSingle(this.database()
.versionIndex().getLastVersion().number())
.toURLString();
}
exchange.setResponseHeader("Set-Cookie", HttpRequest.CookiePropertyCopyBuffer + "=" + URLEncoder.encode(sourceURL, "UTF-8") + "; path=/; ");
} else if (request.type().isDelete()) {
database().delete(request.wri().resourceIdentifier(),
request.user());
if (request.node().parent() != null) {
page = new RedirectPage(request, request.node().parent()
.identifier());
} else {
isIndexRequest = true;
}
} else if (request.type().isPaste()) {
String url = null;
if (request.parameters()
.hasParameter(RequestParameter.ParameterURL)) {
url = request.parameters().get(RequestParameter.ParameterURL)
.value();
} else {
url = URLDecoder.decode(request.copyBuffer(), "UTF-8");
}
this.pasteURL(request, url);
isGetRequest = !request.isRootRequest();
isIndexRequest = !isGetRequest;
} else if (request.type().isReset()) {
this.resetConfiguration(request.parameters()
.get(RequestParameter.ParameterReset).value());
isGetRequest = !request.isRootRequest();
isIndexRequest = !isGetRequest;
} else if (request.type().isCopyPasteExport()) {
this.respondToExportXMLRequest(request, new CopyPasteNodeWriter(),
exchange);
return;
} else if (request.type().isExportXML()) {
this.respondToExportXMLRequest(request, new ExportNodeWriter(),
exchange);
return;
} else if (request.type().isExportJSON()) {
this.respondToExportJSONRequest(request,
new ExportJSONNodeWriter(),
exchange);
return;
}
// If the request is not redirected (in case of INSERT or DELETE) then
// assemble appropriate
// HtmlContentGenerator.
if (page == null) {
DatabaseWikiContentGenerator contentGenerator = new DatabaseWikiContentGenerator(
request, this.getTitle(), this.cssLinePrinter());
if ((isGetRequest) || (request.type().isCopy())) {// This is the
// default case
// where no
// action has
// been
// performed and
// no special
// content is
// requested
contentGenerator.put(
DatabaseWikiContentGenerator.ContentTimemachine,
new TimemachinePrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new DataMenuPrinter(request, _layouter));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentObjectLink,
new NodePathPrinter(request, _layouter));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentAnnotation,
new ObjectAnnotationPrinter(request));
// contentGenerator.put(DatabaseWikiContentGenerator.ContentProvenance,
// new VersionIndexPrinter(request));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentProvenance,
new ObjectProvenancePrinter(request, _layouter));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new DataNodePrinter(request, _layouter));
} else if (isIndexRequest) { // The case for the root of the
// DatabaseWiki
contentGenerator.put(
DatabaseWikiContentGenerator.ContentTimemachine,
new TimemachinePrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new DataMenuPrinter(request, _layouter));
// TODO: This could be simplified by storing the mapping in a
// Map<String,IndexContentPrinter>
if (DatabaseLayouter.IndexAZMultiPage.equals(_layouter
.indexType())) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new AZMultiPageIndexPrinter(request, database()
.content()));
} else if (DatabaseLayouter.IndexAZSinglePage.equals(_layouter
.indexType())) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new AZSinglePageIndexPrinter(request, database()
.content()));
} else if (DatabaseLayouter.IndexMultiColumn.equals(_layouter
.indexType())) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new MultiColumnIndexPrinter(request, database()
.content()));
} else if (DatabaseLayouter.IndexPartialList.equals(_layouter
.indexType())) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new PartialIndexPrinter(request, database()
.content()));
} else {
contentGenerator
.put(DatabaseWikiContentGenerator.ContentContent,
new FullIndexPrinter(request, database()
.content()));
}
} else if (request.type().isSearch()) { // The case for a search
// request
DatabaseContent content = null;
String query = request.parameters()
.get(RequestParameter.ParameterSearch).value();
if (query != null) {
content = database().search(query);
} else {
content = database().content();
}
contentGenerator.put(
DatabaseWikiContentGenerator.ContentTimemachine,
new TimemachinePrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new DataMenuPrinter(request, _layouter));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new SearchResultPrinter(request, content));
} else if ((request.type().isCreate()) || (request.type().isEdit())) { // The
// case
// for
// a
// create
// or
// edit
// request
contentGenerator.put(
DatabaseWikiContentGenerator.ContentObjectLink,
new NodePathPrinter(request, _layouter));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new DataUpdateFormPrinter(request, _layouter));
} else if (request.type().isCreateSchemaNode()) { // Creating a new
// schema node.
contentGenerator.put(
DatabaseWikiContentGenerator.ContentObjectLink,
new NodePathPrinter(request, _layouter));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new CreateSchemaNodeFormPrinter(request));
} else if ((request.type().isTimemachineChanges())
|| ((request.type().isTimemachinePrevious()))) {
if (request.node() != null) { // Showing version index
contentGenerator.put(
DatabaseWikiContentGenerator.ContentObjectLink,
new NodePathPrinter(request, _layouter));
}
contentGenerator.put(
DatabaseWikiContentGenerator.ContentTimemachine,
new TimemachinePrinter(request));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new VersionIndexPrinter(request));
} else if (request.type().isLayout()) { // Editing the layout
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new LayoutEditor(request));
} else if (request.type().isPasteForm()) { // Pasting XML data from
// a URL
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new InputFormPrinter(request, "Copy & Paste",
"Insert source URL",
RequestParameter.ParameterPaste,
RequestParameter.ParameterURL));
} else if (request.type().isStyleSheet()) { // Editing the
// stylesheet
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new FileEditor(request, "Edit style sheet"));
} else if (request.type().isTemplate()) { // Editing the template
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new FileEditor(request, "Edit template"));
} else if (request.type().isURLDecoding()) { // Editing the URL
// decoding rules
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new FileEditor(request, "Edit URL decoding rules"));
} else if (request.type().isSettings()) { // The list of prior
// combinations of
// config files, can be
// used to revert.
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new SettingsListingPrinter(request));
} else {
throw new WikiRequestException(
WikiRequestException.InvalidRequest, exchange.getRequestURI().toString());
}
page = HtmlTemplateDecorator.decorate(_template, contentGenerator);
}
// Send the resulting page to the user.
exchange.send(page);
}
/**
* Responds to requests for wiki pages
* TODO: Factor this out so that wiki pages are handled at server level.
*
* @param request
* @throws java.io.IOException
* @throws org.dbwiki.exception.WikiException
*/
protected void respondToPageRequest(WikiPageRequest request,
Exchange<?> exchange) throws java.io.IOException,
org.dbwiki.exception.WikiException {
// Again, we need to further distinguish the request type
// for .isAction() requests (see above).
boolean isGetRequest = request.type().isGet();
boolean isIndexRequest = request.type().isIndex();
RequestParameterAction action = new RequestParameterActionCancel();
if (request.type().isDelete()) {
wiki().delete((PageIdentifier) request.wri().resourceIdentifier());
exchange.send(new RedirectPage(request.wri().databaseIdentifier()
.databaseHomepage()));
return;
} else if (request.type().isAction()) {
action = RequestParameter.actionParameter(request.parameters().get(
RequestParameter.ParameterAction));
if (action.actionInsert()) {
wiki().insert(request.getWikiPage(), request.user());
} else if (action.actionUpdate()) {
if (request.parameters().hasParameter(ParameterDatabaseID)) {
this.updateConfigurationFile(request);
isGetRequest = !request.isRootRequest();
isIndexRequest = !isGetRequest;
} else {
wiki().update(
new PageIdentifier(request.parameters()
.get(RequestParameter.ActionValuePageID)
.value()), request.getWikiPage(),
request.user());
isGetRequest = true;
isIndexRequest = false;
}
}
}
DatabaseWikiContentGenerator contentGenerator = new DatabaseWikiContentGenerator(
request, this.getTitle(), this.cssLinePrinter());
if (isGetRequest) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new PageMenuPrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new PageContentPrinter(request, _layouter));
} else if ((isIndexRequest) || (request.type().isDelete())
|| (action.actionInsert())) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new PageMenuPrinter(request));
if (DatabaseLayouter.IndexAZMultiPage.equals(_layouter.indexType())) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new AZMultiPageIndexPrinter(request, wiki().content()));
} else if (DatabaseLayouter.IndexAZSinglePage.equals(_layouter
.indexType())) {
contentGenerator
.put(DatabaseWikiContentGenerator.ContentContent,
new AZSinglePageIndexPrinter(request, wiki()
.content()));
} else if (DatabaseLayouter.IndexMultiColumn.equals(_layouter
.indexType())) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new MultiColumnIndexPrinter(request, wiki().content()));
} else if (DatabaseLayouter.IndexPartialList.equals(_layouter
.indexType())) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new PartialIndexPrinter(request, wiki().content()));
} else {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentContent,
new FullIndexPrinter(request, wiki().content()));
}
} else if ((request.type().isCreate()) || (request.type().isEdit())) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new PageUpdateFormPrinter(request));
} else if (request.type().isLayout()) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new LayoutEditor(request));
} else if (request.type().isStyleSheet()) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new FileEditor(request, "Edit style sheet"));
} else if (request.type().isTemplate()) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new FileEditor(request, "Edit template"));
} else if (request.type().isURLDecoding()) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new FileEditor(request, "Edit URL decoding rules"));
} else if (request.type().isSettings()) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new SettingsListingPrinter(request));
} else if (request.type().isPageHistory()) {
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new PageMenuPrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new PageHistoryPrinter(request));
} else {
throw new WikiRequestException(WikiRequestException.InvalidRequest,
exchange.getRequestURI().toASCIIString());
}
exchange.send(HtmlTemplateDecorator.decorate(_template, contentGenerator));
}
/**
* Respond to request for a schema node Like respondToDataRequest, this
* first checks the operation is a GET or POST. If POST, then the action is
* performed and the response redirects. If GET, then an appropriate
* ContentGenerator is constructed and used to render the schema node.
*
* @param request
* @throws java.io.IOException
* @throws org.dbwiki.exception.WikiException
*/
protected void respondToSchemaRequest(WikiSchemaRequest request,
Exchange<?> exchange) throws java.io.IOException,
org.dbwiki.exception.WikiException {
// TODO: fill in and tidy up
//
// Most of the code here is copied and pasted from above.
// Again, we need to further distinguish the request type
// for .isAction() requests (see above).
boolean isGetRequest = request.type().isGet();
boolean isIndexRequest = request.type().isIndex();
if (request.type().isDelete()) {
database().deleteSchemaNode(request.wri().resourceIdentifier(),
request.user());
if (request.schema().parent() != null) {
exchange.send(new RedirectPage(request,
request.schema().parent().identifier()));
return;
} else {
isIndexRequest = true;
}
}
// This is where all the action happens. Note that .isAction() requests
// result from
// HTTP POST request. The class RequestType currently does not
// distinguish these
// requests further, thus it has to be done here.
if (request.type().isAction()) {
RequestParameterAction action = RequestParameter
.actionParameter(request.parameters().get(
RequestParameter.ParameterAction));
GroupSchemaNode parent = null;
if (action.actionSchemaNode()) {
if (!request.isRootRequest())
parent = (GroupSchemaNode) request.schema();
_database.insertSchemaNode(
parent,
request.parameters().get(ParameterSchemaNodeName)
.value(),
Byte.parseByte(request.parameters()
.get(ParameterSchemaNodeType).value()),
request.user());
isGetRequest = !request.isRootRequest();
isIndexRequest = !isGetRequest;
}
}
// RequestParameterAction action = new RequestParameterActionCancel();
// if (request.type().isDelete()) {
// wiki().delete((PageIdentifier)request.wri().resourceIdentifier());
// new
// RedirectPage(request.wri().databaseIdentifier().databaseHomepage()).send(request.exchange());
// return;
// } else if (request.type().isAction()) {
// action =
// RequestParameter.actionParameter(request.parameters().get(RequestParameter.ParameterAction));
// if (action.actionInsert()) {
// wiki().insert(this.getWikiPage(request), request.user());
// } else if (action.actionUpdate()) {
// if (request.parameters().hasParameter(ParameterWikiID)) {
// this.updateConfigurationFile(request);
// isGetRequest = !request.isRootRequest();
// isIndexRequest = !isGetRequest;
// } else {
// wiki().update(new
// PageIdentifier(request.parameters().get(RequestParameter.ActionValuePageID).value()),
// this.getWikiPage(request), request.user());
// isGetRequest = true;
// isIndexRequest = false;
// }
// }
// }
//
DatabaseWikiContentGenerator contentGenerator = new DatabaseWikiContentGenerator(
request, this.getTitle(), this.cssLinePrinter());
if (isGetRequest) {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentTimemachine,
new TimemachinePrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new SchemaMenuPrinter(request));
contentGenerator.put(
DatabaseWikiContentGenerator.ContentObjectLink,
new SchemaPathPrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new SchemaNodePrinter(request, _layouter));
} else if ((isIndexRequest) || (request.type().isDelete())) { // ||
// (action.actionInsert()))
// {
contentGenerator.put(
DatabaseWikiContentGenerator.ContentTimemachine,
new TimemachinePrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu,
new SchemaMenuPrinter(request));
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new SchemaNodePrinter(request, _layouter));
} else if (request.type().isCreateSchemaNode()
&& request.schema().isGroup()) {
// FIXME #schemaversioning: only display the option to create a new
// schema node if we're viewing a group?
contentGenerator.put(DatabaseWikiContentGenerator.ContentContent,
new CreateSchemaNodeFormPrinter(request));
}
// if (IndexAZMultiPage.equals(_layouter.indexType())) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// AZMultiPageIndexPrinter(request, wiki().content()));
// } else if (IndexAZSinglePage.equals(_layouter.indexType())) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// AZSinglePageIndexPrinter(request, wiki().content()));
// } else if (IndexMultiColumn.equals(_layouter.indexType())) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// MultiColumnIndexPrinter(request, wiki().content()));
// } else if (IndexPartialList.equals(_layouter.indexType())) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// PartialIndexPrinter(request, wiki().content()));
// } else {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// FullIndexPrinter(request, wiki().content()));
// }
// }
// } //else if ((request.type().isCreate()) ||
// (request.type().isEdit())) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// PageUpdateFormPrinter(request));
// } else if (request.type().isLayout()) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// LayoutEditor(request));
// } else if (request.type().isStyleSheet()) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// FileEditor(request, "Edit style sheet"));
// } else if (request.type().isTemplate()) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// FileEditor(request, "Edit template"));
// } else if (request.type().isSettings()) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// SettingsListingPrinter(request));
// } else if (request.type().isPageHistory()) {
// contentGenerator.put(DatabaseWikiContentGenerator.ContentMenu, new
// PageMenuPrinter(request));
// contentGenerator.put(DatabaseWikiContentGenerator.ContentContent, new
// PageHistoryPrinter(request));
// } else {
// throw new WikiRequestException(WikiRequestException.InvalidRequest,
// request.exchange().getRequestURI().toASCIIString());
// }
exchange.send(HtmlTemplateDecorator.decorate(_template, contentGenerator));
}
/** Handles POST requests that provide a new version of a config file.
*
* @param request
* @throws org.dbwiki.exception.WikiException
*/
protected synchronized void updateConfigurationFile(WikiRequest request) throws org.dbwiki.exception.WikiException {
int wikiID = Integer.valueOf(request.parameters().get(ParameterDatabaseID).value());
int fileType = Integer.valueOf(request.parameters().get(ParameterFileType).value());
String value = null;
if (fileType == WikiServerConstants.RelConfigFileColFileTypeValLayout) {
Properties properties = new Properties();
for (int iParameter = 0; iParameter < request.parameters().size(); iParameter++) {
RequestParameter parameter = request.parameters().get(iParameter);
if (DatabaseLayouter.isLayoutParameter(parameter.name())) {
if (parameter.hasValue()) {
properties.setProperty(parameter.name(), parameter.value());
} else {
properties.setProperty(parameter.name(), "(null)");
}
}
}
StringWriter writer = new StringWriter();
try {
properties.store(writer, "Database Layout");
} catch (java.io.IOException ioException) {
throw new WikiFatalException(ioException);
}
value = writer.toString();
} else {
value = request.parameters().get(ParameterFileContent).value();
}
if (fileType == WikiServerConstants.RelConfigFileColFileTypeValLayout) {
server().updateConfigFile(wikiID, fileType, value, request.user());
_layouter = new DatabaseLayouter(value);
} else if (fileType == WikiServerConstants.RelConfigFileColFileTypeValTemplate) {
server().updateConfigFile(wikiID, fileType, value, request.user());
_template = value;
} else if (fileType == WikiServerConstants.RelConfigFileColFileTypeValCSS) {
_cssVersion = server().updateConfigFile(wikiID, fileType, value, request.user());
_cssLinePrinter = new CSSLinePrinter(this.id(), _cssVersion);
} else if (fileType == WikiServerConstants.RelConfigFileColFileTypeValURLDecoding) {
_urlDecoder = new URLDecodingRules(_database.schema(), value);
_urlDecodingVersion = server().updateConfigFile(wikiID, fileType, value, request.user());
}
}
}