001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.responders;
004:
005: import fitnesse.wiki.*;
006: import fitnesse.util.*;
007: import fitnesse.html.*;
008: import fitnesse.http.*;
009: import fitnesse.authentication.*;
010: import java.net.*;
011: import java.io.*;
012: import org.w3c.dom.Document;
013:
014: public class WikiImportingResponder extends ChunkingResponder implements
015: XmlizerPageHandler, SecureResponder {
016: public XmlizerPageHandler xmlizerPageHandler = this ;
017:
018: public String remoteHostname;
019:
020: public int remotePort;
021:
022: public WikiPagePath remotePath = new WikiPagePath();
023:
024: public WikiPagePath relativePath = new WikiPagePath();
025:
026: private int alternation = 0;
027:
028: private int importCount = 0;
029:
030: private boolean isUpdate;
031:
032: private boolean isNonRoot;
033:
034: private PageData data;
035:
036: public static String remoteUsername;
037:
038: public static String remotePassword;
039:
040: protected void doSending() throws Exception {
041: data = page.getData();
042: String remoteWikiUrl = establishRemoteUrlAndUpdateStyle();
043: HtmlPage html = makeHtml();
044: response.add(html.preDivision);
045:
046: try {
047: setRemoteUserCredentials();
048: parseUrl(remoteWikiUrl);
049: Document pageTree = getPageTree();
050: addHeadContent();
051: if (isNonRoot)
052: importRemotePageContent(page);
053: new PageXmlizer().deXmlizeSkippingRootLevel(pageTree, page,
054: xmlizerPageHandler);
055: addTailContent();
056:
057: if (!isUpdate) {
058: data.setAttribute("WikiImportRoot", remoteUrl());
059: page.commit(data);
060: }
061: } catch (MalformedURLException e) {
062: writeErrorMessage(e.getMessage());
063: } catch (FileNotFoundException e) {
064: writeErrorMessage("The remote resource, " + remoteUrl()
065: + ", was not found.");
066: } catch (AuthenticationRequiredException e) {
067: writeAuthenticationForm(e.getMessage());
068: } catch (Exception e) {
069: writeErrorMessage(e.toString());
070: }
071:
072: response.add(html.postDivision);
073: response.closeAll();
074: }
075:
076: private void setRemoteUserCredentials() {
077: if (request.hasInput("remoteUsername"))
078: remoteUsername = (String) request
079: .getInput("remoteUsername");
080: if (request.hasInput("remotePassword"))
081: remotePassword = (String) request
082: .getInput("remotePassword");
083: }
084:
085: private String establishRemoteUrlAndUpdateStyle() throws Exception {
086: String remoteWikiUrl = (String) request.getInput("remoteUrl");
087: if (data.hasAttribute("WikiImportRoot")) {
088: remoteWikiUrl = data.getAttribute("WikiImportRoot");
089: isUpdate = true;
090: } else if (data.hasAttribute("WikiImportSource")) {
091: remoteWikiUrl = data.getAttribute("WikiImportSource");
092: isUpdate = true;
093: isNonRoot = true;
094: }
095: return remoteWikiUrl;
096: }
097:
098: private void writeErrorMessage(String message) throws Exception {
099: HtmlTag alert = HtmlUtil.makeDivTag("centered");
100: alert.add(new HtmlTag("h2", "Import Failure"));
101: alert.add(message);
102: response.add(alert.html());
103: }
104:
105: private void addHeadContent() throws Exception {
106: TagGroup head = new TagGroup();
107: if (isUpdate)
108: head.add("Updating imported wiki.");
109: else
110: head.add("Importing wiki.");
111: head.add(" This may take a few moments.");
112: head.add(HtmlUtil.BR);
113: head.add(HtmlUtil.BR);
114: head.add("Destination wiki: ");
115: String pageName = PathParser.render(path);
116: head.add(HtmlUtil.makeLink(pageName, pageName));
117:
118: head.add(HtmlUtil.BR);
119: head.add("Source wiki: ");
120: String remoteWikiUrl = remoteUrl();
121: head.add(HtmlUtil.makeLink(remoteWikiUrl, remoteWikiUrl));
122:
123: head.add(HtmlUtil.BR);
124: head.add(HtmlUtil.BR);
125: head.add("Imported pages:");
126: head.add(HtmlUtil.HR);
127: response.add(head.html());
128: }
129:
130: private void addTailContent() throws Exception {
131: TagGroup tail = new TagGroup();
132: tail.add("<a name=\"end\">" + HtmlUtil.HR + "</a>");
133: tail.add("Import complete. ");
134: if (importCount == 1)
135: tail.add("1 page was imported.");
136: else
137: tail.add(importCount + " pages were imported.");
138: response.add(tail.html());
139: }
140:
141: private HtmlPage makeHtml() throws Exception {
142: HtmlPage html = context.htmlPageFactory.newPage();
143: html = context.htmlPageFactory.newPage();
144: String title = "Wiki Import";
145: if (isUpdate)
146: title += " Update";
147: String localPathName = PathParser.render(path);
148: html.title.use(title + ": " + localPathName);
149: html.header.use(HtmlUtil.makeBreadCrumbsWithPageType(
150: localPathName, title));
151: html.main.add(HtmlPage.BreakPoint);
152: html.divide();
153: return html;
154: }
155:
156: protected PageCrawler getPageCrawler() {
157: return root.getPageCrawler();
158: }
159:
160: public void pageAdded(WikiPage newPage) throws Exception {
161: remotePath.addName(newPage.getName());
162: relativePath.addName(newPage.getName());
163: path.addName(newPage.getName());
164: importRemotePageContent(newPage);
165: }
166:
167: private void importRemotePageContent(WikiPage localPage)
168: throws Exception {
169: try {
170: Document doc = getXmlDocument("data");
171: PageData data = new PageXmlizer().deXmlizeData(doc);
172: data.setAttribute("WikiImportSource", remoteUrl());
173: localPage.commit(data);
174: addRowToResponse("");
175: } catch (AuthenticationRequiredException e) {
176: throw e;
177: } catch (Exception e) {
178: addRowToResponse(e.getMessage());
179: }
180: importCount++;
181: }
182:
183: private String remoteUrl() {
184: String remotePathName = PathParser.render(remotePath);
185: return "http://" + remoteHostname + ":" + remotePort + "/"
186: + remotePathName;
187: }
188:
189: public void exitPage() {
190: remotePath.pop();
191: relativePath.pop();
192: path.pop();
193: }
194:
195: public Document getPageTree() throws Exception {
196: return getXmlDocument("pages");
197: }
198:
199: private Document getXmlDocument(String documentType)
200: throws Exception {
201:
202: String remotePathName = PathParser.render(remotePath);
203: RequestBuilder builder = new RequestBuilder("/"
204: + remotePathName);
205: builder.addInput("responder", "proxy");
206: builder.addInput("type", documentType);
207: builder.setHostAndPort(remoteHostname, remotePort);
208: if (remoteUsername != null)
209: builder.addCredentials(remoteUsername, remotePassword);
210:
211: ResponseParser parser = ResponseParser.performHttpRequest(
212: remoteHostname, remotePort, builder);
213:
214: if (parser.getStatus() == 404)
215: throw new Exception("The remote resource, " + remoteUrl()
216: + ", was not found.");
217: if (parser.getStatus() == 401)
218: throw new AuthenticationRequiredException(remoteUrl());
219:
220: String body = parser.getBody();
221: Document doc = XmlUtil.newDocument(body);
222: return doc;
223: }
224:
225: private void addRowToResponse(String status) throws Exception {
226: HtmlTag tag = HtmlUtil.makeDivTag("alternating_row_"
227: + alternate());
228: String relativePathName = PathParser.render(relativePath);
229: String localPathName = PathParser.render(path);
230: tag.add(HtmlUtil.makeLink(localPathName, relativePathName));
231: tag.add(" " + status);
232: response.add(tag.html());
233: }
234:
235: private int alternate() {
236: alternation = alternation % 2 + 1;
237: return alternation;
238: }
239:
240: public void setResponse(ChunkedResponse response) {
241: this .response = response;
242: }
243:
244: public void parseUrl(String urlString) throws Exception {
245: URL url = null;
246: try {
247: url = new URL(urlString);
248: } catch (MalformedURLException e) {
249: throw new MalformedURLException(urlString
250: + " is not a valid URL.");
251: }
252:
253: remoteHostname = url.getHost();
254: remotePort = url.getPort();
255: if (remotePort == -1)
256: remotePort = 80;
257:
258: String path = url.getPath();
259: if (path.startsWith("/"))
260: path = path.substring(1);
261: remotePath = PathParser.parse(path);
262:
263: if (remotePath == null)
264: throw new MalformedURLException("The URL's resource path, "
265: + path + ", is not a valid WikiWord.");
266: }
267:
268: public SecureOperation getSecureOperation() {
269: return new SecureWriteOperation();
270: }
271:
272: private void writeAuthenticationForm(String resource)
273: throws Exception {
274: HtmlTag html = HtmlUtil.makeDivTag("centered");
275: html.add(new HtmlTag("h3", "The wiki at " + resource
276: + " requires authentication."));
277: html.add(HtmlUtil.BR);
278:
279: HtmlTag form = new HtmlTag("form");
280: form.addAttribute("action", request.getResource());
281: form.addAttribute("method", "post");
282: form
283: .add(HtmlUtil.makeInputTag("hidden", "responder",
284: "import"));
285: if (request.hasInput("remoteUrl"))
286: form.add(HtmlUtil.makeInputTag("hidden", "remoteUrl",
287: (String) request.getInput("remoteUrl")));
288:
289: form.add("remote username: ");
290: form.add(HtmlUtil.makeInputTag("text", "remoteUsername"));
291: form.add(HtmlUtil.BR);
292: form.add("remote password: ");
293: form.add(HtmlUtil.makeInputTag("password", "remotePassword"));
294: form.add(HtmlUtil.BR);
295: form.add(HtmlUtil.makeInputTag("submit", "submit",
296: "Authenticate and Continue Import"));
297:
298: html.add(form);
299: response.add(html.html());
300: }
301:
302: private static class AuthenticationRequiredException extends
303: Exception {
304: private static final long serialVersionUID = 1L;
305:
306: public AuthenticationRequiredException(String message) {
307: super(message);
308: }
309: }
310: }
|