[seam-commits] Seam SVN: r8348 - in trunk/examples/wiki: src/etc/WEB-INF and 37 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Fri Jun 6 20:25:04 EDT 2008


Author: christian.bauer at jboss.com
Date: 2008-06-06 20:25:03 -0400 (Fri, 06 Jun 2008)
New Revision: 8348

Added:
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiHttpSessionManager.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiServletListener.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryDisplayPositionComparator.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryNameComparator.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiURLRenderer.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiFormattedTextValidator.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextPreview.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextValidator.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLink.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLinkResolver.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiTextParser.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/DefaultWikiTextRenderer.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/MacroWikiTextRenderer.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/NullWikiTextRenderer.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/WikiTextRenderer.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/MacroComponentHandler.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/MacroIncludeTextRenderer.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIMacro.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIWikiFormattedText.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/WikiFormattedTextHandler.java
   trunk/examples/wiki/view/includes/admin/sessionManager.xhtml
   trunk/examples/wiki/view/includes/onlineUsers.xhtml
Removed:
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/engine/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/renderer/
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/MacroComponentHandler.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIMacro.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIWikiFormattedText.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFormattedTextHandler.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiTextEditor.java
Modified:
   trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml
   trunk/examples/wiki/src/etc/WEB-INF/components.xml
   trunk/examples/wiki/src/etc/WEB-INF/faces-config.xml
   trunk/examples/wiki/src/etc/WEB-INF/web.xml
   trunk/examples/wiki/src/etc/i18n/messages_en.properties
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Authenticator.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/CommentHome.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DefaultWikiLinkResolver.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DocumentHome.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Help.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Menu.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/NodeHome.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/UserHome.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/WikiIdentity.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/captcha/WikiCaptchaValidator.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserDAO.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserRoleAccessFactory.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/WikiNodeDAO.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedDAO.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedEntryManager.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/LinkProtocol.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/UserProfile.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFile.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeInfo.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/query/NestedSetNodeWrapper.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/Plugin.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginInfo.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginModule.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/preferences/template/WriteProtectedAreaTemplate.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/search/WikiSearchSupport.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FileServlet.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFaceletsResourceResolver.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiRedirect.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/UploadHandler.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/WikiUploadImageHandler.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/preferences/metamodel/PreferenceEntity.java
   trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirMenu.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirTocQuery.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DocPager.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/LastModifiedDocuments.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/faqBrowser/templates/faqQuestionForm.xhtml
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumQuery.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ReplyHome.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/TopicHome.java
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/lastTopicPost.xhtml
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/replyForm.xhtml
   trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/topicForm.xhtml
   trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/editing/Linking.java
   trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/preferences/InstancePreferencesTests.java
   trunk/examples/wiki/view/adminHome_d.xhtml
   trunk/examples/wiki/view/docEdit_d.xhtml
   trunk/examples/wiki/view/includes/commentForm.xhtml
   trunk/examples/wiki/view/includes/wikiTextEditor.xhtml
   trunk/examples/wiki/view/includes/wikiTextPreview.xhtml
   trunk/examples/wiki/view/themes/default/css/template.css
   trunk/examples/wiki/view/themes/default/template.xhtml
   trunk/examples/wiki/view/themes/inrelationto/css/inrelationto.css
   trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css
   trunk/examples/wiki/view/themes/sfwkorg/template.xhtml
   trunk/examples/wiki/view/userHome_d.xhtml
Log:
New session monitor, improved wiki text editor, minor optimizations

Modified: trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml
===================================================================
--- trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/etc/META-INF/wiki.taglib.xml	2008-06-07 00:25:03 UTC (rev 8348)
@@ -37,6 +37,31 @@
     </function>
 
     <function>
+        <function-name>toDate</function-name>
+        <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
+        <function-signature>java.util.Date toDate(java.lang.Long)</function-signature>
+    </function>
+
+    <function>
+        <function-name>getTimeDifference</function-name>
+        <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
+        <function-signature>java.lang.String getTimeDifference(java.util.Date,java.util.Date)</function-signature>
+    </function>
+
+    <function>
+        <function-name>getTimeDifferenceToCurrent</function-name>
+        <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
+        <function-signature>java.lang.String getTimeDifferenceToCurrent(java.util.Date)</function-signature>
+    </function>
+
+    <function>
+        <function-name>currentDate</function-name>
+        <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
+        <function-signature>java.util.Date currentDate()</function-signature>
+    </function>
+
+
+    <function>
         <function-name>concat</function-name>
         <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
         <function-signature>java.lang.String concat(java.lang.String,java.lang.String)</function-signature>
@@ -85,12 +110,6 @@
     </function>
 
     <function>
-        <function-name>hasMessage</function-name>
-        <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
-        <function-signature>boolean hasMessage(java.lang.String,java.lang.String)</function-signature>
-    </function>
-
-    <function>
         <function-name>escapeJSMessage</function-name>
         <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
         <function-signature>java.lang.String escapeJSMessage(java.lang.String)</function-signature>
@@ -139,6 +158,12 @@
     </function>
 
     <function>
+        <function-name>isGuestOrAdminUsername</function-name>
+        <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
+        <function-signature>boolean isGuestOrAdminUsername(java.lang.String)</function-signature>
+    </function>
+
+    <function>
         <function-name>isLastItemInList</function-name>
         <function-class>org.jboss.seam.wiki.util.WikiUtil</function-class>
         <function-signature>boolean isLastItemInList(java.util.List,java.lang.Object)</function-signature>
@@ -152,7 +177,7 @@
 
     <tag>
         <tag-name>formattedText</tag-name>
-		<handler-class>org.jboss.seam.wiki.core.ui.WikiFormattedTextHandler</handler-class> 
+		<handler-class>org.jboss.seam.wiki.core.wikitext.renderer.jsf.WikiFormattedTextHandler</handler-class>
     </tag>
 
     <tag>
@@ -166,8 +191,8 @@
     <tag>
     	<tag-name>plugin</tag-name>
     	<component>
-    		<component-type>org.jboss.seam.wiki.core.ui.UIMacro</component-type>
-    		<handler-class>org.jboss.seam.wiki.core.ui.MacroComponentHandler</handler-class>
+    		<component-type>org.jboss.seam.wiki.core.wikitext.renderer.jsf.UIMacro</component-type>
+    		<handler-class>org.jboss.seam.wiki.core.wikitext.renderer.jsf.MacroComponentHandler</handler-class>
     	</component>
     </tag>
 

Modified: trunk/examples/wiki/src/etc/WEB-INF/components.xml
===================================================================
--- trunk/examples/wiki/src/etc/WEB-INF/components.xml	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/etc/WEB-INF/components.xml	2008-06-07 00:25:03 UTC (rev 8348)
@@ -18,7 +18,7 @@
                  http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.1.xsd">
 
     <!-- Conversation timeout: 20 minutes -->
-    <core:manager concurrent-request-timeout="2000"
+    <core:manager concurrent-request-timeout="4000"
                   conversation-timeout="1200000"
                   conversation-id-parameter="cid"/>
 
@@ -86,7 +86,9 @@
 
     <!-- Misc Settings -->
 
+    <!-- TODO: Disabled, see http://jira.jboss.com/jira/browse/JBSEAM-3070
     <web:context-filter regex-url-pattern="/(service|servlets)/.+"/>
+    -->
     <web:redirect-filter disabled="true"/> <!-- Messes up into-conversation-redirect and is not needed -->
 
     <component name="wikiUrlRewriteFilter" class="org.jboss.seam.wiki.core.ui.WikiUrlRewriteFilter" precedence="30">

Modified: trunk/examples/wiki/src/etc/WEB-INF/faces-config.xml
===================================================================
--- trunk/examples/wiki/src/etc/WEB-INF/faces-config.xml	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/etc/WEB-INF/faces-config.xml	2008-06-07 00:25:03 UTC (rev 8348)
@@ -10,8 +10,8 @@
 
     <!-- Needed because WikiFormattedTextHandler instantiates these, asking the JSF infrastructure -->
     <component>
-        <component-type>org.jboss.seam.wiki.core.ui.UIMacro</component-type>
-        <component-class>org.jboss.seam.wiki.core.ui.UIMacro</component-class>
+        <component-type>org.jboss.seam.wiki.core.wikitext.renderer.jsf.UIMacro</component-type>
+        <component-class>org.jboss.seam.wiki.core.wikitext.renderer.jsf.UIMacro</component-class>
     </component>
 
     <!-- We map this to <wiki:loadStyle src="..."/> in Facelets -->

Modified: trunk/examples/wiki/src/etc/WEB-INF/web.xml
===================================================================
--- trunk/examples/wiki/src/etc/WEB-INF/web.xml	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/etc/WEB-INF/web.xml	2008-06-07 00:25:03 UTC (rev 8348)
@@ -4,6 +4,11 @@
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          version="2.5">
 
+    <!-- LaceWiki administration -->
+    <listener>
+        <listener-class>org.jboss.seam.wiki.admin.WikiServletListener</listener-class>
+    </listener>
+
     <!--
         (This resolves the not-thrown ViewExpiredException on session timeout and JSF POSTback.)
         I have got a lot of times to understand JSF 1.2 implementation code. As I guess from code,
@@ -143,7 +148,7 @@
 
     <!-- Session timeout,can be extended for authenticated users in components.xml! -->
     <session-config>
-        <session-timeout>10</session-timeout>
+        <session-timeout>30</session-timeout>
     </session-config>
 
 </web-app>

Modified: trunk/examples/wiki/src/etc/i18n/messages_en.properties
===================================================================
--- trunk/examples/wiki/src/etc/i18n/messages_en.properties	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/etc/i18n/messages_en.properties	2008-06-07 00:25:03 UTC (rev 8348)
@@ -232,8 +232,14 @@
 lacewiki.msg.wikiTextEditor.FormatHeadline2=Headline 2
 lacewiki.msg.wikiTextEditor.FormatHeadline3=Headline 3
 lacewiki.msg.wikiTextEditor.FormatHeadline4=Headline 4
-lacewiki.button.wikiTextEditor.UpdatePreview=Update Pre<u>v</u>iew
-lacewiki.button.wikiTextEditor.UpdatePreview.accesskey=V
+lacewiki.button.wikiTextEditor.EnablePreview=Pre<u>v</u>iew On
+lacewiki.button.wikiTextEditor.EnablePreview.accesskey=V
+lacewiki.button.wikiTextEditor.DisablePreview=Pre<u>v</u>iew Off
+lacewiki.button.wikiTextEditor.DisablePreview.accesskey=V
+lacewiki.button.wikiTextEditor.Validate=<u>C</u>heck
+lacewiki.button.wikiTextEditor.Validate.accesskey=C
+lacewiki.msg.wikiTextValidator.InvalidWikiText=Invalid wiki text, please click HELP for formatting instructions.
+lacewiki.msg.wikiTextValidator.EmptyWikiText=Please enter wiki text, field can not be empty.
 
 # Document Display
 

Added: trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiHttpSessionManager.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiHttpSessionManager.java	                        (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiHttpSessionManager.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,167 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.admin;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.wiki.core.model.User;
+import org.jboss.seam.wiki.core.model.Role;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.Logger;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.security.Identity;
+
+import javax.servlet.http.HttpSession;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * @author Christian Bauer
+ */
+ at Name("wikiHttpSessionManager")
+ at Scope(ScopeType.CONVERSATION)
+ at AutoCreate
+public class WikiHttpSessionManager implements Serializable {
+
+    protected static final String SESSION_ATTR_IDENTITY = "org.jboss.seam.security.identity";
+    protected static final String SESSION_ATTR_ACCESSLVL = "currentAccessLevel";
+
+    @Logger
+    private Log log;
+
+    transient private Map<String, Boolean> selectedSessions = new HashMap<String,Boolean>();
+    transient private Map<String, Long> sessionsSize = new HashMap<String,Long>();
+
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public Map<String, Boolean> getSelectedSessions() { return selectedSessions; }
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public Map<String, Long> getSessionsSize() { return sessionsSize; }
+
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public List<HttpSession> getSessions() {
+        return new ArrayList(WikiServletListener.getSessions().values());
+    }
+
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public HttpSession getSession(String id) {
+        return WikiServletListener.getSessions().get(id);
+    }
+
+    /**
+     * Calculate the size of an HttpSession using serialization.
+     * <p>
+     * This is extremely crude and a guesstimate, especially because this ignores any
+     * serialization errors.
+     * </p>
+     *
+     * @param id the identifier of th HttpSession
+     * @return size in bytes
+     */
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public long getSessionSize(String id) {
+        HttpSession session = WikiServletListener.getSessions().get(id);
+        long sessionSize = 0;
+        if (session != null) {
+            Enumeration elem = session.getAttributeNames();
+            while (elem.hasMoreElements()) {
+                String attName = (String)elem.nextElement();
+                log.debug("serializing session attribute: " + attName);
+                ByteArrayOutputStream bos = null;
+                try {
+                    bos = new ByteArrayOutputStream();
+                    ObjectOutputStream out = new ObjectOutputStream(bos);
+                    out.writeObject(
+                        session.getAttribute(attName)
+                    );
+                    out.close();
+                } catch (Exception ex) {
+                    // Just swallow that
+                    log.warn("error during serialization, ignoring: " + ex);
+                }
+                if (bos != null) {
+                    byte[] buf = bos.toByteArray();
+                    sessionSize = sessionSize + buf.length;
+                }
+            }
+        }
+        return sessionSize;
+    }
+
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public String getUsername(String id) {
+        log.debug("trying to get username of Http session: " + id);
+        HttpSession session = WikiServletListener.getSessions().get(id);
+        String username = User.GUEST_USERNAME;
+        if (session != null) {
+            Identity identity = (Identity)session.getAttribute(SESSION_ATTR_IDENTITY);
+            if (identity != null && identity.getPrincipal() != null)
+                username = identity.getPrincipal().getName();
+        }
+        return username;
+    }
+
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public void calculateSelectedSessionsSize() {
+        sessionsSize.clear();
+        for (Map.Entry<String, Boolean> entry : selectedSessions.entrySet()) {
+            if (entry.getValue()) {
+                log.debug("calculating size of Http session: " + entry.getKey());
+                sessionsSize.put(
+                    entry.getKey(),
+                    getSessionSize( entry.getKey() )
+                );
+            }
+        }
+        selectedSessions.clear();
+    }
+
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public void refresh() {
+        selectedSessions.clear();
+    }
+
+    /* TODO: The way Seam handles sessions conflicts with "destroying" it from the "outside"
+    @Restrict("#{s:hasPermission('User', 'isAdmin', currentUser)}")
+    public void invalidateSelectedSessions() {
+        for (Map.Entry<String, Boolean> entry : selectedSessions.entrySet()) {
+            if (entry.getValue()) {
+                HttpSession s = getSession(entry.getKey());
+                if (s != null) {
+                    log.debug("########### invalidating Http session: " + entry.getKey());
+                    Session seamSession = (Session)s.getAttribute("org.jboss.seam.web.session");
+                    seamSession.invalidate();
+                }
+            }
+        }
+        selectedSessions.clear();
+    }
+    */
+
+    public long getNumberOfOnlineMembers() {
+        Collection<HttpSession> sessions = WikiServletListener.getSessions().values();
+
+        long loggedInUsers = 0l;
+        for (HttpSession session : sessions) {
+            Integer userLevel = (Integer)session.getAttribute(SESSION_ATTR_ACCESSLVL);
+            if (userLevel != null && userLevel > Role.GUESTROLE_ACCESSLEVEL) {
+                loggedInUsers++;
+            }
+        }
+        return loggedInUsers;
+
+    }
+    
+    public long getNumberOfOnlineGuests() {
+        return WikiServletListener.getSessions().values().size() - getNumberOfOnlineMembers();
+    }
+    
+
+}

Added: trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiServletListener.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiServletListener.java	                        (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/admin/WikiServletListener.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.admin;
+
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author Christian Bauer
+ */
+public class WikiServletListener implements HttpSessionListener {
+
+    private static final LogProvider log = Logging.getLogProvider(WikiServletListener.class);
+
+    // Thread-safe read/write and non-blocking reads (snapshot reads)
+    private static ConcurrentHashMap<String, HttpSession> sessions =
+            new ConcurrentHashMap<String, HttpSession>();
+
+    public void sessionCreated(HttpSessionEvent event) {
+        log.debug("starting monitoring of Http session: " + event.getSession().getId());
+        sessions.put(event.getSession().getId(), event.getSession());
+    }
+
+    
+    public void sessionDestroyed(HttpSessionEvent event) {
+        log.debug("stopping monitoring of Http session: " + event.getSession().getId());
+        sessions.remove(event.getSession().getId());
+    }
+
+    public static ConcurrentHashMap<String, HttpSession> getSessions() {
+        return sessions;
+    }
+}

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Authenticator.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Authenticator.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Authenticator.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -17,8 +17,8 @@
 import org.jboss.seam.wiki.core.action.prefs.UserManagementPreferences;
 import org.jboss.seam.wiki.core.dao.UserDAO;
 import org.jboss.seam.wiki.core.dao.WikiNodeDAO;
-import org.jboss.seam.wiki.core.renderer.MacroWikiTextRenderer;
-import org.jboss.seam.wiki.core.renderer.WikiURLRenderer;
+import org.jboss.seam.wiki.core.wikitext.renderer.MacroWikiTextRenderer;
+import org.jboss.seam.wiki.core.ui.WikiURLRenderer;
 import org.jboss.seam.wiki.core.model.*;
 import org.jboss.seam.wiki.core.model.Role;
 import org.jboss.seam.wiki.util.Hash;
@@ -181,23 +181,6 @@
         return "loggedOut";
     }
 
-    /**
-     * Assigns the Guest user to 'currentUser' when 'currentUser' is first referenced. If a
-     * user actually logs in, the 'currentUser' is reset.
-     */
-    @Factory(value = "currentUser", autoCreate = true)
-    public void setGuestUser() {
-        Contexts.getSessionContext().set("currentUser", Component.getInstance("guestUser"));
-    }
-
-    /**
-     * Assigns the context variable 'currentAccessLevel' when no user is logged in.
-     */
-    @Factory(value = "currentAccessLevel", autoCreate = true)
-    public void setGuestAccessLevel() {
-        Contexts.getSessionContext().set("currentAccessLevel", Role.GUESTROLE_ACCESSLEVEL);
-    }
-
     @Observer("org.jboss.seam.security.loginSuccessful")
     public void extendSessionTime() {
         // Store the regular session timeout value, so we can set it back later on logout

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/CommentHome.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/CommentHome.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/CommentHome.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -22,13 +22,11 @@
 import org.jboss.seam.wiki.core.action.prefs.CommentsPreferences;
 import org.jboss.seam.wiki.core.exception.InvalidWikiRequestException;
 import org.jboss.seam.wiki.core.ui.WikiRedirect;
-import org.jboss.seam.wiki.core.engine.WikiFormattedTextValidator;
+import org.jboss.seam.wiki.core.wikitext.editor.WikiTextValidator;
 import org.jboss.seam.wiki.util.WikiUtil;
 
 import static org.jboss.seam.international.StatusMessage.Severity.INFO;
-import static org.jboss.seam.international.StatusMessage.Severity.WARN;
 
-import javax.faces.validator.ValidatorException;
 import java.util.Date;
 
 @Name("commentHome")
@@ -115,9 +113,6 @@
 
     @Override
     public String persist() {
-
-        if (!validateContent()) return null;
-
         String outcome = super.persist();
         if (outcome != null) {
 
@@ -209,23 +204,6 @@
 
     /* -------------------------- Internal Methods ------------------------------ */
 
-    // TODO: Why again are we using a different validator here for the text editor?
-    protected boolean validateContent() {
-        WikiFormattedTextValidator validator = new WikiFormattedTextValidator();
-        try {
-            validator.validate(null, null, getInstance().getContent());
-        } catch (ValidatorException e) {
-            // TODO: Needs to use resource bundle, how?
-            StatusMessages.instance().addToControl(
-                getTextAreaId(),
-                WARN,
-                e.getFacesMessage().getSummary()
-            );
-            return false;
-        }
-        return true;
-    }
-
     protected void endConversation() {
         showForm = false;
         Conversation.instance().end();
@@ -267,10 +245,33 @@
         return quoted.toString();
     }
 
-    protected String getTextAreaId() {
-        return "commentTextArea";
+    @Override
+    protected WikiTextValidator.ValidationCommand[] getPersistValidationCommands() {
+        return new WikiTextValidator.ValidationCommand[] {
+            new WikiTextValidator.ValidationCommand() {
+                public String getKey() {
+                    return "comment";
+                }
+
+                public String getWikiTextValue() {
+                    return getInstance().getContent();
+                }
+
+                public boolean getWikiTextRequired() {
+                    return true;
+                }
+            }
+        };
     }
 
+    protected String getValidationRequiredWikiTextEditorId() {
+        return "comment";
+    }
+
+    protected String getValidationRequiredWikiText() {
+        return getInstance().getContent();
+    }
+
     /* -------------------------- Public Features ------------------------------ */
 
     public boolean isShowForm() {

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DefaultWikiLinkResolver.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DefaultWikiLinkResolver.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DefaultWikiLinkResolver.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -7,8 +7,8 @@
 import org.jboss.seam.log.Log;
 import org.jboss.seam.wiki.core.dao.WikiNodeDAO;
 import org.jboss.seam.wiki.core.model.*;
-import org.jboss.seam.wiki.core.engine.WikiLinkResolver;
-import org.jboss.seam.wiki.core.engine.WikiLink;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLinkResolver;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLink;
 import org.jboss.seam.wiki.util.WikiUtil;
 
 import java.util.Map;

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DocumentHome.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DocumentHome.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/DocumentHome.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -19,13 +19,14 @@
 import org.jboss.seam.wiki.core.action.prefs.WikiPreferences;
 import org.jboss.seam.wiki.core.feeds.FeedDAO;
 import org.jboss.seam.wiki.core.feeds.FeedEntryManager;
-import org.jboss.seam.wiki.core.engine.WikiLinkResolver;
-import org.jboss.seam.wiki.core.renderer.MacroWikiTextRenderer;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLinkResolver;
+import org.jboss.seam.wiki.core.wikitext.renderer.MacroWikiTextRenderer;
 import org.jboss.seam.wiki.core.model.*;
 import org.jboss.seam.wiki.core.exception.InvalidWikiRequestException;
 import org.jboss.seam.wiki.core.template.TemplateRegistry;
 import org.jboss.seam.wiki.core.template.WikiDocumentTemplate;
 import org.jboss.seam.wiki.core.template.WikiDocumentEditorDefaults;
+import org.jboss.seam.wiki.core.wikitext.editor.WikiTextValidator;
 import org.jboss.seam.wiki.preferences.Preferences;
 import org.hibernate.validator.Length;
 
@@ -52,7 +53,6 @@
     private Boolean minorRevision;
     private String formContent;
     private Set<WikiFile> linkTargets;
-    private boolean enabledPreview = false;
     private boolean pushOnFeeds = false;
     private boolean pushOnSiteFeed = false;
     private boolean isOnSiteFeed = false;
@@ -255,6 +255,34 @@
         return (DocumentNodeRemover)Component.getInstance(DocumentNodeRemover.class);
     }
 
+    @Override
+    protected WikiTextValidator.ValidationCommand[] getPersistValidationCommands() {
+        return getValidationCommands();
+    }
+
+    protected WikiTextValidator.ValidationCommand[] getUpdateValidationCommands() {
+        return getValidationCommands();
+    }
+
+    private WikiTextValidator.ValidationCommand[] getValidationCommands() {
+        return new WikiTextValidator.ValidationCommand[] {
+            new WikiTextValidator.ValidationCommand() {
+                public String getKey() {
+                    return "content";
+                }
+
+                public String getWikiTextValue() {
+                    return getFormContent();
+                }
+
+                public boolean getWikiTextRequired() {
+                    return true;
+                }
+            }
+        };
+    }
+
+
     /* -------------------------- Messages ------------------------------ */
 
     @Override
@@ -398,15 +426,6 @@
     }
     public void setMinorRevision(boolean minorRevision) { this.minorRevision = minorRevision; }
 
-    public boolean isEnabledPreview() {
-        return enabledPreview;
-    }
-
-    public void setEnabledPreview(boolean enabledPreview) {
-        this.enabledPreview = enabledPreview;
-        syncFormContentToInstance(getParentNode());
-    }
-
     public boolean isOnSiteFeed() {
         return isOnSiteFeed;
     }

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Help.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Help.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Help.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -19,9 +19,6 @@
     @Logger
     Log log;
 
-    @In
-    WikiNodeDAO wikiNodeDAO;
-
     @In("#{preferences.get('Wiki')}")
     WikiPreferences wikiPreferences;
 
@@ -29,7 +26,7 @@
 
     @Create
     public void create() {
-        helpAreaRoot = wikiNodeDAO.findArea(WikiUtil.convertToWikiName(wikiPreferences.getHelpArea()));
+        helpAreaRoot = WikiNodeDAO.instance().findArea(WikiUtil.convertToWikiName(wikiPreferences.getHelpArea()));
     }
 
     WikiDocument selectedHelpDoc;
@@ -41,7 +38,7 @@
     public void selectDocumentByName(String documentName) {
         log.debug("Searching for help document with wiki name in area: " + helpAreaRoot.getAreaNumber() + ", " + WikiUtil.convertToWikiName(documentName));
         selectedHelpDoc =
-                wikiNodeDAO.findWikiDocumentInArea(
+                WikiNodeDAO.instance().findWikiDocumentInArea(
                         helpAreaRoot.getAreaNumber(),
                         WikiUtil.convertToWikiName(documentName)
                 );

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Menu.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Menu.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/Menu.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -7,6 +7,7 @@
 package org.jboss.seam.wiki.core.action;
 
 import org.jboss.seam.ScopeType;
+import org.jboss.seam.Component;
 import org.jboss.seam.annotations.*;
 import org.jboss.seam.log.Log;
 import org.jboss.seam.wiki.core.action.prefs.WikiPreferences;
@@ -14,6 +15,7 @@
 import org.jboss.seam.wiki.core.model.WikiDirectory;
 import org.jboss.seam.wiki.core.nestedset.query.NestedSetNodeWrapper;
 import org.jboss.seam.wiki.core.cache.PageFragmentCache;
+import org.jboss.seam.wiki.preferences.Preferences;
 
 import java.io.Serializable;
 
@@ -35,15 +37,6 @@
     Log log;
 
     @In
-    WikiDirectory wikiRoot;
-
-    @In
-    WikiNodeDAO wikiNodeDAO;
-
-    @In("#{preferences.get('Wiki')}")
-    WikiPreferences wikiPreferences;
-
-    @In
     Integer currentAccessLevel;
 
     NestedSetNodeWrapper<WikiDirectory> root;
@@ -57,8 +50,9 @@
     @Observer(value = { "Node.updated", "Node.removed", "PersistenceContext.filterReset" }, create = false)
     public void refreshRoot() {
         log.debug("Loading menu items tree");
-        root = wikiNodeDAO.findMenuItemTree(
-                wikiRoot,
+        WikiPreferences wikiPreferences = Preferences.instance().get(WikiPreferences.class);
+        root = WikiNodeDAO.instance().findMenuItemTree(
+                (WikiDirectory)Component.getInstance("wikiRoot"),
                 wikiPreferences.getMainMenuDepth(), 
                 wikiPreferences.getMainMenuLevels(),
                 wikiPreferences.isMainMenuShowAdminOnly()

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/NodeHome.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/NodeHome.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/NodeHome.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -19,6 +19,7 @@
 import org.jboss.seam.wiki.core.model.*;
 import org.jboss.seam.wiki.core.action.prefs.WikiPreferences;
 import org.jboss.seam.wiki.core.exception.InvalidWikiRequestException;
+import org.jboss.seam.wiki.core.wikitext.editor.WikiTextValidator;
 import org.jboss.seam.wiki.util.WikiUtil;
 import org.jboss.seam.wiki.preferences.Preferences;
 import org.jboss.seam.international.StatusMessages;
@@ -36,6 +37,9 @@
  */
 public abstract class NodeHome<N extends WikiNode, P extends WikiNode> extends EntityHome<N> {
 
+    // TODO: This is a performance optimization, our EM is always already joined (SMPC)
+    protected void joinTransaction() {}
+
     /* -------------------------- Context Wiring ------------------------------ */
 
     @In
@@ -48,12 +52,15 @@
     protected User currentUser;
     @In
     protected List<Role.AccessLevel> accessLevelsList;
+    @In
+    protected WikiTextValidator wikiTextValidator;
 
     public WikiNodeDAO getWikiNodeDAO() { return wikiNodeDAO; }
     public UserDAO getUserDAO() { return userDAO; }
     public WikiDirectory getWikiRoot() { return wikiRoot; }
     public User getCurrentUser() { return currentUser; }
     public List<Role.AccessLevel> getAccessLevelsList() { return accessLevelsList; }
+    public WikiTextValidator getWikiTextValidator() { return wikiTextValidator; }
 
     /* -------------------------- Request Wiring ------------------------------ */
 
@@ -214,6 +221,8 @@
     public String persist() {
         checkPersistPermissions();
 
+        if (!validateWikiTexts(getPersistValidationCommands())) return null;
+
         if (!preparePersist()) return null;
 
         getLog().trace("linking new node with its parent node: " + getParentNode());
@@ -247,6 +256,8 @@
     public String update() {
         checkUpdatePermissions();
 
+        if (!validateWikiTexts(getUpdateValidationCommands())) return null;
+
         if (!prepareUpdate()) return null;
 
         // Modification metadata
@@ -407,6 +418,25 @@
         return Identity.instance().hasPermission("Node", "edit", node);
     }
 
+    protected boolean validateWikiTexts(WikiTextValidator.ValidationCommand[] validationCommands) {
+        if (validationCommands == null) return true;
+
+        boolean allValid = true;
+        for (WikiTextValidator.ValidationCommand validationCommand : validationCommands) {
+            getWikiTextValidator().validate(validationCommand);
+            allValid = getWikiTextValidator().isValid(validationCommand.getKey());
+        }
+        return allValid;
+    }
+
+    protected WikiTextValidator.ValidationCommand[] getUpdateValidationCommands() {
+        return null;
+    }
+
+    protected WikiTextValidator.ValidationCommand[] getPersistValidationCommands() {
+        return null;
+    }
+
     /* -------------------------- Optional Subclass Callbacks ------------------------------ */
 
     protected boolean isPageRootController() { return true; }

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/UserHome.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/UserHome.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/UserHome.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -28,6 +28,7 @@
 import org.jboss.seam.wiki.core.model.WikiUploadImage;
 import org.jboss.seam.wiki.core.upload.Uploader;
 import org.jboss.seam.wiki.core.exception.InvalidWikiRequestException;
+import org.jboss.seam.wiki.core.wikitext.editor.WikiTextValidator;
 import org.jboss.seam.wiki.preferences.PreferenceVisibility;
 import org.jboss.seam.wiki.preferences.Preferences;
 import org.jboss.seam.wiki.preferences.PreferenceProvider;
@@ -47,6 +48,9 @@
 @Scope(ScopeType.CONVERSATION)
 public class UserHome extends EntityHome<User> {
 
+    // TODO: This is a performance optimization, our EM is always already joined (SMPC)
+    //protected void joinTransaction() {}
+
     @In
     private StatusMessages statusMessages;
 
@@ -153,7 +157,8 @@
     public String persist() {
 
         // Validate
-        if (!isUniqueUsername() ||
+        if (!validateWikiTextEditors() ||
+            !isUniqueUsername() ||
             !passwordAndControlNotNull() ||
             !passwordMatchesRegex() ||
             !passwordMatchesControl()) {
@@ -213,6 +218,10 @@
     @Restrict("#{s:hasPermission('User', 'edit', userHome.instance)}")
     public String update() {
 
+        if (!validateWikiTextEditors()) {
+            return null;
+        }
+
         if (uploader.hasData()) {
             uploader.uploadNewInstance();
             if (WikiUploadImage.class.isAssignableFrom(uploader.getUpload().getClass())) {
@@ -339,7 +348,17 @@
         );
     }
 
+    protected boolean validateWikiTextEditors() {
+        WikiTextValidator wikiTextValidator =
+                (WikiTextValidator) Component.getInstance(WikiTextValidator.class);
 
+        wikiTextValidator.validate("bio", getInstance().getProfile().getBio(), false);
+        wikiTextValidator.validate("signature", getInstance().getProfile().getSignature(), false);
+
+        return wikiTextValidator.isValid("bio") && wikiTextValidator.isValid("signature");
+    }
+
+
     /* -------------------------- Messages ------------------------------ */
 
     @Override

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/WikiIdentity.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/WikiIdentity.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/action/WikiIdentity.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -19,8 +19,6 @@
 import org.jboss.seam.security.Identity;
 import org.jboss.seam.wiki.core.model.*;
 
-import javax.security.auth.login.LoginException;
-
 /**
  * Need this until Drools fixes bugs and becomes usable/debuggable.
  *

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/captcha/WikiCaptchaValidator.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/captcha/WikiCaptchaValidator.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/captcha/WikiCaptchaValidator.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -16,6 +16,7 @@
 import javax.faces.validator.ValidatorException;
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
+import java.io.Serializable;
 
 /**
  * I don't trust the built-in validator with @CaptchaResponse.
@@ -28,7 +29,7 @@
  */
 @Name("wikiCaptchaValidator")
 @Validator(id = "wikiCaptchaValidator")
-public class WikiCaptchaValidator implements javax.faces.validator.Validator {
+public class WikiCaptchaValidator implements javax.faces.validator.Validator, Serializable {
 
     public static final String VERIFICATION_MSG_EXPR = "#{messages['lacewiki.label.VerificationError']}";
 

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserDAO.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserDAO.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserDAO.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -6,9 +6,7 @@
 
 import org.jboss.seam.annotations.In;
 import org.jboss.seam.annotations.Name;
-import org.jboss.seam.annotations.Transactional;
 import org.jboss.seam.annotations.AutoCreate;
-import org.jboss.seam.wiki.core.model.Role;
 import org.jboss.seam.wiki.core.model.User;
 import org.jboss.seam.Component;
 import org.hibernate.criterion.Order;

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserRoleAccessFactory.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserRoleAccessFactory.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/UserRoleAccessFactory.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -19,6 +19,18 @@
     @In
     EntityManager entityManager;
 
+    // Anonymous (not logged-in) user
+    @Factory(value = "currentUser", scope = ScopeType.SESSION, autoCreate = true)
+    public User getCurrentUser() {
+        return getGuestUser();
+    }
+
+    // Anonymous (not logged-in) user's access level
+    @Factory(value = "currentAccessLevel", scope = ScopeType.SESSION, autoCreate = true)
+    public Integer getCurrentAccessLevel() {
+        return Role.GUESTROLE_ACCESSLEVEL;
+    }
+
     @Factory(value = "guestUser", scope = ScopeType.SESSION)
     public User getGuestUser() {
         try {

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/WikiNodeDAO.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/WikiNodeDAO.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/dao/WikiNodeDAO.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -559,9 +559,12 @@
 
     public NestedSetNodeWrapper<WikiDirectory> findMenuItemTree(WikiDirectory startDir, Long maxDepth, Long flattenToLevel, boolean showAdminOnly) {
 
-        NestedSetNodeWrapper<WikiDirectory> startNodeWrapper = new NestedSetNodeWrapper<WikiDirectory>(startDir, getComparatorDisplayPosition());
+        NestedSetNodeWrapper<WikiDirectory> startNodeWrapper = 
+            new NestedSetNodeWrapper<WikiDirectory>(startDir, new WikiDirectoryDisplayPositionComparator());
+
         NestedSetResultTransformer<WikiDirectory> transformer =
-                new NestedSetResultTransformer<WikiDirectory>(startNodeWrapper, flattenToLevel);
+            new NestedSetResultTransformer<WikiDirectory>(startNodeWrapper, flattenToLevel);
+
         transformer.getAdditionalProjections().put("displayPosition", "m.displayPosition");
 
         // Make hollow copies for menu display so that changes to the model in the persistence context don't appear
@@ -586,10 +589,16 @@
         return findWikiDirectoryTree(startDir, null, 0l, false);
     }
 
-    public NestedSetNodeWrapper<WikiDirectory> findWikiDirectoryTree(WikiDirectory startDir, Long maxDepth, Long flattenToLevel, boolean showAdminOnly) {
+    public NestedSetNodeWrapper<WikiDirectory> findWikiDirectoryTree(WikiDirectory startDir,
+                                                                     Long maxDepth, Long flattenToLevel,
+                                                                     boolean showAdminOnly) {
 
-        NestedSetNodeWrapper<WikiDirectory> startNodeWrapper = new NestedSetNodeWrapper<WikiDirectory>(startDir, getComparatorWikiDirectoryName());
-        NestedSetResultTransformer<WikiDirectory> transformer = new NestedSetResultTransformer<WikiDirectory>(startNodeWrapper, flattenToLevel);
+        NestedSetNodeWrapper<WikiDirectory> startNodeWrapper =
+            new NestedSetNodeWrapper<WikiDirectory>(startDir, new WikiDirectoryNameComparator());
+
+        NestedSetResultTransformer<WikiDirectory> transformer =
+            new NestedSetResultTransformer<WikiDirectory>(startNodeWrapper, flattenToLevel);
+
         appendNestedSetNodes(transformer, maxDepth, showAdminOnly, null);
         return startNodeWrapper;
 
@@ -650,45 +659,6 @@
         nestedSetQuery.list(); // Append all children hierarchically to the transformers rootWrapper
     }
 
-    public Comparator<NestedSetNodeWrapper<WikiDirectory>> getComparatorWikiDirectoryName() {
-        // Needs to be equals() safe (SortedSet):
-        // - compare by name, if equal
-        // - compare by id
-        return
-            new Comparator<NestedSetNodeWrapper<WikiDirectory>>() {
-                public int compare(NestedSetNodeWrapper<WikiDirectory> o1, NestedSetNodeWrapper<WikiDirectory> o2) {
-                    WikiDirectory node1 = o1.getWrappedNode();
-                    WikiDirectory node2 = o2.getWrappedNode();
-                    if (node1.getName().compareTo(node2.getName()) != 0) {
-                        return node1.getName().compareTo(node2.getName());
-                    }
-                    return node1.getId().compareTo(node2.getId());
-                }
-            };
-    }
-
-    public Comparator<NestedSetNodeWrapper<WikiDirectory>> getComparatorDisplayPosition() {
-        // Needs to be equals() safe (SortedSet):
-        // - compare by display position, if equal
-        // - compare by name, if equal
-        // - compare by id
-        return
-            new Comparator<NestedSetNodeWrapper<WikiDirectory>>() {
-                public int compare(NestedSetNodeWrapper<WikiDirectory> o1, NestedSetNodeWrapper<WikiDirectory> o2) {
-                    WikiDirectory node1 = o1.getWrappedNode();
-                    Long node1DisplayPosition = (Long)o1.getAdditionalProjections().get("displayPosition");
-                    WikiDirectory node2 = o2.getWrappedNode();
-                    Long node2DisplayPosition = (Long)o2.getAdditionalProjections().get("displayPosition");
-                    if (node1DisplayPosition.compareTo(node2DisplayPosition) != 0) {
-                        return node1DisplayPosition.compareTo(node2DisplayPosition);
-                    } else if (node1.getName().compareTo(node2.getName()) != 0) {
-                        return node1.getName().compareTo(node2.getName());
-                    }
-                    return node1.getId().compareTo(node2.getId());
-                }
-            };
-    }
-
     private Session getSession(boolean restricted) {
         if (restricted) {
             return ((Session)((org.jboss.seam.persistence.EntityManagerProxy) restrictedEntityManager).getDelegate());
@@ -697,4 +667,8 @@
         }
     }
 
+    public static WikiNodeDAO instance() {
+        return (WikiNodeDAO)Component.getInstance(WikiNodeDAO.class);
+    }
+
 }

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedDAO.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedDAO.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedDAO.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -13,7 +13,7 @@
 import org.jboss.seam.annotations.Name;
 import org.jboss.seam.log.Log;
 import org.jboss.seam.wiki.core.model.*;
-import org.jboss.seam.wiki.core.renderer.WikiURLRenderer;
+import org.jboss.seam.wiki.core.ui.WikiURLRenderer;
 
 import javax.persistence.EntityManager;
 import javax.persistence.EntityNotFoundException;

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedEntryManager.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedEntryManager.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/feeds/FeedEntryManager.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -14,14 +14,14 @@
 import org.jboss.seam.annotations.Logger;
 import org.jboss.seam.annotations.Scope;
 import org.jboss.seam.log.Log;
-import org.jboss.seam.wiki.core.engine.WikiLink;
-import org.jboss.seam.wiki.core.engine.WikiLinkResolver;
-import org.jboss.seam.wiki.core.engine.WikiTextParser;
-import org.jboss.seam.wiki.core.engine.WikiFormattedTextValidator;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLink;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLinkResolver;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiTextParser;
+import org.jboss.seam.wiki.core.wikitext.editor.WikiFormattedTextValidator;
+import org.jboss.seam.wiki.core.wikitext.renderer.DefaultWikiTextRenderer;
 import org.jboss.seam.wiki.core.model.FeedEntry;
 import org.jboss.seam.wiki.core.model.WikiTextMacro;
-import org.jboss.seam.wiki.core.renderer.DefaultWikiTextRenderer;
-import org.jboss.seam.wiki.core.renderer.WikiURLRenderer;
+import org.jboss.seam.wiki.core.ui.WikiURLRenderer;
 
 /**
  * @author Christian Bauer

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/LinkProtocol.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/LinkProtocol.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/LinkProtocol.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -11,10 +11,11 @@
 import javax.persistence.*;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
+import java.io.Serializable;
 
 @Entity
 @Table(name = "LINK_PROTOCOL")
-public class LinkProtocol {
+public class LinkProtocol implements Serializable {
 
     @Id
     @GeneratedValue(generator = "wikiSequenceGenerator")

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/UserProfile.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/UserProfile.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/UserProfile.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -10,11 +10,12 @@
 
 import javax.persistence.*;
 import java.util.Date;
+import java.io.Serializable;
 
 @Entity
 @Table(name = "USER_PROFILE")
 @org.hibernate.annotations.BatchSize(size = 20)
-public class UserProfile {
+public class UserProfile implements Serializable {
 
     @Id
     @GeneratedValue(generator = "wikiSequenceGenerator")

Added: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryDisplayPositionComparator.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryDisplayPositionComparator.java	                        (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryDisplayPositionComparator.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.model;
+
+import org.jboss.seam.wiki.core.nestedset.query.NestedSetNodeWrapper;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Needs to be equals() safe (SortedSet): compare by display position, if equal compare by name,
+ * if equal compare by id.
+ *
+ * @author Christian Bauer
+ */
+public class WikiDirectoryDisplayPositionComparator
+        implements Comparator<NestedSetNodeWrapper<WikiDirectory>>, Serializable {
+
+    public int compare(NestedSetNodeWrapper<WikiDirectory> o1, NestedSetNodeWrapper<WikiDirectory> o2) {
+        WikiDirectory node1 = o1.getWrappedNode();
+        Long node1DisplayPosition = (Long)o1.getAdditionalProjections().get("displayPosition");
+        WikiDirectory node2 = o2.getWrappedNode();
+        Long node2DisplayPosition = (Long)o2.getAdditionalProjections().get("displayPosition");
+        if (node1DisplayPosition.compareTo(node2DisplayPosition) != 0) {
+            return node1DisplayPosition.compareTo(node2DisplayPosition);
+        } else if (node1.getName().compareTo(node2.getName()) != 0) {
+            return node1.getName().compareTo(node2.getName());
+        }
+        return node1.getId().compareTo(node2.getId());
+    }
+
+}

Added: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryNameComparator.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryNameComparator.java	                        (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiDirectoryNameComparator.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,31 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.model;
+
+import org.jboss.seam.wiki.core.nestedset.query.NestedSetNodeWrapper;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Needs to be equals() safe (SortedSet), compare by name, if equal compare by id.
+ *
+ * @author Christian Bauer
+ */
+public class WikiDirectoryNameComparator
+        implements Comparator<NestedSetNodeWrapper<WikiDirectory>>, Serializable {
+
+    public int compare(NestedSetNodeWrapper<WikiDirectory> o1, NestedSetNodeWrapper<WikiDirectory> o2) {
+        WikiDirectory node1 = o1.getWrappedNode();
+        WikiDirectory node2 = o2.getWrappedNode();
+        if (node1.getName().compareTo(node2.getName()) != 0) {
+            return node1.getName().compareTo(node2.getName());
+        }
+        return node1.getId().compareTo(node2.getId());
+    }
+
+}

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFile.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFile.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/model/WikiFile.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -2,12 +2,13 @@
 
 import javax.persistence.*;
 import java.util.*;
+import java.io.Serializable;
 
 @Entity
 @Table(name = "WIKI_FILE")
 @org.hibernate.annotations.ForeignKey(name = "FK_WIKI_FILE_NODE_ID")
 //TODO: @org.hibernate.annotations.OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
-public abstract class WikiFile<N extends WikiFile> extends WikiNode<N> {
+public abstract class WikiFile<N extends WikiFile> extends WikiNode<N> implements Serializable {
 
     @org.hibernate.annotations.CollectionOfElements(fetch = FetchType.LAZY)
     @JoinTable(name = "WIKI_TAG", joinColumns = @JoinColumn(name = "FILE_ID"))

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeInfo.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeInfo.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/NestedSetNodeInfo.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -4,9 +4,10 @@
 
 import javax.persistence.Embeddable;
 import javax.persistence.Column;
+import java.io.Serializable;
 
 @Embeddable
-public class NestedSetNodeInfo<N extends NestedSetNode> {
+public class NestedSetNodeInfo<N extends NestedSetNode> implements Serializable {
 
     @Parent
     private N owner;

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/query/NestedSetNodeWrapper.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/query/NestedSetNodeWrapper.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/nestedset/query/NestedSetNodeWrapper.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -9,6 +9,7 @@
 import org.jboss.seam.wiki.core.nestedset.NestedSetNode;
 
 import java.util.*;
+import java.io.Serializable;
 
 /**
  * Wraps a {@link org.jboss.seam.wiki.core.nestedset.NestedSetDelegate} and links it into a read-only tree of parent and children.
@@ -43,7 +44,7 @@
  *
  * @author Christian Bauer
  */
-public class NestedSetNodeWrapper<N extends NestedSetNode> {
+public class NestedSetNodeWrapper<N extends NestedSetNode> implements Serializable {
 
     N wrappedNode;
     NestedSetNodeWrapper<N> wrappedParent;

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/Plugin.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/Plugin.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/Plugin.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -8,17 +8,17 @@
 
 import org.jboss.seam.Component;
 import org.jboss.seam.wiki.core.exception.InvalidWikiConfigurationException;
-import org.jboss.seam.wiki.core.plugin.metamodel.PluginModule;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.io.Serializable;
 
 /**
  * Plugin metadata.
  *
  * @author Christian Bauer
  */
-public class Plugin {
+public class Plugin implements Serializable {
 
     // Some constants that represent the sub-package layout of a plugin package
     public static final String PACKAGE_I18N = "i18n";

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginInfo.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginInfo.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginInfo.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -6,17 +6,19 @@
  */
 package org.jboss.seam.wiki.core.plugin.metamodel;
 
+import java.io.Serializable;
+
 /**
  * @author Christian Bauer
  */
-public class PluginInfo {
+public class PluginInfo implements Serializable {
 
     private String description;
     private String version;
     private ApplicationVersion applicationVersion;
     private Vendor vendor;
 
-    public class ApplicationVersion {
+    public class ApplicationVersion implements Serializable {
         private String min;
         private String max;
 
@@ -34,7 +36,7 @@
         }
     }
 
-    public class Vendor {
+    public class Vendor implements Serializable {
         private String name;
         private String url;
 

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginModule.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginModule.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/plugin/metamodel/PluginModule.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -10,11 +10,12 @@
 import org.jboss.seam.wiki.core.exception.InvalidWikiConfigurationException;
 
 import java.util.*;
+import java.io.Serializable;
 
 /**
  * @author Christian Bauer
  */
-public abstract class PluginModule {
+public abstract class PluginModule implements Serializable {
 
     private Plugin plugin;
     private String key;

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/preferences/template/WriteProtectedAreaTemplate.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/preferences/template/WriteProtectedAreaTemplate.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/preferences/template/WriteProtectedAreaTemplate.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -18,17 +18,15 @@
 public class WriteProtectedAreaTemplate implements PreferenceValueTemplate, Serializable {
 
     @In
-    WikiNodeDAO wikiNodeDAO;
-
-    @In
     WikiDirectory wikiRoot;
 
     private List<String> areaNames;
 
     public List<String> getTemplateValues() {
         if (areaNames == null) {
-             areaNames = new ArrayList<String>();
-            List<WikiNode> areas = wikiNodeDAO.findChildren(wikiRoot, WikiNode.SortableProperty.name, false, 0, Integer.MAX_VALUE);
+            areaNames = new ArrayList<String>();
+            List<WikiNode> areas =
+                WikiNodeDAO.instance().findChildren(wikiRoot, WikiNode.SortableProperty.name, false, 0, Integer.MAX_VALUE);
             for (WikiNode area : areas) {
                 if (area.isWriteProtected()) {
                     areaNames.add(area.getName());

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/search/WikiSearchSupport.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/search/WikiSearchSupport.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/search/WikiSearchSupport.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -5,7 +5,7 @@
 import org.jboss.seam.wiki.core.model.WikiComment;
 import org.jboss.seam.wiki.core.search.metamodel.SearchSupport;
 import org.jboss.seam.wiki.core.search.metamodel.SearchableEntityHandler;
-import org.jboss.seam.wiki.core.renderer.WikiURLRenderer;
+import org.jboss.seam.wiki.core.ui.WikiURLRenderer;
 import org.jboss.seam.Component;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.highlight.*;

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FeedServlet.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -10,6 +10,8 @@
 import com.sun.syndication.io.SyndFeedOutput;
 import com.sun.syndication.io.FeedException;
 import org.jboss.seam.Component;
+import org.jboss.seam.servlet.ContextualHttpServletRequest;
+import org.jboss.seam.contexts.Contexts;
 import org.jboss.seam.international.Messages;
 import org.jboss.seam.wiki.core.feeds.FeedDAO;
 import org.jboss.seam.wiki.core.model.*;
@@ -76,17 +78,29 @@
     // Allow unit testing
     public FeedServlet() {}
 
-    // TODO: All data access in this method runs with auto-commit mode, see http://jira.jboss.com/jira/browse/JBSEAM-957
     @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+    protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
             throws ServletException, IOException {
+        new ContextualHttpServletRequest(request) {
+            @Override
+            public void process() throws Exception {
+                doWork(request, response);
+            }
+        }.run();
+    }
 
+    // TODO: All data access in this method runs with auto-commit mode, see http://jira.jboss.com/jira/browse/JBSEAM-957
+    protected void doWork(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+
         String feedIdParam = request.getParameter("feedId");
         String areaNameParam = request.getParameter("areaName");
         String nodeNameParam = request.getParameter("nodeName");
         String aggregateParam = request.getParameter("aggregate");
         log.debug(">>> feed request id: '" + feedIdParam + "' area name: '" + areaNameParam + "' node name: '" + nodeNameParam + "'");
 
+        Contexts.getSessionContext().set("LAST_ACCESS_ACTION", "Feed: " +feedIdParam + " area: '" + areaNameParam + "' node: '" + nodeNameParam + "'");
+
         // Feed type
         String pathInfo = request.getPathInfo();
         log.debug("requested feed type: " + pathInfo);

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FileServlet.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FileServlet.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/FileServlet.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -3,6 +3,8 @@
 import org.jboss.seam.wiki.core.dao.WikiNodeDAO;
 import org.jboss.seam.wiki.core.model.WikiUpload;
 import org.jboss.seam.wiki.core.model.WikiUploadImage;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.servlet.ContextualHttpServletRequest;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.logging.Log;
 
@@ -42,14 +44,27 @@
 
     }
 
-    // TODO: All data access in this method runs with auto-commit mode, see http://jira.jboss.com/jira/browse/JBSEAM-957
     @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+    protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
             throws ServletException, IOException {
+        new ContextualHttpServletRequest(request) {
+            @Override
+            public void process() throws Exception {
+                doWork(request, response);
+            }
+        }.run();
+    }
 
+    // TODO: All data access in this method runs with auto-commit mode, see http://jira.jboss.com/jira/browse/JBSEAM-957
+    protected void doWork(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+
         if (DOWNLOAD_PATH.equals(request.getPathInfo())) {
 
             String id = request.getParameter("fileId");
+
+            Contexts.getSessionContext().set("LAST_ACCESS_ACTION", "File: " + id);
+
             WikiUpload file = null;
 
             if (!"".equals(id)) {

Deleted: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/MacroComponentHandler.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/MacroComponentHandler.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/MacroComponentHandler.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -1,26 +0,0 @@
-package org.jboss.seam.wiki.core.ui;
-
-import com.sun.facelets.FaceletContext;
-import com.sun.facelets.tag.jsf.ComponentConfig;
-import com.sun.facelets.tag.jsf.ComponentHandler;
-
-import javax.faces.component.UIComponent;
-
-/**
- * Chaining up the macros. Still a bit of a riddle, what Pete did here.
- *
- * @author Pete Muir
- */
-public class MacroComponentHandler extends ComponentHandler {
-
-    public MacroComponentHandler(ComponentConfig config) {
-        super(config);
-    }
-
-    @Override
-    protected void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent) {
-        super.onComponentCreated(ctx, c, parent);
-        parent.getAttributes().put(UIMacro.NEXT_MACRO, c.getClientId(ctx.getFacesContext()));
-    }
-
-}

Deleted: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIMacro.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIMacro.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIMacro.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -1,35 +0,0 @@
-package org.jboss.seam.wiki.core.ui;
-
-import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
-
-import javax.faces.component.UINamingContainer;
-
-/**
- * A wrapper component that applies to macro includes.
- * <p>
- * A macro XHTML template must have a <tt>&lt;wiki:macro&gt;</tt> root element.
- * </p>
- *
- * @author Pete Muir
- */
-public class UIMacro extends UINamingContainer {
-
-    public static final String COMPONENT_FAMILY = "org.jboss.seam.wiki.core.ui.UIMacro";
-
-    public static final String NEXT_MACRO = "org.jboss.seam.wiki.core.ui.UIMacro.nextMacro";
-
-    @Override
-    public String getFamily() {
-        return COMPONENT_FAMILY;
-    }
-
-    private WikiPluginMacro wikiPluginMacro;
-
-    public WikiPluginMacro getWikiMacro() {
-        return wikiPluginMacro;
-    }
-
-    public void setWikiMacro(WikiPluginMacro wikiPluginMacro) {
-        this.wikiPluginMacro = wikiPluginMacro;
-    }
-}

Deleted: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIWikiFormattedText.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIWikiFormattedText.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIWikiFormattedText.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -1,289 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.seam.wiki.core.ui;
-
-import antlr.ANTLRException;
-import antlr.RecognitionException;
-import org.jboss.seam.Component;
-import org.jboss.seam.core.Events;
-import org.jboss.seam.contexts.Contexts;
-import org.jboss.seam.log.Log;
-import org.jboss.seam.log.Logging;
-import org.jboss.seam.ui.util.JSF;
-import org.jboss.seam.wiki.core.engine.*;
-import org.jboss.seam.wiki.core.model.WikiFile;
-import org.jboss.seam.wiki.core.model.WikiUploadImage;
-import org.jboss.seam.wiki.core.model.WikiTextMacro;
-import org.jboss.seam.wiki.core.renderer.DefaultWikiTextRenderer;
-import org.jboss.seam.wiki.util.WikiUtil;
-import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
-
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIOutput;
-import javax.faces.context.FacesContext;
-import javax.faces.context.ResponseWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Uses WikiTextParser and WikiLinkResolver to render Seam Text markup with wiki links.
- *
- * Any lexer/parser error results in WARN level log message, you can disable this in your logging
- * configuration by raising the log level for this class to ERROR.
- *
- * @author Christian Bauer
- */
-public class UIWikiFormattedText extends UIOutput {
-
-    Log log = Logging.getLog(UIWikiFormattedText.class);
-
-    public static final String ATTR_LINK_STYLE_CLASS                = "linkStyleClass";
-    public static final String ATTR_BROKEN_LINK_STYLE_CLASS         = "brokenLinkStyleClass";
-    public static final String ATTR_ATTACHMENT_LINK_STYLE_CLASS     = "attachmentLinkStyleClass";
-    public static final String ATTR_THUMBNAIL_LINK_STYLE_CLASS      = "thumbnailLinkStyleClass";
-    public static final String ATTR_INTERNAL_TARGET_FRAME           = "internalTargetFrame";
-    public static final String ATTR_EXTERNAL_TARGET_FRAME           = "externalTargetFrame";
-    public static final String ATTR_LINK_BASE_FILE                  = "linkBaseFile";
-    public static final String ATTR_CURRENT_AREA_NUMBER             = "currentAreaNumber";
-    public static final String ATTR_ENABLE_MACRO_RENDERING          = "enableMacroRendering";
-    public static final String ATTR_ENABLE_TRANSIENT_MACROS         = "enableTransientMacros";
-
-    private Map<Integer, WikiPluginMacro> macrosWithTemplateByPosition;
-
-    public static final String COMPONENT_FAMILY = "org.jboss.seam.wiki.core.ui.UIWikiFormattedText";
-
-    public static final String COMPONENT_TYPE = "org.jboss.seam.wiki.core.ui.UIWikiFormattedText";
-
-    public UIWikiFormattedText() {
-        super();
-        macrosWithTemplateByPosition = new HashMap<Integer, WikiPluginMacro>();
-    }
-
-    @Override
-    public String getFamily() {
-        return COMPONENT_FAMILY;
-    }
-
-    @Override
-    public boolean getRendersChildren() {
-        return true;
-    }
-
-    @Override
-    public String getRendererType() {
-        return null;
-    }
-
-    @Override
-    public void encodeBegin(FacesContext facesContext) throws IOException {
-        if (!isRendered() || getValue() == null) return;
-        log.debug(">>> ENCODE BEGIN of WikiFormattedText component");
-
-        // Use the WikiTextParser to resolve macros
-        WikiTextParser parser = new WikiTextParser((String) getValue(), true, true);
-
-        // Resolve the base document and directory we are resolving against
-        final WikiFile baseFile = (WikiFile)getAttributes().get(ATTR_LINK_BASE_FILE);
-        final Long currentAreaNumber = (Long)getAttributes().get(ATTR_CURRENT_AREA_NUMBER);
-        parser.setCurrentAreaNumber(currentAreaNumber);
-
-        parser.setResolver((WikiLinkResolver)Component.getInstance("wikiLinkResolver"));
-
-        // Set a customized renderer for parser macro callbacks
-        class WikiFormattedTextRenderer extends DefaultWikiTextRenderer {
-
-            @Override
-            public String renderInternalLink(WikiLink internalLink) {
-                return "<a href=\""
-                        + (
-                            internalLink.isBroken()
-                                ? internalLink.getUrl()
-                                : wikiURLRenderer.renderURL(internalLink.getFile())
-                           )
-                        + (
-                            internalLink.getFragment() != null
-                                ? "#"+internalLink.getEncodedFragment()
-                                : ""
-                          )
-                        + "\" target=\""
-                        + (getAttributes().get(ATTR_INTERNAL_TARGET_FRAME) != null ? getAttributes().get(ATTR_INTERNAL_TARGET_FRAME) : "")
-                        + "\" class=\""
-                        + (internalLink.isBroken() ? getAttributes().get(ATTR_BROKEN_LINK_STYLE_CLASS)
-                        : getAttributes().get(ATTR_LINK_STYLE_CLASS)) + "\">"
-                        + internalLink.getDescription() + "</a>";
-            }
-
-            @Override
-            public String renderExternalLink(WikiLink externalLink) {
-                return "<a href=\""
-                        + WikiUtil.escapeEmailURL(externalLink.getUrl())
-                        + "\" target=\""
-                        + (getAttributes().get(ATTR_EXTERNAL_TARGET_FRAME) != null ? getAttributes().get(ATTR_EXTERNAL_TARGET_FRAME) : "")
-                        + "\" class=\""
-                        + (externalLink.isBroken() ? getAttributes().get(ATTR_BROKEN_LINK_STYLE_CLASS)
-                        : getAttributes().get(ATTR_LINK_STYLE_CLASS)) + "\">"
-                        + WikiUtil.escapeEmailURL(externalLink.getDescription()) + "</a>";
-            }
-
-            @Override
-            public String renderFileAttachmentLink(int attachmentNumber, WikiLink attachmentLink) {
-                return "<a href=\""
-                        + wikiURLRenderer.renderURL(baseFile)
-                        + "#attachment" + attachmentNumber
-                        + "\" target=\""
-                        + (getAttributes().get(ATTR_INTERNAL_TARGET_FRAME) != null ? getAttributes().get(ATTR_INTERNAL_TARGET_FRAME) : "")
-                        + "\" class=\""
-                        + getAttributes().get(ATTR_ATTACHMENT_LINK_STYLE_CLASS) + "\">"
-                        + attachmentLink.getDescription() + "[" + attachmentNumber + "]" + "</a>";
-            }
-
-            @Override
-            public String renderThumbnailImageLink(WikiLink link) {
-
-                // TODO: This is not typesafe and clean, need different rendering strategy for WikiUpload subclasses
-                WikiUploadImage image = (WikiUploadImage)link.getFile();
-                if (image.getThumbnail() == 'F') {
-                    // Full size display, no thumbnail
-                    //TODO: Make sure we really don't need this - but it messes up the comment form conversation:
-                    //String imageUrl = WikiUtil.renderURL(image) + "&amp;cid=" + Conversation.instance().getId();
-                    String imageUrl = wikiURLRenderer.renderURL(image);
-                    return "<img src='"+ imageUrl + "'" +
-                            " width='"+ image.getSizeX()+"'" +
-                            " height='"+ image.getSizeY() +"'/>";
-                } else {
-                    // Thumbnail with link display
-
-                    //TODO: Make sure we really don't need this - but it messes up the comment form conversation:
-                    // String thumbnailUrl = WikiUtil.renderURL(image) + "&amp;thumbnail=true&amp;cid=" + Conversation.instance().getId();
-                    String thumbnailUrl = wikiURLRenderer.renderURL(image) + "?thumbnail=true";
-
-                    return "<a href=\""
-                            + (link.isBroken() ? link.getUrl() : wikiURLRenderer.renderURL(image))
-                            + "\" target=\""
-                            + (getAttributes().get(ATTR_INTERNAL_TARGET_FRAME) != null ? getAttributes().get(ATTR_INTERNAL_TARGET_FRAME) : "")
-                            + "\" class=\""
-                            + getAttributes().get(ATTR_THUMBNAIL_LINK_STYLE_CLASS) + "\"><img src=\""
-                            + thumbnailUrl + "\"/></a>";
-                }
-            }
-
-            @Override
-            public String renderMacro(WikiTextMacro macro) {
-
-                WikiPluginMacro pluginMacroWithTemplate = macrosWithTemplateByPosition.get(macro.getPosition());
-                if (pluginMacroWithTemplate == null) {
-                    log.debug("macro does not have an XHTML template/include, skipping: " + macro);
-                    return "";
-                }
-
-                log.debug("firing BEFORE_VIEW_RENDER macro event");
-                Events.instance().raiseEvent(
-                    pluginMacroWithTemplate.getCallbackEventName(WikiPluginMacro.CallbackEvent.BEFORE_VIEW_RENDER),
-                        pluginMacroWithTemplate
-                );
-
-                log.debug("preparing include rendering for macro: " + pluginMacroWithTemplate);
-                UIComponent child = findComponent( pluginMacroWithTemplate.getClientId() );
-                log.debug("JSF child client identifier: " + child.getClientId(getFacesContext()));
-                ResponseWriter originalResponseWriter = getFacesContext().getResponseWriter();
-                StringWriter stringWriter = new StringWriter();
-                ResponseWriter tempResponseWriter = originalResponseWriter
-                        .cloneWithWriter(stringWriter);
-                getFacesContext().setResponseWriter(tempResponseWriter);
-
-                try {
-                    log.debug("rendering template of macro: " + pluginMacroWithTemplate);
-                    JSF.renderChild(getFacesContext(), child);
-
-                    log.debug("firing AFTER_VIEW_RENDER macro event");
-                    Events.instance().raiseEvent(
-                        pluginMacroWithTemplate.getCallbackEventName(WikiPluginMacro.CallbackEvent.AFTER_VIEW_RENDER),
-                        pluginMacroWithTemplate
-                    );
-                }
-                catch (Exception ex) {
-                    throw new RuntimeException(ex);
-                } finally {
-                    getFacesContext().setResponseWriter(originalResponseWriter);
-                }
-                return stringWriter.getBuffer().toString();
-            }
-
-            @Override
-            public void setAttachmentLinks(List<WikiLink> attachmentLinks) {
-                // Put attachments (wiki links...) into the event context for later rendering
-                setLinks("wikiTextAttachments", attachmentLinks);
-            }
-
-            @Override
-            public void setExternalLinks(List<WikiLink> externalLinks) {
-                // Put external links (to targets not on this wiki) into the event context for later rendering
-                setLinks("wikiTextExternalLinks", externalLinks);
-            }
-
-            private void setLinks(String contextVariable, List<WikiLink> links) {
-                // TODO: Need some tricks here with link identifiers and attachment numbers, right now we just skip this if it's already set
-                /// ... hoping that the first caller was the document renderer and not the comment renderer - that means comment attachments are broken
-                List<WikiLink> contextLinks = (List<WikiLink>)Contexts.getEventContext().get(contextVariable);
-                if (contextLinks == null || contextLinks.size()==0) {
-                    Contexts.getEventContext().set(contextVariable, links);
-                }
-                        /*
-                Map<Integer, WikiLink> contextLinks =
-                    (Map<Integer,WikiLink>)Contexts.getEventContext().get(contextVariable);
-                if (contextLinks == null) {
-                    contextLinks = new HashMap<Integer, WikiLink>();
-                }
-                for (WikiLink link : links) {
-                    contextLinks.put(link.getIdentifier(), link);
-                }
-                Contexts.getEventContext().set(contextVariable, contextLinks);
-                */
-            }
-
-            @Override
-            protected String getHeadlineId(Headline h, String headline) {
-                // HTML id attribute has restrictions on valid values... so the easiest way is to make this a WikiLink
-                return HEADLINE_ID_PREFIX+WikiUtil.convertToWikiName(headline);
-                // We also need to access it correctly, see WikiLink.java and getHeadLineLink()
-            }
-
-            @Override
-            protected String getHeadlineLink(Headline h, String headline) {
-                return "<a href=\""+ wikiURLRenderer.renderURL(baseFile)+"#"+WikiTextRenderer.HEADLINE_ID_PREFIX+WikiUtil.convertToWikiName(headline)+"\">"
-                        + headline
-                       +"</a>";
-            }
-        }
-
-        parser.setRenderer(new WikiFormattedTextRenderer());
-
-        try {
-            log.debug("parsing wiki text for HTML encoding");
-            parser.parse();
-
-        } catch (RecognitionException rex) {
-            // Log a nice message for any lexer/parser errors, users can disable this if they want to
-            log.warn( WikiFormattedTextValidator.getErrorMessage((String) getValue(), rex) );
-        } catch (ANTLRException ex) {
-            // All other errors are fatal;
-            throw new RuntimeException(ex);
-        }
-
-        facesContext.getResponseWriter().write(parser.toString());
-
-        log.debug("<<< ENCODE END of WikiFormattedText component");
-    }
-
-    protected void addMacroWithTemplate(WikiPluginMacro pluginMacro) {
-        macrosWithTemplateByPosition.put(pluginMacro.getPosition(), pluginMacro);
-    }
-
-}

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFaceletsResourceResolver.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFaceletsResourceResolver.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFaceletsResourceResolver.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -11,7 +11,7 @@
 import java.net.URL;
 
 /**
- * Utitility to load Facelets XHTML files as a resource from the classapth.
+ * Utitility to load Facelets XHTML files as a resource from the classpath.
  *
  * @author Christian Bauer
  */

Deleted: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFormattedTextHandler.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFormattedTextHandler.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFormattedTextHandler.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -1,378 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.seam.wiki.core.ui;
-
-import antlr.ANTLRException;
-import antlr.RecognitionException;
-import com.sun.facelets.FaceletContext;
-import com.sun.facelets.el.VariableMapperWrapper;
-import com.sun.facelets.tag.MetaRuleset;
-import com.sun.facelets.tag.MetaTagHandler;
-import com.sun.facelets.tag.TagAttribute;
-import com.sun.facelets.tag.TagConfig;
-import com.sun.facelets.tag.jsf.ComponentSupport;
-import org.jboss.seam.Component;
-import org.jboss.seam.contexts.Contexts;
-import org.jboss.seam.core.Events;
-import org.jboss.seam.core.Expressions;
-import org.jboss.seam.faces.ResourceLoader;
-import org.jboss.seam.log.Log;
-import org.jboss.seam.log.Logging;
-import org.jboss.seam.wiki.core.engine.WikiTextParser;
-import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
-import org.jboss.seam.wiki.core.plugin.PluginRegistry;
-import org.jboss.seam.wiki.core.plugin.metamodel.MacroPluginModule;
-import org.jboss.seam.wiki.core.renderer.NullWikiTextRenderer;
-import org.jboss.seam.wiki.core.model.WikiTextMacro;
-import org.ajax4jsf.component.html.HtmlLoadStyle;
-
-import javax.el.ELException;
-import javax.el.VariableMapper;
-import javax.faces.FacesException;
-import javax.faces.component.UIComponent;
-import java.io.IOException;
-import java.net.URL;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.Stack;
-
-/**
- * Creates a <tt>UIWikiFormattedText</tt> JSF component and substitutes macro names in wiki
- * text with real macro components in the tree. These <tt>UIMacro</tt> components are
- * build from XHTML fragments/includes. Interacts closely with the state of the
- * <tt>UIWikiFormattedText</tt> component to split component tree creation and rendering duties.
- *
- * @author Peter Muir
- * @author Christian Bauer
- */
-public class WikiFormattedTextHandler extends MetaTagHandler {
-
-    public static final String MACRO_STACK_PAGE_VARIABLE = "macroStack";
-
-    private Log log = Logging.getLog(WikiFormattedTextHandler.class);
-
-    private static final String MARK = "org.jboss.seam.wiki.core.ui.WikiFormattedTextHandler";
-    private TagAttribute valueAttribute;
-
-    public WikiFormattedTextHandler(TagConfig config) {
-        super(config);
-        this.valueAttribute = this.getRequiredAttribute("value");
-    }
-
-    /*
-    * Main apply method called by facelets to create this component.
-    */
-    public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, ELException {
-        log.debug(">>> building wiki text components for child of: " + parent.getClientId(ctx.getFacesContext()));
-        String id = ctx.generateUniqueId(this.tagId);
-        UIComponent cmp = findChildByTagId(parent, id);
-        if (cmp == null) {
-            cmp = createComponent(ctx);
-            cmp.getAttributes().put(MARK, id);
-        }
-        this.nextHandler.apply(ctx, cmp);
-        parent.getChildren().add(cmp);
-        createMacroComponents(ctx, cmp);
-        log.debug("<<< completed building wiki text components for child of: " + parent.getClientId(ctx.getFacesContext()));
-    }
-
-    private UIComponent createComponent(FaceletContext ctx) {
-        UIWikiFormattedText wikiFormattedText = new UIWikiFormattedText();
-        setAttributes(ctx, wikiFormattedText);
-        return wikiFormattedText;
-    }
-
-    /*
-    * Have to manually wire the component as the Facelets magic wirer
-    * is a package scoped class.
-    */
-    @Override
-    protected void setAttributes(FaceletContext ctx, Object instance) {
-        UIComponent cmp = (UIComponent) instance;
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_LINK_STYLE_CLASS);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_BROKEN_LINK_STYLE_CLASS);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_ATTACHMENT_LINK_STYLE_CLASS);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_THUMBNAIL_LINK_STYLE_CLASS);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_INTERNAL_TARGET_FRAME);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_EXTERNAL_TARGET_FRAME);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_LINK_BASE_FILE);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_CURRENT_AREA_NUMBER);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_ENABLE_MACRO_RENDERING, false);
-        setAttribute(ctx, cmp, UIWikiFormattedText.ATTR_ENABLE_TRANSIENT_MACROS, false);
-    }
-
-    @Override
-    protected MetaRuleset createMetaRuleset(Class type) {
-        return super.createMetaRuleset(type).ignoreAll();
-    }
-
-    /**
-     * We create the included macro template components as first-class components here.
-     * <p/>
-     * This routine parses the wiki text and for each encountered wiki macro, it tries to
-     * include an XHTML template. If no template is found, we do nothing. If a template is
-     * found, we also include its CSS into the document header, then add it to the parent
-     * component, the <tt>UIWikiFormattedText</tt> we are handling. This parent component
-     * keeps a map of <tt>WikiMacro</tt> instances, keyed by position in the rendered
-     * wiki text.
-     * </p>
-     * <p>
-     * Macros are never reentrant, that means a macro can not render itself. To avoid this,
-     * we push a macro onto a stack before including it in the component tree, after checking if
-     * it is already present on the stack. If it is already present, we log a warning and don't do
-     * anything. After rendering, we pop the stack. The stack is held in the PAGE context.
-     * </p>
-     * @param ctx FaceletContext
-     * @param parent Parent component
-     */
-    private void createMacroComponents(final FaceletContext ctx, final UIComponent parent) {
-        if (!(parent instanceof UIWikiFormattedText)) return;
-        final UIWikiFormattedText wikiFormattedTextComponent = (UIWikiFormattedText) parent;
-
-        String unparsed = valueAttribute.getValue(ctx);
-
-        // Don't forget this, transporting the value to the handled component, we need to render it (again) later
-        wikiFormattedTextComponent.setValue(unparsed);
-
-        if (getAttribute(UIWikiFormattedText.ATTR_ENABLE_MACRO_RENDERING) == null ||
-            !getAttribute(UIWikiFormattedText.ATTR_ENABLE_MACRO_RENDERING).getBoolean(ctx)) {
-            log.debug("macro rendering disabled");
-            return;
-        }
-
-        // We need to parse the wiki text once (later again for rendering) to find all macros in the text
-        log.debug("creating macro components from wiki text macros");
-        WikiTextParser parser = new WikiTextParser(unparsed, true, false);
-        parser.setRenderer(
-            new NullWikiTextRenderer() {
-
-                // A collection of all macros (whether they have templates or not) that we found in this piece of wiki text
-                final Set<String> macrosFoundInWikiText = new HashSet<String>();
-
-                @Override
-                public String renderMacro(WikiTextMacro wikiTextMacro) {
-                    log.debug("=== found macro in wiki text: " + wikiTextMacro);
-
-                    // Check reentrancy
-                    if (!isMacroOnPageStack(wikiTextMacro)) {
-                        log.debug("adding macro to page macro stack");
-                        getPageMacroStack().push(wikiTextMacro);
-                    } else {
-                        log.warn("macros are not reentrant, duplicate macro on page stack: " + wikiTextMacro);
-                        return null;
-                    }
-
-                    // Check if the wikiTextMacro actually is registered, we don't build unknown macros
-                    WikiPluginMacro pluginMacro = PluginRegistry.instance().createWikiPluginMacro(wikiTextMacro);
-                    if (pluginMacro == null) {
-                        log.info("macro is not bound in plugin registry: " + wikiTextMacro);
-                        getPageMacroStack().pop();
-                        return null;
-                    }
-
-                    // Check if we can find the template to include for this wikiTextMacro
-                    String macroIncludePath = getMacroIncludePath(pluginMacro);
-                    if (macroIncludePath == null) {
-                        getPageMacroStack().pop();
-                        return null;
-                    }
-
-                    // Before we build the nested components, set the WikiMacro instance in the PAGE context under a
-                    // unique name, so we can use a VariableMapper later and alias this as 'currentMacro'
-                    String macroPageVariableName = pluginMacro.getPageVariableName();
-                    log.debug("setting WikiMacro instance in PAGE context as variable named: " + macroPageVariableName);
-                    Contexts.getPageContext().set(macroPageVariableName, pluginMacro);
-
-                    // Whoever wants to do something before we finally build the XHTML template
-                    log.debug("firing VIEW_BUILD macro event");
-                    Events.instance().raiseEvent(pluginMacro.getCallbackEventName(WikiPluginMacro.CallbackEvent.VIEW_BUILD), pluginMacro);
-
-                    // This is where the magic happens... the UIWikiFormattedText component should have one child after that, a UIMacro
-                    includeMacroFacelet(pluginMacro, macroIncludePath, ctx, wikiFormattedTextComponent);
-
-                    // Now get the identifier of the newly created UIMacro instance and set it for future use
-                    Object macroId = wikiFormattedTextComponent.getAttributes().get(UIMacro.NEXT_MACRO);
-                    if (macroId != null) {
-                        pluginMacro.setClientId(macroId.toString());
-                        wikiFormattedTextComponent.getAttributes().remove(UIMacro.NEXT_MACRO);
-                    } else {
-                        // Best guess based wikiTextMacro renderer, needed during reRendering when we don't build the child
-                        // - only then is NEXT_MACRO set by the MacroComponentHandler
-                        macroId =
-                            wikiFormattedTextComponent.getChildren().get(
-                                wikiFormattedTextComponent.getChildCount()-1
-                            ).getClientId( ctx.getFacesContext() );
-                        pluginMacro.setClientId(macroId.toString());
-                    }
-
-                    // Put an optional CSS include in the header of the wiki document we are rendering in.
-                    // (This needs to happen after the clientId is set, as CSS resource path rendering needs to
-                    // know if it occurs in a JSF request (clientId present) or not.
-                    includeMacroCSS(pluginMacro, wikiFormattedTextComponent);
-
-                    // We need to make the UIMacro child transient if we run in the wiki text editor preview. The reason
-                    // is complicated: If we don't make it transient, all value expressions inside the wikiTextMacro templates that
-                    // use 'currentMacro' will refer to the "old" saved ValueExpression and then of course to the "old"
-                    // VariableMapper. In other words: We need to make sure that the subtree is completely fresh every
-                    // time the wiki text preview is reRendered, otherwise we never get a 'currentMacro' binding updated.
-                    // This also means that VariableMapper is a completely useless construct, because it is basically an
-                    // alias that is evaluated just once.
-                    // Note: This means we can't click on form elements of any plugin/wikiTextMacro template in the preview. This
-                    // should be solved by not showing/ghosting any form elements during preview.
-                    if (getAttribute(UIWikiFormattedText.ATTR_ENABLE_TRANSIENT_MACROS) != null &&
-                        getAttribute(UIWikiFormattedText.ATTR_ENABLE_TRANSIENT_MACROS).getBoolean(ctx)) {
-                        log.debug("setting macro to transient rendering, not storing its state between renderings: " + pluginMacro);
-                        UIMacro uiMacro = (UIMacro)ComponentSupport.findChild(wikiFormattedTextComponent, macroId.toString());
-                        uiMacro.setTransient(true);
-                    }
-
-                    // Finally, pop the wikiTextMacro stack of the page, then transport the finished WikiMacro instance into
-                    // the UIWikiFormattedText component for rendering - we are done building the component tree at this
-                    // point.
-                    getPageMacroStack().pop();
-                    wikiFormattedTextComponent.addMacroWithTemplate(pluginMacro);
-
-                    // Well, we don't render anything here...
-                    return null;
-                }
-
-                private String getMacroIncludePath(WikiPluginMacro pluginMacro) {
-
-                    // Check singleton configuration
-                    if (pluginMacro.getMetadata().isRenderOptionSet(MacroPluginModule.RenderOption.SINGLETON) &&
-                        macrosFoundInWikiText.contains(pluginMacro.getName())) {
-                        log.warn("macro is a SINGLETON, can not be used twice in the same document area: " + pluginMacro);
-                        return null;
-                    } else {
-                        macrosFoundInWikiText.add(pluginMacro.getName());
-                    }
-
-                    // Check skin configuration
-                    String currentSkin = (String)Component.getInstance("skin");
-                    if (!pluginMacro.getMetadata().isAvailableForSkin(currentSkin)) {
-                        log.warn("macro is not available for skin '"+currentSkin+"': " + pluginMacro);
-                        return null;
-                    }
-
-                    // Try to get an XHTML template, our source for building nested components
-                    // Fun with slashes: For some reason, Facelets really needs a slash at the start, otherwise
-                    // it doesn't use my custom ResourceResolver...
-                    String includePath = "/"+ pluginMacro.getMetadata().getPlugin().getPackageDefaultTemplatePath(pluginMacro.getName());
-                    URL faceletURL = ResourceLoader.instance().getResource(includePath);
-                    if (faceletURL == null) {
-                        log.debug("macro has no default include file, not building any components: " + pluginMacro);
-                        return null;
-                    } else {
-                        log.debug("using default template include as a resource from package: " + includePath);
-                    }
-
-                    return includePath;
-                }
-
-                private void includeMacroFacelet(WikiPluginMacro pluginMacro, String includePath, FaceletContext ctx, UIComponent parent) {
-                    VariableMapper orig = ctx.getVariableMapper();
-                    try {
-                        log.debug("setting 'currentMacro' as an EL variable, resolves dynamically to WikiMacro instance in PAGE context");
-                        ctx.setVariableMapper(new VariableMapperWrapper(orig));
-                        ctx.getVariableMapper().setVariable(
-                            WikiPluginMacro.CURRENT_MACRO_EL_VARIABLE,
-                            Expressions.instance().createValueExpression("#{"+ pluginMacro.getPageVariableName()+"}").toUnifiedValueExpression()
-                        );
-
-                        log.debug("including macro facelets file from path: " + includePath);
-                        ctx.includeFacelet(parent, includePath);
-
-                    } catch (IOException e) {
-                        throw new RuntimeException(e);
-                    } finally {
-                        ctx.setVariableMapper(orig);
-                    }
-                }
-
-
-                private void includeMacroCSS(WikiPluginMacro pluginMacro, UIComponent cmp) {
-
-                    String cssPath = "/"+ pluginMacro.getMetadata().getPlugin().getPackageCSSPath()+"/"+ pluginMacro.getName()+".css";
-                    log.debug("trying to load CSS resource from classpath: " + cssPath);
-                    if (ResourceLoader.instance().getResource(cssPath) != null) {
-                        String cssRequestURIPath = pluginMacro.getRequestCSSPath()+"/"+ pluginMacro.getName()+".css";
-                        log.debug("including macro CSS file, rendering URI for document head: " + cssRequestURIPath);
-
-                        // Use Ajax4JSF loader, it can do what we want - add a CSS to the HTML <head>
-                        HtmlLoadStyle style = new HtmlLoadStyle();
-                        style.setSrc(cssRequestURIPath);
-                        
-                        cmp.getChildren().add(style);
-                        // Clear these out in the next build phase
-                        ComponentSupport.markForDeletion(style);
-                    } else {
-                        log.debug("no CSS resource found for macro");
-                    }
-                }
-            }
-        );
-
-        try {
-            parser.parse();
-        } catch (RecognitionException rex) {
-            // Swallow parsing errors, we don't really care here...
-        } catch (ANTLRException ex) {
-            // All other errors are fatal;
-            throw new RuntimeException(ex);
-        }
-    }
-
-    // Some utilities...
-
-    private static UIComponent findChildByTagId(UIComponent parent, String id) {
-        Iterator itr = parent.getFacetsAndChildren();
-        while (itr.hasNext()) {
-            UIComponent c = (UIComponent) itr.next();
-            String cid = (String) c.getAttributes().get(MARK);
-            if (id.equals(cid)) {
-                return c;
-            }
-        }
-        return null;
-    }
-
-    private void setAttribute(FaceletContext ctx, UIComponent cmp, String name) {
-        setAttribute(ctx, cmp, name, null);
-    }
-
-    private void setAttribute(FaceletContext ctx, UIComponent cmp, String name, Object defaultValue) {
-        TagAttribute attribute = this.getAttribute(name);
-        if (attribute != null) {
-            Object o = attribute.getObject(ctx);
-            if (o == null && defaultValue == null) {
-                throw new IllegalArgumentException("Attribute '" + name + "' resolved to null and no default value specified");
-            } else if (o == null) {
-                cmp.getAttributes().put(name, defaultValue);
-            } else {
-                cmp.getAttributes().put(name, o);
-            }
-        }
-    }
-
-    private Stack<WikiTextMacro> getPageMacroStack() {
-        if (Contexts.getPageContext().get(MACRO_STACK_PAGE_VARIABLE) == null) {
-            log.debug("macro page stack is null, creating new stack for this page");
-            Contexts.getPageContext().set(MACRO_STACK_PAGE_VARIABLE, new Stack<WikiTextMacro>());
-        }
-        return (Stack<WikiTextMacro>)Contexts.getPageContext().get(MACRO_STACK_PAGE_VARIABLE);
-    }
-
-    private boolean isMacroOnPageStack(WikiTextMacro macro) {
-        Stack<WikiTextMacro> macroStack = getPageMacroStack();
-        for (WikiTextMacro macroOnPageStack : macroStack) {
-            if (macroOnPageStack.getName().equals(macro.getName())) return true;
-        }
-        return false;
-    }
-
-}
\ No newline at end of file

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiRedirect.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiRedirect.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiRedirect.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -14,7 +14,6 @@
 import org.jboss.seam.log.Log;
 import org.jboss.seam.faces.RedirectException;
 import org.jboss.seam.wiki.core.model.WikiDocument;
-import org.jboss.seam.wiki.core.renderer.WikiURLRenderer;
 
 import javax.faces.context.FacesContext;
 import javax.faces.context.ExternalContext;

Deleted: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiTextEditor.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiTextEditor.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiTextEditor.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -1,47 +0,0 @@
-package org.jboss.seam.wiki.core.ui;
-
-import org.jboss.seam.annotations.Name;
-import org.jboss.seam.annotations.Scope;
-import org.jboss.seam.annotations.Logger;
-import org.jboss.seam.ScopeType;
-import org.jboss.seam.wiki.core.engine.WikiFormattedTextValidator;
-import org.jboss.seam.international.StatusMessages;
-import org.jboss.seam.log.Log;
-
-import static org.jboss.seam.international.StatusMessage.Severity.WARN;
-
-import java.io.Serializable;
-
-import javax.faces.validator.ValidatorException;
-
-/**
- * Utility class bound to Wiki text editor UI.
- * <p>
- *
- * @author Christian Bauer
- */
- at Name("wikiTextEditor")
- at Scope(ScopeType.CONVERSATION)
-public class WikiTextEditor implements Serializable {
-
-    @Logger
-    Log log;
-
-    public void validate(String textEditorId, String value) {
-        if (value == null) return;
-        log.debug("validating value of text editor: " + textEditorId);
-        WikiFormattedTextValidator validator = new WikiFormattedTextValidator();
-        try {
-            validator.validate(null, null, value);
-        } catch (ValidatorException e) {
-            log.debug("exception during validation: " + e.getFacesMessage().getSummary());
-            StatusMessages.instance().addToControl(
-                textEditorId + "TextArea",
-                WARN,
-                e.getFacesMessage().getSummary()
-            );
-        }
-        log.debug("completed validation of text editor value");
-
-    }
-}

Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiURLRenderer.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/renderer/WikiURLRenderer.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiURLRenderer.java	                        (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiURLRenderer.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,152 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.ui;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.wiki.util.WikiUtil;
+import org.jboss.seam.wiki.core.action.prefs.WikiPreferences;
+import org.jboss.seam.wiki.core.model.WikiNode;
+import org.jboss.seam.wiki.core.model.User;
+import org.jboss.seam.wiki.core.model.Feed;
+import org.jboss.seam.wiki.core.ui.FeedServlet;
+
+import java.io.Serializable;
+
+/**
+ * Renders outgoing URLs in a unified fashion, see urlrewrite.xml for incoming URL GET request rewriting.
+ * <p>
+ * Note that some of the rendering is delegated into the domain model for subclasses of <tt>WikiNode</tt>.
+ * </p>
+ *
+ * @author Christian Bauer
+ */
+
+ at Name("wikiURLRenderer")
+ at Scope(ScopeType.CONVERSATION)
+ at AutoCreate
+public class WikiURLRenderer implements Serializable {
+
+    @In
+    String contextPath;
+
+    @In("#{preferences.get('Wiki')}")
+    WikiPreferences prefs;
+
+    public String renderSearchURL(String search) {
+        return renderSearchURL(search, false);
+    }
+
+    public String renderSearchURL(String search, boolean usePrefsPath) {
+        if (search == null || search.length() == 0) return "";
+        StringBuilder url = new StringBuilder();
+        String skin = Component.getInstance("skin") != null ? (String)Component.getInstance("skin") : "d";
+        url.append(usePrefsPath ? prefs.getBaseUrl() : contextPath);
+        url.append("/search_").append(skin).append(".seam?query=").append(encodeURL(search));
+        return url.toString();
+    }
+
+    public String renderTagURL(String tag) {
+        return renderTagURL(tag, false);
+    }
+
+    public String renderTagURL(String tag, boolean usePrefsPath) {
+        if (tag == null || tag.length() == 0) return "";
+        StringBuilder url = new StringBuilder();
+        url.append(usePrefsPath ? prefs.getBaseUrl() : contextPath);
+        url.append("/tag/").append(encodeURL(tag));
+        return url.toString();
+    }
+
+    public String renderUserInfoURL(User user) {
+        return renderUserInfoURL(user, false);
+    }
+
+    public String renderUserInfoURL(User user, boolean usePrefsPath) {
+        if (user == null || user.getUsername() == null) return "";
+        StringBuilder url = new StringBuilder();
+        url.append(usePrefsPath ? prefs.getBaseUrl() : contextPath);
+        url.append("/user/").append(user.getUsername());
+        return url.toString();
+    }
+
+    public String renderAggregateFeedURL(String aggregateId) {
+        return renderAggregateFeedURL(aggregateId, false);
+    }
+
+    public String renderAggregateFeedURL(String aggregateId, boolean usePrefsPath) {
+        if (aggregateId == null) return "";
+        StringBuilder url = new StringBuilder();
+        url.append(usePrefsPath ? prefs.getBaseUrl() : contextPath);
+        url.append("/service/Feed/atom/Aggregate/").append(aggregateId);
+        return url.toString();
+    }
+
+    public String renderFeedURL(Feed feed) {
+        return renderFeedURL(feed, null, null, false);
+    }
+
+    public String renderFeedURL(Feed feed, String tag, String comments) {
+        return renderFeedURL(feed, tag, comments, false);
+    }
+
+    public String renderFeedURL(Feed feed, String tag, String comments, boolean usePrefsPath) {
+        if (feed == null || feed.getId() == null) return "";
+        StringBuilder url = new StringBuilder();
+        url.append(usePrefsPath ? prefs.getBaseUrl() : contextPath);
+        url.append("/service/Feed/atom").append(feed.getURL());
+        if (comments != null && comments.length() >0) {
+            url.append("/Comments/").append(FeedServlet.Comments.valueOf(comments));
+        }
+        if (tag != null && tag.length() >0) {
+            url.append("/Tag/").append(encodeURL(tag));
+        }
+        return url.toString();
+    }
+
+    public String renderURL(WikiNode node) {
+        return renderURL(node, false);
+    }
+
+    public String renderURL(WikiNode node, boolean usePrefsPath) {
+        if (node == null || node.getId() == null) return "";
+        return prefs.isRenderPermlinks() ? renderPermURL(node, usePrefsPath) : renderWikiURL(node, usePrefsPath);
+    }
+
+    public String renderPermURL(WikiNode node) {
+        return renderPermURL(node, false);
+    }
+
+    public String renderPermURL(WikiNode node, boolean usePrefsPath) {
+        if (node == null || node.getId() == null) return "";
+        return (usePrefsPath ? prefs.getBaseUrl() : contextPath) + "/" + node.getPermURL(prefs.getPermlinkSuffix());
+    }
+
+    public String renderWikiURL(WikiNode node) {
+        return renderWikiURL(node, false);
+    }
+
+    public String renderWikiURL(WikiNode node, boolean usePrefsPath) {
+        if (node == null || node.getId() == null) return "";
+        return (usePrefsPath ? prefs.getBaseUrl() : contextPath) + "/" + node.getWikiURL();
+    }
+
+    // TODO: We need more methods here, rendering year/month/day/tag/etc. on WikiURL (not perm url)
+
+    private String encodeURL(String s) {
+        return WikiUtil.encodeURL(s);
+    }
+
+    public static WikiURLRenderer instance() {
+        return (WikiURLRenderer) Component.getInstance(WikiURLRenderer.class);
+    }
+
+}

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/UploadHandler.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/UploadHandler.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/UploadHandler.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -3,7 +3,6 @@
 import org.jboss.seam.wiki.core.model.WikiUpload;
 import org.jboss.seam.wiki.core.upload.editor.UploadEditor;
 import org.jboss.seam.wiki.core.upload.Uploader;
-import org.jboss.seam.wiki.core.engine.WikiLink;
 
 public abstract class UploadHandler<WU extends WikiUpload> {
 

Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/WikiUploadImageHandler.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/WikiUploadImageHandler.java	2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/upload/handler/WikiUploadImageHandler.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -4,9 +4,6 @@
 import org.jboss.seam.wiki.core.upload.Uploader;
 import org.jboss.seam.wiki.core.upload.editor.UploadEditor;
 import org.jboss.seam.wiki.core.upload.editor.WikiUploadImageEditor;
-import org.jboss.seam.wiki.core.engine.WikiLink;
-import org.jboss.seam.wiki.util.WikiUtil;
-import org.jboss.seam.core.Conversation;
 
 import javax.swing.*;
 

Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiFormattedTextValidator.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/engine/WikiFormattedTextValidator.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiFormattedTextValidator.java	                        (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiFormattedTextValidator.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,84 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.wikitext.editor;
+
+import org.jboss.seam.ui.validator.FormattedTextValidator;
+import org.jboss.seam.text.SeamTextParser;
+import antlr.SemanticException;
+
+/**
+ * Disables the Seam Text validation for link tags, so wiki links are OK.
+ * <p>
+ * Also provides some conversation to i18n error messages.
+ * </p>
+ *
+ * TODO: Finish the i18n and well, maybe we should just duplicate the
+ * Seam validator here to drop that dependency on the UI package...
+ *
+ * @author Christian Bauer
+ */
+public class WikiFormattedTextValidator extends FormattedTextValidator {
+
+    public SeamTextParser getSeamTextParser(String s) {
+        SeamTextParser parser = super.getSeamTextParser(s);
+        parser.setSanitizer(
+            new SeamTextParser.DefaultSanitizer() {
+
+                // Disable this part of the validation
+                @Override
+                public void validateLinkTagURI(String s) throws SemanticException {}
+
+                @Override
+                public String getInvalidURIMessage(String s) {
+                    return super.getInvalidURIMessage(s);
+                }
+
+                @Override
+                public String getInvalidElementMessage(String s) {
+                    return super.getInvalidElementMessage(s);
+                }
+
+                @Override
+                public String getInvalidAttributeMessage(String s, String s1) {
+                    return super.getInvalidAttributeMessage(s, s1);
+                }
+
+                @Override
+                public String getInvalidAttributeValueMessage(String s, String s1, String s2) {
+                    return super.getInvalidAttributeValueMessage(s, s1, s2);
+                }
+            }
+        );
+        return parser;
+    }
+
+    @Override
+    public String getNoViableAltErrorMessage(String s, String s1) {
+        return super.getNoViableAltErrorMessage(s, s1);
+    }
+
+    @Override
+    public String getMismatchedTokenErrorMessage(String s, String s1) {
+        return super.getMismatchedTokenErrorMessage(s, s1);
+    }
+
+    @Override
+    public String getSemanticErrorMessage(String s) {
+        return super.getSemanticErrorMessage(s);
+    }
+
+    @Override
+    public int getNumberOfCharsBeforeErrorLocation() {
+        return 20;
+    }
+
+    @Override
+    public int getNumberOfCharsAfterErrorLocation() {
+        return 20;
+    }
+
+}

Added: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextPreview.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextPreview.java	                        (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextPreview.java	2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.wikitext.editor;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.log.Log;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.io.Serializable;
+
+/**
+ * Holds conversation-scoped state of wiki text preview feature.
+ *
+ * @author Christian Bauer
+ */
+ at Name("wikiTextPreview")
+ at Scope(ScopeType.CONVERSATION)
+ at AutoCreate
+public class WikiTextPreview implements Serializable {
+
+    @Logger
+    Log log;
+
+    @In
+    WikiTextValidator wikiTextValidator;
+
+    private Map<String, Boolean> previewEnabled = new HashMap<String, Boolean>();
+
+    public void enablePreview(String key) {
+        previewEnabled.put(key, true);
+    }
+
+    public void enablePreview(String key, String value, boolean valueRequired) {
+        // Only enable preview if text passes validation
+        wikiTextValidator.validate(key, value, valueRequired);
+        if (wikiTextValidator.isValid(key)) previewEnabled.put(key, true);
+    }
+
+    public void disablePreview(String key) {
+        previewEnabled.remove(key);
+    }
+
+    pu