// 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.responders.editing; import java.io.File; import java.io.IOException; import fitnesse.wikitext.parser.WikiWordBuilder; import util.EnvironmentVariableTool; import util.StringUtil; import fitnesse.FitNesseContext; import fitnesse.Responder; import fitnesse.http.Request; import fitnesse.http.Response; import fitnesse.http.SimpleResponse; import fitnesse.responders.ErrorResponder; import fitnesse.responders.NotFoundResponder; import fitnesse.wiki.PageCrawler; import fitnesse.wiki.PageData; import fitnesse.wiki.PathParser; import fitnesse.wiki.SymbolicPage; import fitnesse.wiki.WikiPage; import fitnesse.wiki.WikiPagePath; import fitnesse.wiki.WikiPageProperties; import fitnesse.wiki.WikiPageProperty; import fitnesse.wikitext.Utils; public class SymbolicLinkResponder implements Responder { private Response response; private String resource; private PageCrawler crawler; private FitNesseContext context; private WikiPage page; public Response makeResponse(FitNesseContext context, Request request) throws IOException { resource = request.getResource(); this.context = context; crawler = context.root.getPageCrawler(); page = crawler.getPage(context.root, PathParser.parse(resource)); if (page == null) return new NotFoundResponder().makeResponse(context, request); response = new SimpleResponse(); if (request.hasInput("removal")) removeSymbolicLink(request, page); else if (request.hasInput("rename")) renameSymbolicLink(request, page); else addSymbolicLink(request, page); return response; } private void setRedirect(String resource) { response.redirect(resource + "?properties"); } private void removeSymbolicLink(Request request, WikiPage page) { String linkToRemove = (String) request.getInput("removal"); PageData data = page.getData(); WikiPageProperties properties = data.getProperties(); WikiPageProperty symLinks = getSymLinkProperty(properties); symLinks.remove(linkToRemove); if (symLinks.keySet().size() == 0) properties.remove(SymbolicPage.PROPERTY_NAME); page.commit(data); setRedirect(resource); } private void renameSymbolicLink(Request request, WikiPage page) { String linkToRename = (String) request.getInput("rename"), newName = (String) request.getInput("newname"); if (page.hasChildPage(newName)) { response = new ErrorResponder(resource + " already has a child named " + newName + ".").makeResponse(context, null); response.setStatus(412); } else { PageData data = page.getData(); WikiPageProperties properties = data.getProperties(); WikiPageProperty symLinks = getSymLinkProperty(properties); String currentPath = symLinks.get(linkToRename); symLinks.remove(linkToRename); symLinks.set(newName, currentPath); page.commit(data); setRedirect(resource); } } private void addSymbolicLink(Request request, WikiPage page) throws IOException { String linkName = StringUtil.trimNonNullString((String) request.getInput("linkName")); String linkPath = StringUtil.trimNonNullString((String) request.getInput("linkPath")); if (isFilePath(linkPath) && !isValidDirectoryPath(linkPath)) { String message = "Cannot create link to the file system path, <b>" + linkPath + "</b>." + "<br/> The canonical file system path used was <b>" + createFileFromPath(linkPath).getCanonicalPath() + ".</b>" + "<br/>Either it doesn't exist or it's not a directory."; response = new ErrorResponder(message).makeResponse(context, null); response.setStatus(404); } else if (!isFilePath(linkPath) && isInternalPageThatDoesntExist(linkPath)) { response = new ErrorResponder("The page to which you are attempting to link, " + Utils.escapeHTML(linkPath) + ", doesn't exist.").makeResponse(context, null); response.setStatus(404); } else if (page.hasChildPage(linkName)) { response = new ErrorResponder(resource + " already has a child named " + linkName + ".").makeResponse(context, null); response.setStatus(412); } else { PageData data = page.getData(); WikiPageProperties properties = data.getProperties(); WikiPageProperty symLinks = getSymLinkProperty(properties); symLinks.set(linkName, linkPath); page.commit(data); setRedirect(resource); } } private boolean isValidDirectoryPath(String linkPath) { File file = createFileFromPath(linkPath); if (file.exists()) return file.isDirectory(); else { File parentDir = file.getParentFile(); return parentDir.exists() && parentDir.isDirectory(); } } private File createFileFromPath(String linkPath) { String pathToFile = EnvironmentVariableTool.replace(linkPath.substring(7)); return new File(pathToFile); } private boolean isFilePath(String linkPath) { return linkPath.startsWith("file://"); } private boolean isInternalPageThatDoesntExist(String linkPath) { String expandedPath = WikiWordBuilder.expandPrefix(page, linkPath); WikiPagePath path = PathParser.parse(expandedPath); WikiPage start = path.isRelativePath() ? page.getParent() : page; //TODO -AcD- a better way? return !crawler.pageExists(start, path); } private WikiPageProperty getSymLinkProperty(WikiPageProperties properties) { WikiPageProperty symLinks = properties.getProperty(SymbolicPage.PROPERTY_NAME); if (symLinks == null) symLinks = properties.set(SymbolicPage.PROPERTY_NAME); return symLinks; } }