001: /**
002: * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the latest version of the GNU Lesser General
006: * Public License as published by the Free Software Foundation;
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program (LICENSE.txt); if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
016: */package org.jamwiki.utils;
017:
018: import java.io.BufferedReader;
019: import java.io.File;
020: import java.io.FileReader;
021: import java.io.Reader;
022: import java.sql.Timestamp;
023: import java.text.SimpleDateFormat;
024: import java.util.Date;
025: import java.util.LinkedHashMap;
026: import java.util.Vector;
027: import java.util.logging.Logger;
028: import org.jamwiki.WikiBase;
029: import org.jamwiki.model.Topic;
030: import org.jamwiki.model.TopicVersion;
031: import org.jamwiki.model.WikiUser;
032:
033: /**
034: * This class parse a TiddlyWiki file and imports it to JamWiki
035: * @author Michael Greifeneder mikegr@gmx.net
036: */
037: public class TiddlyWikiParser {
038:
039: private static final Logger logger = Logger
040: .getLogger(TiddlyWikiParser.class.getName());
041:
042: private static final String DIV_START = "<div tiddler";
043: private static final String DIV_END = "</div>";
044: private static final String TIDLLER = "tiddler";
045: //private static final String MODIFIER = "modifier";
046: private static final String MODIFIED = "modified";
047: //private static final String TAGS = "tags";
048: private static final SimpleDateFormat formater = new SimpleDateFormat(
049: "yyyyMMddHHmm");
050: private StringBuffer messages = new StringBuffer();
051: private String virtualWiki;
052: private WikiUser user;
053: private String authorIpAddress;
054:
055: /**
056: * Facade for WikiBase. Used for enable unit testing.
057: * @author Michael Greifeneder mikegr@gmx.net
058: */
059: public interface WikiBaseFascade {
060: public void writeTopic(Topic topic, TopicVersion topicVersion,
061: LinkedHashMap categories, Vector links,
062: boolean userVisible, Object transactionObject)
063: throws Exception;
064: }
065:
066: /**
067: * Defaul WikiBaseFascade for production.
068: */
069: private WikiBaseFascade wikiBase = new WikiBaseFascade() {
070: public void writeTopic(Topic topic, TopicVersion topicVersion,
071: LinkedHashMap categories, Vector links,
072: boolean userVisible, Object transactionObject)
073: throws Exception {
074: WikiBase.getDataHandler().writeTopic(topic, topicVersion,
075: null, null, true, null);
076: }
077: };
078:
079: private TiddlyWiki2MediaWikiTranslator translator = new TiddlyWiki2MediaWikiTranslator();
080:
081: /**
082: * Main constructor
083: * @param virtualWiki virtualWiki
084: * @param user user who is currently logged in
085: * @param authorIpAddress IP address of uploading user
086: */
087: public TiddlyWikiParser(String virtualWiki, WikiUser user,
088: String authorIpAddress) {
089: this .virtualWiki = virtualWiki;
090: this .user = user;
091: this .authorIpAddress = authorIpAddress;
092: }
093:
094: /**
095: * Use this contructor for test cases
096: * @param virtualWiki Name of VirtualWiki
097: * @param user User who is logged in.
098: * @param authorIpAddress IP address of uploading user.
099: * @param wikiBase Overwrites default WikiBaseFascade
100: */
101: public TiddlyWikiParser(String virtualWiki, WikiUser user,
102: String authorIpAddress, WikiBaseFascade wikiBase) {
103: this (virtualWiki, user, authorIpAddress);
104: this .wikiBase = wikiBase;
105: }
106:
107: /** Parses file and returns default topic.
108: * @param file TiddlyWiki file
109: * @return main topic for this TiddlyWiki
110: */
111: public String parse(File file) throws Exception {
112: Reader r = new FileReader(file);
113: BufferedReader br = new BufferedReader(r);
114: return parse(br);
115: }
116:
117: /** Parses TiddlyWiki content and returns default topic.
118: * @param br TiddlyWiki file content
119: * @return main topic for this TiddlyWiki
120: */
121: public String parse(BufferedReader br) throws Exception {
122: String line = br.readLine();
123: boolean inTiddler = false;
124: int start = 0;
125: int end = 0;
126: StringBuffer content = new StringBuffer();
127: while (line != null) {
128: if (inTiddler) {
129: end = line.indexOf(DIV_END);
130: if (end != -1) {
131: inTiddler = false;
132: content.append(line.substring(0, end));
133: proecessContent(content.toString());
134: content.setLength(0);
135: line = line.substring(end);
136: } else {
137: content.append(line);
138: line = br.readLine();
139: }
140: } else {
141: start = line.indexOf(DIV_START);
142: if (start != -1
143: && (line.indexOf("<div tiddler=\"%0\"") == -1)) {
144: inTiddler = true;
145: logger.fine("Ignoring:\n"
146: + line.substring(0, start));
147: line = line.substring(start);
148: } else {
149: logger.fine("Div tiddler not found in: \n" + line);
150: line = br.readLine();
151: }
152: }
153: }
154: return "DefaultTiddlers";
155: }
156:
157: private void proecessContent(String content) throws Exception {
158: logger.fine("Content: " + content);
159: String name = findName(content, TIDLLER);
160: if (name == null || "%0".equals(user)) {
161: return;
162: }
163: /* no need for user
164: String user = findName(content, MODIFIER);
165: if (user == null ) {
166: messages.append("WARN: ")
167: return;
168: }
169: */
170: Date lastMod = null;
171: try {
172: lastMod = formater.parse(findName(content, MODIFIED));
173: } catch (Exception e) {
174: messages.append("WARNING: corrupt line: " + content);
175: }
176: if (lastMod == null) {
177: return;
178: }
179: /* ignoring tags
180: String tags = findName(content, TAGS);
181: if (tags == null) {
182: return;
183: }
184: */
185: int idx = content.indexOf(">");
186: if (idx == -1) {
187: logger.warning("No closing of tag");
188: messages.append("WARNING: corrupt line: " + content);
189: return;
190: }
191: String wikicode = content.substring(idx + 1);
192: wikicode = translator.translate(wikicode);
193: messages.append("Adding topic " + name + "\n");
194: saveTopic(name, lastMod, wikicode);
195: logger.fine("Code:" + wikicode);
196: }
197:
198: private void saveTopic(String name, Date lastMod, String content)
199: throws Exception {
200: Topic topic = new Topic();
201: topic.setName(name);
202: topic.setVirtualWiki(virtualWiki);
203: topic.setTopicContent(content);
204: TopicVersion topicVersion = new TopicVersion(user,
205: authorIpAddress, "imported", content);
206: topicVersion.setEditDate(new Timestamp(lastMod.getTime()));
207: // manage mapping bitween MediaWiki and JAMWiki namespaces
208: topic.setTopicType(Topic.TYPE_ARTICLE);
209: // Store topic in database
210: wikiBase
211: .writeTopic(topic, topicVersion, null, null, true, null);
212: }
213:
214: private String findName(String content, String name) {
215: int startIdx = content.indexOf(name);
216: if (startIdx == -1) {
217: logger.warning("no tiddler name found");
218: return null;
219: }
220: startIdx = content.indexOf("\"", startIdx);
221: int endIdx = content.indexOf("\"", startIdx + 1);
222: String value = content.substring(startIdx + 1, endIdx);
223: logger.fine(name + ":" + value);
224: return value;
225: }
226:
227: public String getOutput() {
228: return messages.toString();
229: }
230: }
|