View Javadoc

1   /*
2    * Copyright 2004-2006 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.tuigwaa.cms.core.wiki.base;
17  
18  import java.net.URL;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.seasar.framework.log.Logger;
27  import org.seasar.tuigwaa.cms.core.CmsConstants;
28  import org.seasar.tuigwaa.cms.core.CmsRequest;
29  import org.seasar.tuigwaa.cms.core.CmsResponse;
30  import org.seasar.tuigwaa.cms.core.Resource;
31  import org.seasar.tuigwaa.cms.core.wiki.WikiContext;
32  import org.seasar.tuigwaa.cms.core.wiki.engine.SimpleNode;
33  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiAlias;
34  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiAlign;
35  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiAnnotation;
36  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiAnyOther;
37  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiArgs;
38  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiBlockPlugin;
39  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiCSVTable;
40  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiDefineList;
41  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiDefinedWord;
42  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiDeleteline;
43  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiErrors;
44  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiExcerpt;
45  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiExplanationWord;
46  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiFloatAlign;
47  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiGenerateTree;
48  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiHeading;
49  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiHorizontalline;
50  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiInlinePlugin;
51  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiInterwiki;
52  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiLetters;
53  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiLink;
54  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiList;
55  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiListMember;
56  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiPagename;
57  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiParagraph;
58  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiParserVisitor;
59  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiPreshaped;
60  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiSkipToNewline;
61  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiStrongItalic;
62  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiSyntaxError;
63  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiTable;
64  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiTablecolumn;
65  import org.seasar.tuigwaa.cms.core.wiki.engine.WikiTablemember;
66  import org.seasar.tuigwaa.plugin.Plugin;
67  import org.seasar.tuigwaa.plugin.PluginException;
68  import org.seasar.tuigwaa.plugin.PluginRequest;
69  import org.seasar.tuigwaa.system.Constants;
70  import org.seasar.tuigwaa.system.TgwRuntimeException;
71  import org.seasar.tuigwaa.system.TgwSecurityException;
72  
73  import com.isenshi.util.HtmlBuffer;
74  
75  /***
76   * @author someda
77   */
78  public class HTMLWikiVisitor implements WikiParserVisitor {
79  
80  	private HtmlBuffer buf_ = new HtmlBuffer();
81  
82  	private static final String ANNOTATION_TEXT_PREFIX = "notetext_";
83  
84  	private static final String ANNOTATION_FOOT_PREFIX = "notefoot_";
85  
86  	private static final String ANNOTATION_NOTE_CLASS = "note_super";
87  
88  	private static final String NOTEXIST_CLASS = "notexist";
89  
90  	private static final String CREATIONPAGE_MARK = "?";
91  
92  	private static final String FONTCOLOR_ERROR = "red";
93  
94  	private CmsRequest request_;
95  
96  	private CmsResponse response_;
97  
98  	private WikiConfiguration config_;
99  
100 	private WikiContext ctx;
101 
102 	private List keywords_ = null;
103 
104 	private static final String TAG_SPAN_HIGHLIGHT = "<span class=\"highlight\">";
105 
106 	private static final String TAG_SPAN_CLOSE = "</span>";
107 
108 	private boolean hasCreatePermission = true;
109 
110 	// private static final int FLOAT_WIDTH = 280;
111 
112 	private Logger log_ = Logger.getLogger(getClass());
113 
114 	public HTMLWikiVisitor(CmsRequest request, CmsResponse response,
115 			WikiConfiguration config) {
116 		this.request_ = request;
117 		this.response_ = response;
118 		this.config_ = config;
119 		this.ctx = config.getWikiContext();
120 		keywords_ = (List) request.getAttribute(CmsConstants.PARAM_KEYWORD);
121 	}
122 
123 	public Object visit(SimpleNode node, Object data) {
124 		return null;
125 	}
126 
127 	public Object visit(WikiSyntaxError node, Object data) {
128 		return appendError(node.letter);
129 	}
130 
131 	public Object visit(WikiSkipToNewline node, Object data) {
132 		buf_.appendBody(VisitorUtils.escape(node.letter));
133 		return null;
134 	}
135 
136 	public Object visit(WikiGenerateTree node, Object data) {
137 
138 		for (int i = 0; i < node.jjtGetNumChildren(); i++)
139 			node.jjtGetChild(i).jjtAccept(this, data);
140 
141 		if (node.annotation.size() > 0) {
142 			buf_.appendStartTag("hr");
143 			buf_.appendAttribute("class", "note_hr");
144 			buf_.appendAttribute("align", "left");
145 			buf_.endTag();
146 
147 			Iterator itr = node.annotation.iterator();
148 			int idx = 1;
149 			buf_.setNewline(false);
150 			while (itr.hasNext()) {
151 				buf_.setTab(false);
152 				appendSuper(buf_, ANNOTATION_FOOT_PREFIX + idx,
153 						ANNOTATION_NOTE_CLASS, WikiHelper.ANCHOR_MARK
154 								+ ANNOTATION_TEXT_PREFIX + idx, "*" + idx);
155 				buf_.setTab(true);
156 
157 				SimpleNode n = (SimpleNode) itr.next();
158 				for (int i = 0; i < n.jjtGetNumChildren(); i++) {
159 					n.jjtGetChild(i).jjtAccept(this, data);
160 				}
161 				buf_.appendBr();
162 				idx++;
163 			}
164 			buf_.setNewline(true);
165 		}
166 		return buf_.toString();
167 	}
168 
169 	public Object visit(WikiParagraph node, Object data) {
170 		buf_.appendStartTag("p");
171 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
172 			node.jjtGetChild(i).jjtAccept(this, data);
173 		}
174 		buf_.endTag();
175 		return null;
176 	}
177 
178 	public Object visit(WikiExcerpt node, Object data) {
179 
180 		boolean isTagNeed = VisitorUtils.isExcerptStartNeeded(node);
181 
182 		if (isTagNeed)
183 			buf_.appendStartTag("blockquote");
184 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
185 			// if child is paragraph, not generate <p> tag
186 			if (node.jjtGetChild(i) instanceof WikiParagraph) {
187 				WikiParagraph p = (WikiParagraph) node.jjtGetChild(i);
188 				for (int j = 0; j < p.jjtGetNumChildren(); j++)
189 					p.jjtGetChild(j).jjtAccept(this, data);
190 			} else {
191 				node.jjtGetChild(i).jjtAccept(this, data);
192 			}
193 		}
194 		changeTabAndNewlineState(true);
195 		if (isTagNeed)
196 			buf_.endTag();
197 		return null;
198 	}
199 
200 	public Object visit(WikiList node, Object data) {
201 
202 		int curtype = 0;
203 		int curlevel = 0;
204 		int pretype = 0;
205 		int prelevel = 0;
206 		int[] level = { 0, 0, 0 };
207 
208 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
209 
210 			if (node.jjtGetChild(i) instanceof WikiListMember) {
211 				WikiListMember child = (WikiListMember) node.jjtGetChild(i);
212 
213 				curtype = child.type;
214 				curlevel = child.level;
215 
216 				// upward level change
217 				if (curlevel > prelevel)
218 					startListTag(curtype);
219 
220 				// downward level change
221 				if (curlevel < prelevel) {
222 					for (int j = curlevel; j < prelevel; j++) {
223 						if (level[j] != 0) {
224 							buf_.endTag();
225 							level[j] = 0;
226 						}
227 					}
228 					if (level[curlevel - 1] != curtype) {
229 						buf_.endTag();
230 						startListTag(curtype);
231 					}
232 				}
233 
234 				// not level change but type change
235 				if (curlevel == prelevel && curtype != pretype) {
236 					buf_.endTag();
237 					startListTag(curtype);
238 				}
239 
240 				// change state
241 				if (curlevel != prelevel || curtype != pretype) {
242 					level[curlevel - 1] = curtype;
243 					pretype = curtype;
244 					prelevel = curlevel;
245 				}
246 				child.jjtAccept(this, data);
247 			}
248 		}
249 
250 		// close all list related tag
251 		for (int i = 0; i < level.length; i++)
252 			if (level[i] != 0)
253 				buf_.endTag();
254 		return null;
255 	}
256 
257 	private void startListTag(int type) {
258 		if (type == WikiHelper.LIST_TYPE_NORMAL) {
259 			buf_.appendStartTag("ul");
260 		} else if (type == WikiHelper.LIST_TYPE_NUMERICAL) {
261 			buf_.appendStartTag("ol");
262 		}
263 	}
264 
265 	public Object visit(WikiDefineList node, Object data) {
266 		buf_.appendStartTag("dl");
267 		for (int i = 0; i < node.jjtGetNumChildren(); i++)
268 			node.jjtGetChild(i).jjtAccept(this, data);
269 		buf_.endTag();
270 		return null;
271 	}
272 
273 	public Object visit(WikiPreshaped node, Object data) {
274 		buf_.appendStartTag("pre");
275 		changeTabAndNewlineState(false);
276 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
277 			node.jjtGetChild(i).jjtAccept(this, data);
278 			buf_.appendBody(CmsConstants.LINEBREAK_CODE);
279 		}
280 		buf_.setNewline(true);
281 		buf_.endTag();
282 		buf_.setTab(true);
283 		return null;
284 	}
285 
286 	public Object visit(WikiTable node, Object data) {
287 		processTable(node, data);
288 		return null;
289 	}
290 
291 	// shared by WikiTable and WikiCSVTable
292 	private void processTable(SimpleNode node, Object data) {
293 
294 		VisitorUtils.prepareWikiTable(node, data);
295 		int prenum = 0;
296 		int open = 0;
297 		boolean isBody = false;
298 
299 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
300 
301 			try {
302 				WikiTablemember child = (WikiTablemember) node.jjtGetChild(i);
303 				if (child.jjtGetNumChildren() != prenum) { // start table
304 					if (prenum != 0) {
305 						if (isBody)
306 							buf_.endTag();
307 						buf_.endTag();
308 						isBody = false;
309 						open--;
310 					}
311 					buf_.appendStartTag("table");
312 					open++;
313 				}
314 				if (!isBody) {
315 					if (child.type == WikiHelper.TABLE_TYPE_HEADER) {
316 						buf_.appendStartTag("thead");
317 					} else if (child.type == WikiHelper.TABLE_TYPE_FOOTER) {
318 						buf_.appendStartTag("tfooter");
319 					} else {
320 						buf_.appendStartTag("tbody");
321 						isBody = true;
322 					}
323 				}
324 
325 				prenum = child.jjtGetNumChildren();
326 				child.jjtAccept(this, data);
327 
328 				if (!isBody) {
329 					buf_.endTag();
330 				}
331 			} catch (ClassCastException cce) {// in-case wikierror
332 				while (open > 0) {
333 					if (isBody)
334 						buf_.endTag();
335 					buf_.endTag();
336 					open--;
337 					prenum = 0;
338 					isBody = false;
339 				}
340 				node.jjtGetChild(i).jjtAccept(this, data);
341 				buf_.setNewline(true);
342 			}
343 		}
344 		while (open > 0) {
345 			if (isBody)
346 				buf_.endTag();
347 			buf_.endTag();
348 			open--;
349 		}
350 	}
351 
352 	public Object visit(WikiTablemember node, Object data) {
353 
354 		buf_.appendStartTag("tr");
355 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
356 			node.jjtGetChild(i).jjtAccept(this, data);
357 		}
358 		buf_.setTab(false);
359 		buf_.endTag();
360 		buf_.setTab(true);
361 		return null;
362 	}
363 
364 	public Object visit(WikiTablecolumn node, Object data) {
365 
366 		Map attrs = new HashMap();
367 		if (!node.iscolspan && !node.isrowspan) {
368 			String str = getChildString(node, data, 0);
369 
370 			if (node.align != null)
371 				attrs.put(HtmlBuffer.TAG_STYLE, "text-align:" + node.align
372 						+ ";");
373 
374 			if (node.bgcolor != null) {
375 				String style;
376 				if ((style = (String) attrs.get(HtmlBuffer.TAG_STYLE)) != null) {
377 					style += "background-color:" + node.bgcolor + ";";
378 					attrs.put(HtmlBuffer.TAG_STYLE, style);
379 				} else {
380 					attrs.put(HtmlBuffer.TAG_STYLE, "background-color:"
381 							+ node.bgcolor + ";");
382 				}
383 			}
384 
385 			if (node.color != null) {
386 				String style;
387 				if ((style = (String) attrs.get(HtmlBuffer.TAG_STYLE)) != null) {
388 					style += "color:" + node.color + ";";
389 					attrs.put(HtmlBuffer.TAG_STYLE, style);
390 				} else {
391 					attrs
392 							.put(HtmlBuffer.TAG_STYLE, "color:" + node.color
393 									+ ";");
394 				}
395 			}
396 
397 			if (node.size != null) {
398 				String style;
399 				if ((style = (String) attrs.get(HtmlBuffer.TAG_STYLE)) != null) {
400 					style += "font-size:" + node.size + ";";
401 					attrs.put(HtmlBuffer.TAG_STYLE, style);
402 				} else {
403 					attrs.put(HtmlBuffer.TAG_STYLE, "font-size:" + node.size
404 							+ ";");
405 				}
406 			}
407 
408 			if (node.colspannum > 0)
409 				attrs.put("colspan", ++node.colspannum + "");
410 
411 			if (node.rowspannum > 0)
412 				attrs.put("rowspan", ++node.rowspannum + "");
413 
414 			buf_.appendTd(str, attrs, false);
415 		}
416 		return null;
417 	}
418 
419 	public Object visit(WikiCSVTable node, Object data) {
420 		processTable(node, data);
421 		return null;
422 	}
423 
424 	public Object visit(WikiHeading node, Object data) {
425 
426 		String childstr = getChildString(node, data, 0);
427 		Resource resource = request_.getPage().getResource();
428 		String lockuser = resource.getProperty(CmsConstants.PROPERTY_LOCKUSER);
429 
430 		if (lockuser == null && request_.getMode() != CmsConstants.MODE_FULL) {
431 			String anchorid = VisitorUtils.getAnchorId(node);
432 			if (anchorid != null && !"".equals(anchorid)) {
433 				String pagename = resource.getPath();
434 				if (hasCreatePermission) {
435 					try {
436 						URL url = ctx.getEditPageURL(pagename, request_);
437 						String href = url.toString();
438 						href += "&amp;" + Constants.PARAM_PAGESECTIONID + "="
439 								+ anchorid.substring(1);
440 						href += request_.getURLEncodedQuery();
441 						HtmlBuffer anchorbuf = new HtmlBuffer();
442 						anchorbuf.setNewline(false);
443 						anchorbuf.setTab(false);
444 						appendSuper(anchorbuf, null, "anchor_super", href,
445 								" edit");
446 						childstr += anchorbuf.toString();
447 					} catch (TgwSecurityException tse) {
448 						hasCreatePermission = false;
449 					}
450 				}
451 			}
452 		}
453 		buf_.appendHeading(node.level + 1, childstr);
454 		return null;
455 	}
456 
457 	public Object visit(WikiAlign node, Object data) {
458 
459 		String align = node.image.toLowerCase().substring(0,
460 				node.image.length() - 1);
461 		buf_.appendStartTag("div");
462 		buf_.appendAttribute("align", align);
463 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
464 			node.jjtGetChild(i).jjtAccept(this, data);
465 		}
466 		buf_.endTag();
467 		return null;
468 	}
469 
470 	public Object visit(WikiFloatAlign node, Object data) {
471 
472 		String align = node.image.toLowerCase().substring(1,
473 				node.image.length() - 1);
474 		int idx = 0;
475 		String widthStr = null;
476 		if ((idx = align.indexOf("(")) != -1) {
477 			widthStr = WikiHelper.deleteParenthesis(align, "(", ")");
478 			align = align.substring(0, idx);
479 		}
480 
481 		buf_.appendStartTag("div");
482 		if (widthStr != null) {
483 			buf_.appendAttribute("style", "float:" + align + "; width: "
484 					+ widthStr + "px;");
485 		} else {
486 			buf_.appendAttribute("style", "float:" + align + ";");
487 		}
488 
489 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
490 			node.jjtGetChild(i).jjtAccept(this, data);
491 		}
492 		buf_.endTag();
493 
494 		return null;
495 	}
496 
497 	public Object visit(WikiHorizontalline node, Object data) {
498 		buf_.appendStartTag("hr");
499 		buf_.endTag();
500 		return null;
501 	}
502 
503 	public Object visit(WikiBlockPlugin node, Object data) {
504 
505 		String name = node.name;
506 		boolean ispluginused = false;
507 
508 		PluginRequest prequest = VisitorUtils.createPluginRequest(node);
509 
510 		String childStr = getChildString(node, data, 0);
511 		if (childStr != null && !Constants.LINEBREAK_CODE.equals(childStr)) {
512 			prequest.setChild(WikiHelper.deleteParenthesis(childStr, "{", "}"));
513 		}
514 
515 		if (config_.isPluginLoaded(name)) {
516 			Plugin plugin = config_.getPlugin(name);
517 			try {
518 				buf_.appendBody((String) plugin.service(request_, response_,
519 						prequest));
520 				ispluginused = true;
521 			} catch (PluginException pe) {
522 				log_.error(pe.getMessage());
523 			} catch (TgwRuntimeException e) {
524 				log_.log(e);
525 			} catch (Exception e) {
526 				e.printStackTrace();
527 				// some exception handling framework needed
528 			}
529 		}
530 
531 		if (!ispluginused)
532 			buf_.appendBody("#" + prequest.toString());
533 
534 		return null;
535 	}
536 
537 	public Object visit(WikiLetters node, Object data) {
538 
539 		changeTabAndNewlineState(false);
540 		String letters = (node.isHTMLescape) ? VisitorUtils.escape(node.letter)
541 				: node.letter;
542 		String bodyString = processKeyword(letters);
543 
544 		if (node.isEmail) {
545 			buf_.appendAnchor("mailto:" + node.letter, bodyString);
546 		} else if (node.isURL) {
547 			if (WikiHelper.isImage(node.letter)) {
548 				buf_.appendStartTag("a");
549 				buf_.appendAttribute("href", node.letter);
550 				buf_.appendImg(node.letter, bodyString, 0, null);
551 				buf_.endTag();
552 			} else {
553 				buf_.appendAnchor(node.letter, bodyString);
554 			}
555 		} else if (node.isAnchor) {
556 			String id = (node.letter.startsWith("#")) ? node.letter
557 					.substring(1) : node.letter;
558 			if (request_.getMode() != CmsConstants.MODE_FULL) {
559 				appendSuper(buf_, id, "anchor_super", bodyString, "&dagger;");
560 			} else {
561 				appendSuper(buf_, id, "anchor_super", bodyString, "&nbsp;");
562 			}
563 		} else if (node.isWikiname) {
564 			processSecurityLink(node.letter, bodyString, null);
565 		} else if (node.isNewline) {
566 			buf_.appendBr();
567 		} else {
568 			buf_.appendBody(bodyString);
569 		}
570 		changeTabAndNewlineState(true);
571 		return null;
572 	}
573 
574 	public Object visit(WikiStrongItalic node, Object data) {
575 
576 		int tag = 0;
577 		changeTabAndNewlineState(false);
578 
579 		if (VisitorUtils.isBold(node)) {
580 			buf_.appendStartTag("strong");
581 			tag++;
582 		}
583 
584 		if (VisitorUtils.isItalic(node)) {
585 			buf_.appendStartTag("em");
586 			tag++;
587 		}
588 
589 		String pre = VisitorUtils.getAppendString(node, true);
590 		String post = VisitorUtils.getAppendString(node, false);
591 
592 		if (pre != null)
593 			buf_.appendBody(pre);
594 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
595 			node.jjtGetChild(i).jjtAccept(this, data);
596 		}
597 		changeTabAndNewlineState(false);
598 		if (post != null)
599 			buf_.appendBody(post);
600 
601 		for (int i = 0; i < tag; i++)
602 			buf_.endTag();
603 
604 		return null;
605 	}
606 
607 	public Object visit(WikiDeleteline node, Object data) {
608 		changeTabAndNewlineState(false);
609 		buf_.appendStartTag("del");
610 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
611 			node.jjtGetChild(i).jjtAccept(this, data);
612 		}
613 		changeTabAndNewlineState(false);
614 		buf_.endTag();
615 		return null;
616 	}
617 
618 	public Object visit(WikiAnnotation node, Object data) {
619 		buf_.setNewline(false);
620 		buf_.appendStartTag("a");
621 		buf_.appendAttribute("id", ANNOTATION_TEXT_PREFIX + node.num);
622 		buf_.appendAttribute("class", ANNOTATION_NOTE_CLASS);
623 		buf_.appendAttribute("href", "#" + ANNOTATION_FOOT_PREFIX + node.num);
624 		buf_.appendBody("*" + node.num);
625 		buf_.endTag();
626 		buf_.setNewline(true);
627 		return null;
628 	}
629 
630 	// interwiki not implemented...
631 	public Object visit(WikiInterwiki node, Object data) {
632 		buf_.appendBody("[[" + node.image + "]]");
633 		return null;
634 	}
635 
636 	public Object visit(WikiLink node, Object data) {
637 		String[] s = WikiHelper.split(node.image, WikiHelper.LINK_DELIMITER);
638 		buf_.appendAnchor(s[1], s[0], true);
639 		return null;
640 	}
641 
642 	public Object visit(WikiAlias node, Object data) {
643 		String[] s = WikiHelper.split(node.image, WikiHelper.ALIAS_DELIMITER);
644 
645 		changeTabAndNewlineState(false);
646 		if (node.islink) {
647 			buf_.appendAnchor(s[1], s[0], true);
648 		} else {
649 			String[] t = WikiHelper.split(s[1], WikiHelper.ANCHOR_MARK);
650 			if (t[0] == null || t[0].equals("")) {
651 				buf_.appendAnchor(WikiHelper.ANCHOR_MARK + t[1], s[0]);
652 			} else {
653 				processSecurityLink(t[0], s[0], t[1]);
654 			}
655 		}
656 		changeTabAndNewlineState(true);
657 		return null;
658 	}
659 
660 	public Object visit(WikiPagename node, Object data) {
661 		String[] s = WikiHelper.split(node.image, WikiHelper.ANCHOR_MARK);
662 		changeTabAndNewlineState(false);
663 		processSecurityLink(s[0], s[0], s[1]);
664 		changeTabAndNewlineState(true);
665 		return null;
666 	}
667 
668 	public Object visit(WikiInlinePlugin node, Object data) {
669 		String name = node.name;
670 
671 		boolean ispluginused = false;
672 		int inlinestart = 0;
673 		PluginRequest prequest = VisitorUtils.createPluginRequest(node);
674 		if (prequest.getArgs() != null)
675 			inlinestart = 1;
676 
677 		String childstr = getChildString(node, data, inlinestart);
678 		prequest.setChild(childstr);
679 
680 		changeTabAndNewlineState(false);
681 
682 		if (config_.isPluginLoaded(name)) {
683 			Plugin plugin = config_.getPlugin(name);
684 			try {
685 				buf_.appendBody((String) plugin.service(request_, response_,
686 						prequest));
687 				ispluginused = true;
688 			} catch (PluginException pe) {
689 				log_.error(pe.getMessage());
690 			} catch (TgwRuntimeException e) {
691 				log_.log(e);
692 			} catch (Exception e) {
693 				e.printStackTrace();
694 				// some exception handling framework needed
695 			}
696 		}
697 
698 		if (!ispluginused) {
699 			if ("amp".equals(name)) {
700 				buf_.appendBody("&");
701 			} else {
702 				buf_.appendBody("&amp;" + prequest.toString() + ";");
703 			}
704 		}
705 		changeTabAndNewlineState(true);
706 		return null;
707 	}
708 
709 	public Object visit(WikiArgs node, Object data) {
710 		return null;
711 	}
712 
713 	public Object visit(WikiErrors node, Object data) {
714 		return appendError(node.letter);
715 	}
716 
717 	public Object visit(WikiListMember node, Object data) {
718 		buf_.appendStartTag("li");
719 
720 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
721 			node.jjtGetChild(i).jjtAccept(this, data);
722 		}
723 		buf_.setTab(false);
724 		buf_.endTag();
725 		buf_.setTab(true);
726 		return null;
727 	}
728 
729 	public Object visit(WikiDefinedWord node, Object data) {
730 		if (node.jjtGetNumChildren() > 0) {
731 			buf_.appendStartTag("dt");
732 			for (int i = 0; i < node.jjtGetNumChildren(); i++) {
733 				node.jjtGetChild(i).jjtAccept(this, data);
734 			}
735 			buf_.setTab(false);
736 			buf_.endTag();
737 			buf_.setTab(true);
738 		}
739 		return null;
740 	}
741 
742 	public Object visit(WikiExplanationWord node, Object data) {
743 		buf_.appendStartTag("dd");
744 		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
745 			node.jjtGetChild(i).jjtAccept(this, data);
746 		}
747 		buf_.setTab(false);
748 		buf_.endTag();
749 		buf_.setTab(true);
750 		return null;
751 	}
752 
753 	public Object visit(WikiAnyOther node, Object data) {
754 		changeTabAndNewlineState(false);
755 		buf_.appendBody(node.letter);
756 		return null;
757 	}
758 
759 	private String getChildString(SimpleNode node, Object data, int idx) {
760 		int start = buf_.nextIndex();
761 		String childstr = null;
762 		buf_.setTab(false);
763 		for (int i = idx; i < node.jjtGetNumChildren(); i++) {
764 			node.jjtGetChild(i).jjtAccept(this, data);
765 		}
766 		int end = buf_.nextIndex();
767 		if (start != end)
768 			childstr = buf_.cut(start, end);
769 		buf_.setTab(true);
770 
771 		return childstr;
772 	}
773 
774 	private void processSecurityLink(String pagename, String body, String anchor) {
775 		try {
776 			if (ctx.isPageExist(pagename, request_)) {
777 				Resource resource = ctx.getResource(request_, pagename);
778 				if (resource.isFolder()) {
779 					if (!pagename.endsWith("/"))
780 						pagename = pagename + "/";
781 				}
782 				URL url = ctx.getURLByName(pagename, request_);
783 				if (anchor == null || "".equals(anchor)) {
784 					buf_.appendAnchor(url.toString(), body);
785 				} else {
786 					buf_.appendAnchor(url.toString() + WikiHelper.ANCHOR_MARK
787 							+ anchor, body);
788 				}
789 			} else if (request_.getMode() != CmsConstants.MODE_FULL) {
790 				URL url = ctx.getCreatePageURL(pagename, request_);
791 				buf_.appendAnchor(url.toString(), CREATIONPAGE_MARK);
792 				buf_.appendStartTag("span");
793 				buf_.appendAttribute("class", NOTEXIST_CLASS);
794 				buf_.appendBody(body);
795 				buf_.endTag();
796 			} else {
797 				buf_.appendBody(body);
798 			}
799 		} catch (TgwSecurityException tse) {
800 			buf_.appendBody(body);
801 		}
802 	}
803 
804 	private Object appendError(String str) {
805 		buf_.setNewline(false);
806 		buf_.appendStartTag("span");
807 		buf_.appendAttribute("style", "color:" + FONTCOLOR_ERROR + ";");
808 		buf_.appendBody(str);
809 		buf_.endTag();
810 		buf_.setNewline(true);
811 		return null;
812 	}
813 
814 	private void changeTabAndNewlineState(boolean flag) {
815 		buf_.setNewline(flag);
816 		buf_.setTab(flag);
817 	}
818 
819 	private String processKeyword(String letter) {
820 		String ret = letter;
821 		if (keywords_ != null) {
822 			for (Iterator i = keywords_.iterator(); i.hasNext();) {
823 				String s = (String) i.next();
824 				ret = ret
825 						.replaceAll(s, TAG_SPAN_HIGHLIGHT + s + TAG_SPAN_CLOSE);
826 			}
827 		}
828 		return ret;
829 	}
830 
831 	private void appendSuper(HtmlBuffer buf, String styleId, String styleClass,
832 			String href, String body) {
833 		buf.appendStartTag("a");
834 		if (styleId != null)
835 			buf.appendAttribute("id", styleId);
836 		if (styleClass != null)
837 			buf.appendAttribute("class", styleClass);
838 		buf.appendAttribute("href", href);
839 		buf.appendBody(body);
840 		buf.endTag();
841 	}
842 
843 }