Seam SVN: r8349 - in trunk/src/main/org/jboss/seam/security: jaas and 1 other directories.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2008-06-07 05:40:12 -0400 (Sat, 07 Jun 2008)
New Revision: 8349
Modified:
trunk/src/main/org/jboss/seam/security/Credentials.java
trunk/src/main/org/jboss/seam/security/Identity.java
trunk/src/main/org/jboss/seam/security/JpaTokenStore.java
trunk/src/main/org/jboss/seam/security/RememberMe.java
trunk/src/main/org/jboss/seam/security/RunAsOperation.java
trunk/src/main/org/jboss/seam/security/jaas/SeamLoginModule.java
trunk/src/main/org/jboss/seam/security/management/action/RoleAction.java
Log:
JBSEAM-2079
Modified: trunk/src/main/org/jboss/seam/security/Credentials.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/Credentials.java 2008-06-07 00:25:03 UTC (rev 8348)
+++ trunk/src/main/org/jboss/seam/security/Credentials.java 2008-06-07 09:40:12 UTC (rev 8349)
@@ -76,7 +76,7 @@
public boolean isSet()
{
- return username != null && password != null;
+ return getUsername() != null && password != null;
}
public boolean isInvalid()
Modified: trunk/src/main/org/jboss/seam/security/Identity.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/Identity.java 2008-06-07 00:25:03 UTC (rev 8348)
+++ trunk/src/main/org/jboss/seam/security/Identity.java 2008-06-07 09:40:12 UTC (rev 8349)
@@ -76,8 +76,10 @@
private Principal principal;
private Subject subject;
- private RememberMe rememberMe;
+ private RememberMe rememberMe;
+ private boolean systemOp;
+
private String jaasConfigName = null;
private List<String> preAuthenticationRoles = new ArrayList<String>();
@@ -259,7 +261,7 @@
{
try
{
- if (Events.exists()) Events.instance().raiseEvent(EVENT_QUIET_LOGIN, this);
+ if (Events.exists()) Events.instance().raiseEvent(EVENT_QUIET_LOGIN);
// Ensure that we haven't been authenticated as a result of the EVENT_QUIET_LOGIN event
if (!isLoggedIn(false))
@@ -354,7 +356,9 @@
preAuthenticationRoles.clear();
}
- if (Events.exists()) Events.instance().raiseEvent(EVENT_POST_AUTHENTICATE, this);
+ credentials.setPassword(null);
+
+ if (Events.exists()) Events.instance().raiseEvent(EVENT_POST_AUTHENTICATE, this);
}
/**
@@ -398,6 +402,7 @@
public boolean hasRole(String role)
{
if (!securityEnabled) return true;
+ if (systemOp) return true;
isLoggedIn(true);
@@ -509,6 +514,8 @@
*/
public void checkPermission(String name, String action, Object...arg)
{
+ if (systemOp) return;
+
isLoggedIn(true);
if ( !hasPermission(name, action, arg) )
@@ -529,6 +536,8 @@
public void checkPermission(Object target, String action)
{
+ if (systemOp) return;
+
isLoggedIn(true);
if ( !hasPermission(target, action) )
@@ -557,11 +566,8 @@
*/
public boolean hasPermission(String name, String action, Object...arg)
{
- if (!securityEnabled)
- {
- return true;
- }
-
+ if (!securityEnabled) return true;
+ if (systemOp) return true;
if (permissionMapper == null) return false;
if (arg != null)
@@ -581,11 +587,8 @@
public boolean hasPermission(Object target, String action)
{
- if (!securityEnabled)
- {
- return true;
- }
-
+ if (!securityEnabled) return true;
+ if (systemOp) return true;
if (permissionMapper == null) return false;
return permissionMapper.resolvePermission(target, action);
@@ -692,10 +695,13 @@
principal = operation.getPrincipal();
subject = operation.getSubject();
+ systemOp = operation.isSystemOperation();
+
operation.execute();
}
finally
{
+ systemOp = false;
principal = savedPrincipal;
subject = savedSubject;
}
Modified: trunk/src/main/org/jboss/seam/security/JpaTokenStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/JpaTokenStore.java 2008-06-07 00:25:03 UTC (rev 8348)
+++ trunk/src/main/org/jboss/seam/security/JpaTokenStore.java 2008-06-07 09:40:12 UTC (rev 8349)
@@ -100,7 +100,10 @@
public void invalidateToken(String username, String value)
{
Object token = lookupToken(username, value);
- lookupEntityManager().remove(token);
+ if (token != null)
+ {
+ lookupEntityManager().remove(token);
+ }
}
public void invalidateAll(String username)
Modified: trunk/src/main/org/jboss/seam/security/RememberMe.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/RememberMe.java 2008-06-07 00:25:03 UTC (rev 8348)
+++ trunk/src/main/org/jboss/seam/security/RememberMe.java 2008-06-07 09:40:12 UTC (rev 8349)
@@ -3,7 +3,10 @@
import static org.jboss.seam.ScopeType.SESSION;
import static org.jboss.seam.annotations.Install.BUILT_IN;
+import java.io.Serializable;
import java.rmi.server.UID;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
import javax.faces.context.FacesContext;
@@ -33,7 +36,7 @@
@Scope(SESSION)
@Install(precedence = BUILT_IN, classDependencies = "javax.faces.context.FacesContext")
@BypassInterceptors
-public class RememberMe
+public class RememberMe implements Serializable
{
class UsernameSelector extends Selector
{
@@ -84,10 +87,19 @@
public DecodedToken(String cookieValue)
{
- String decoded = new String(Base64.decode(cookieValue));
-
- username = decoded.substring(0, decoded.indexOf(':'));
- value = decoded.substring(decoded.indexOf(':') + 1);
+ if (cookieValue != null)
+ {
+ try
+ {
+ String decoded = new String(Base64.decode(cookieValue));
+ username = decoded.substring(0, decoded.indexOf(':'));
+ value = decoded.substring(decoded.indexOf(':') + 1);
+ }
+ catch (Exception ex)
+ {
+ // swallow
+ }
+ }
}
public String getUsername()
@@ -136,8 +148,16 @@
if (this.enabled != enabled)
{
this.enabled = enabled;
- usernameSelector.setCookieEnabled(enabled);
- usernameSelector.setDirty();
+ if (mode.equals(Mode.usernameOnly))
+ {
+ usernameSelector.setCookieEnabled(enabled);
+ usernameSelector.setDirty();
+ }
+ else if (mode.equals(Mode.autoLogin))
+ {
+ tokenSelector.setCookieEnabled(enabled);
+ tokenSelector.setDirty();
+ }
}
}
@@ -216,7 +236,7 @@
tokenSelector.setCookiePath(ctx.getExternalContext().getRequestContextPath());
}
- String token = usernameSelector.getCookieValue();
+ String token = tokenSelector.getCookieValue();
if (token != null)
{
setEnabled(true);
@@ -237,29 +257,59 @@
}
}
+ /**
+ * I hate these hacks...
+ */
+ private class BoolWrapper
+ {
+ boolean value;
+ }
+
@Observer(Identity.EVENT_QUIET_LOGIN)
- public void quietLogin(Identity identity)
+ public void quietLogin()
{
+ final Identity identity = Identity.instance();
+
if (mode.equals(Mode.autoLogin) && isEnabled())
{
+ final String username = identity.getCredentials().getUsername();
+ final BoolWrapper userEnabled = new BoolWrapper();
+ final List<String> roles = new ArrayList<String>();
+
// Double check our credentials again
- if (tokenStore.validateToken(identity.getCredentials().getUsername(),
- identity.getCredentials().getPassword()))
- {
- // Success, authenticate the user (if their account is enabled)
- if (IdentityManager.instance().isUserEnabled(identity.getCredentials().getUsername()))
+ if (tokenStore.validateToken(username, identity.getCredentials().getPassword()))
+ {
+ new RunAsOperation(true) {
+ @Override
+ public void execute()
+ {
+ if (IdentityManager.instance().isUserEnabled(username))
+ {
+ userEnabled.value = true;
+
+ for (String role : IdentityManager.instance().getImpliedRoles(username))
+ {
+ roles.add(role);
+ }
+ }
+ }
+ }.run();
+
+ if (userEnabled.value)
{
- identity.getSubject().getPrincipals().add(new SimplePrincipal(
- identity.getCredentials().getUsername()));
- // And populate the roles
- for (String role : IdentityManager.instance().getImpliedRoles(
- identity.getCredentials().getUsername()))
+ identity.unAuthenticate();
+ identity.preAuthenticate();
+
+ // populate the roles
+ for (String role : roles)
{
identity.addRole(role);
}
-
+
+ // Set the principal
+ identity.getSubject().getPrincipals().add(new SimplePrincipal(username));
identity.postAuthenticate();
-
+
autoLoggedIn = true;
}
}
@@ -271,7 +321,7 @@
{
if (mode.equals(Mode.autoLogin))
{
- tokenSelector.getCookieValue();
+ tokenSelector.clearCookieValue();
}
}
@@ -292,8 +342,11 @@
DecodedToken decoded = new DecodedToken(tokenSelector.getCookieValue());
- // Invalidate the current token whether enabled or not
- tokenStore.invalidateToken(decoded.getUsername(), decoded.getValue());
+ // Invalidate the current token (if it exists) whether enabled or not
+ if (decoded.getUsername() != null)
+ {
+ tokenStore.invalidateToken(decoded.getUsername(), decoded.getValue());
+ }
if ( !enabled )
{
@@ -302,8 +355,9 @@
else
{
String value = generateTokenValue();
- tokenStore.createToken(decoded.getUsername(), value);
- tokenSelector.setCookieValueIfEnabled(encodeToken(decoded.getUsername(), value));
+ tokenStore.createToken(identity.getPrincipal().getName(), value);
+ tokenSelector.setCookieEnabled(enabled);
+ tokenSelector.setCookieValueIfEnabled(encodeToken(identity.getPrincipal().getName(), value));
}
}
}
@@ -311,7 +365,10 @@
@Observer(Credentials.EVENT_CREDENTIALS_UPDATED)
public void credentialsUpdated()
{
- usernameSelector.setDirty();
+ if (mode.equals(Mode.usernameOnly))
+ {
+ usernameSelector.setDirty();
+ }
}
/**
Modified: trunk/src/main/org/jboss/seam/security/RunAsOperation.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/RunAsOperation.java 2008-06-07 00:25:03 UTC (rev 8348)
+++ trunk/src/main/org/jboss/seam/security/RunAsOperation.java 2008-06-07 09:40:12 UTC (rev 8349)
@@ -20,6 +20,8 @@
private Set<String> roles;
+ private boolean systemOp = false;
+
public RunAsOperation()
{
principal = new SimplePrincipal(null);
@@ -27,6 +29,17 @@
roles = new HashSet<String>();
}
+ /**
+ * A system operation allows any security checks to pass
+ *
+ * @param systemOp
+ */
+ public RunAsOperation(boolean systemOp)
+ {
+ this();
+ systemOp = true;
+ }
+
public abstract void execute();
public Principal getPrincipal()
@@ -45,6 +58,11 @@
return this;
}
+ public boolean isSystemOperation()
+ {
+ return systemOp;
+ }
+
public void run()
{
for (String role : roles)
Modified: trunk/src/main/org/jboss/seam/security/jaas/SeamLoginModule.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/jaas/SeamLoginModule.java 2008-06-07 00:25:03 UTC (rev 8348)
+++ trunk/src/main/org/jboss/seam/security/jaas/SeamLoginModule.java 2008-06-07 09:40:12 UTC (rev 8349)
@@ -123,7 +123,7 @@
try
{
- boolean success = identityManager.authenticate(username, identity.getPassword());
+ boolean success = identityManager.authenticate(username, identity.getCredentials().getPassword());
if (success)
{
Modified: trunk/src/main/org/jboss/seam/security/management/action/RoleAction.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/action/RoleAction.java 2008-06-07 00:25:03 UTC (rev 8348)
+++ trunk/src/main/org/jboss/seam/security/management/action/RoleAction.java 2008-06-07 09:40:12 UTC (rev 8349)
@@ -2,6 +2,7 @@
import static org.jboss.seam.ScopeType.CONVERSATION;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -14,7 +15,7 @@
@Name("org.jboss.seam.security.management.roleAction")
@Scope(CONVERSATION)
-public class RoleAction
+public class RoleAction implements Serializable
{
private String role;
private List<String> groups;
16 years, 7 months
Seam SVN: r8348 - in trunk/examples/wiki: src/etc/WEB-INF and 37 other directories.
by seam-commits@lists.jboss.org
Author: christian.bauer(a)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
+ */
+@Name("wikiHttpSessionManager")
+(a)Scope(ScopeType.CONVERSATION)
+@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><wiki:macro></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) + "&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) + "&thumbnail=true&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
- */
-@Name("wikiTextEditor")
-(a)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
+ */
+
+@Name("wikiURLRenderer")
+(a)Scope(ScopeType.CONVERSATION)
+@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
+ */
+@Name("wikiTextPreview")
+(a)Scope(ScopeType.CONVERSATION)
+@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);
+ }
+
+ public Boolean isPreviewEnabled(String key) {
+ return previewEnabled.get(key);
+ }
+
+}
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextValidator.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiTextEditor.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextValidator.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextValidator.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,123 @@
+package org.jboss.seam.wiki.core.wikitext.editor;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Logger;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.log.Log;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.HashMap;
+
+import javax.faces.validator.ValidatorException;
+import javax.faces.application.FacesMessage;
+
+/**
+ * Wraps the <tt>WikiFormattedTextValidator</tt> into a conversation-scoped action
+ * that queues the right messages and holds the status of various text editors
+ * for easy error checking by the user interface.
+ *
+ * @see WikiFormattedTextValidator
+ *
+ * @author Christian Bauer
+ */
+@Name("wikiTextValidator")
+(a)Scope(ScopeType.CONVERSATION)
+@AutoCreate
+public class WikiTextValidator implements Serializable {
+
+ @Logger
+ Log log;
+
+ private Map<String, String> validationFailures = new HashMap<String, String>();
+
+ /**
+ * Validates the wiki text value and stores the validation state in this component.
+ *
+ * @param key
+ * The key under which the validation status is stored and can be later retrieved with <tt>isValid()</tt>
+ * @param value
+ * The wiki text
+ * @param valueRequired
+ * Checks before validation if a value is present and required.
+ */
+ public void validate(String key, String value, boolean valueRequired) {
+ log.debug("validating value of text editor: " + key);
+ if (valueRequired && (value == null || value.length() == 0)) {
+ log.debug("validation failed for required but null or empty wiki text with key: " + key);
+ validationFailures.put(key, "lacewiki.msg.wikiTextValidator.EmptyWikiText");
+ return;
+ }
+ WikiFormattedTextValidator validator = new WikiFormattedTextValidator();
+ try {
+ validationFailures.remove(key);
+ validator.validate(null, null, value);
+ } catch (ValidatorException e) {
+ log.debug("exception during validation: " + e.getFacesMessage().getSummary());
+ validationFailures.put(key, convertFacesMessage(e.getFacesMessage()));
+ }
+ log.debug("completed validation of text editor value for key: " + key);
+ }
+
+ /**
+ * Makes it easier to call the validation routine programmatically.
+ *
+ * @param validationCommand
+ * A command that bundles the validation values and options.
+ */
+ public void validate(ValidationCommand validationCommand) {
+ validate(
+ validationCommand.getKey(),
+ validationCommand.getWikiTextValue(),
+ validationCommand.getWikiTextRequired()
+ );
+ }
+
+ /**
+ * Validation status of wiki text with the given key.
+ * <p>
+ * <b>Attention: Returns <tt>true</tt> if the given key can not be found!</b>
+ * </p>
+ *
+ * @param key
+ * The key under which the validation status has been stored, i.e. from an earlier <tt>validate()</tt> call
+ * @return
+ * True if no status for <tt>key</tt> can be found or if previous validation failed for <tt>key</tt>
+ */
+ public boolean isValid(String key) {
+ return !validationFailures.containsKey(key);
+ }
+
+ /**
+ * Return the last validation failure message key for the given wiki text key.
+ *
+ * @param key
+ * The key under which the validation status has been stored, i.e. from an earlier <tt>validate()</tt> call
+ * @return
+ * The validation failure message bundle key or null if no error is known.
+ */
+ public String getValidationFailureMessageBundleKey(String key) {
+ return validationFailures.get(key);
+ }
+
+ // TODO: These are supposed to be message bundle keys, not the literal ANTLR parser messages, see WikiFormattedTextValidator
+ protected String convertFacesMessage(FacesMessage fm) {
+ // Convert the FacesMessage to a StatusMessage (which of course is then converted back to JSF...)
+ StringBuilder msg = new StringBuilder();
+ msg.append(fm.getSummary());
+
+ // Append the detail only if the summary doesn't end with it already
+ if (!fm.getSummary().endsWith(fm.getDetail())) {
+ msg.append(" (").append(fm.getDetail()).append(")");
+ }
+ return msg.toString();
+ }
+
+ public interface ValidationCommand {
+ public String getKey();
+ public String getWikiTextValue();
+ public boolean getWikiTextRequired();
+ }
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/editor/WikiTextValidator.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLink.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/engine/WikiLink.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLink.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLink.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,59 @@
+package org.jboss.seam.wiki.core.wikitext.engine;
+
+import org.jboss.seam.wiki.core.model.WikiFile;
+import org.jboss.seam.wiki.core.wikitext.renderer.WikiTextRenderer;
+import org.jboss.seam.wiki.util.WikiUtil;
+
+/**
+ * Simple value holder for link resolution and rendering.
+ *
+ * @author Christian Bauer
+ */
+public class WikiLink {
+
+ int identifier;
+ WikiFile file;
+ boolean requiresUpdating = false;
+ String url;
+ String fragment;
+ String description;
+ boolean broken = false;
+ boolean external = false;
+
+ public WikiLink(boolean broken, boolean external) {
+ this.broken = broken;
+ this.external = external;
+ }
+
+ public int getIdentifier() { return identifier; }
+ public void setIdentifier(int identifier) { this.identifier = identifier; }
+
+ public WikiFile getFile() { return file; }
+ public void setFile(WikiFile file) { this.file = file; }
+
+ public String getUrl() { return url; }
+ public void setUrl(String url) { this.url = url; }
+
+ public String getFragment() { return fragment; }
+ public void setFragment(String fragment) { this.fragment = fragment; }
+
+ public String getEncodedFragment() {
+ if (fragment != null) {
+ return WikiTextRenderer.HEADLINE_ID_PREFIX+WikiUtil.convertToWikiName(fragment);
+ }
+ return "";
+ }
+
+ public String getDescription() { return description; }
+ public void setDescription(String description) { this.description = description; }
+
+ public boolean isBroken() { return broken; }
+ public boolean isExternal() { return external; }
+
+ public boolean isRequiresUpdating() { return requiresUpdating; }
+ public void setRequiresUpdating(boolean requiresUpdating) { this.requiresUpdating = requiresUpdating; }
+
+ public String toString() {
+ return "File:" + file + " Description: " + description + " URL: " + url;
+ }
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLink.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLinkResolver.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/engine/WikiLinkResolver.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLinkResolver.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLinkResolver.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,175 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.wikitext.engine;
+
+import org.jboss.seam.wiki.core.model.WikiFile;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * The heart of the wiki, converts and resolves human-readable link tags from and to permanent
+ * links that can be stored (or read) persistently. Also resolves link texts (from stored
+ * link tags) to <tt>WikiLink</tt> objects, for rendering.
+ * <p>
+ * Use the supplied regular expressions to implement the methods, or parse the wiki text
+ * completely by hand and convert/resolve links.
+ *
+ * TODO: With a new multi-stage SeamTextParser we could remove most of this regex stuff
+ *
+ * @author Christian Bauer
+ */
+public interface WikiLinkResolver {
+
+ /**
+ * Matches known protocols, e.g. [=>http://foo.bar], which can be ignored and "resolved" as-is
+ */
+ public static final String REGEX_KNOWN_PROTOCOL = "^(http://)|(https://)|(ftp://)|(mailto:).+$";
+
+ /**
+ * Matches customized protocols, e.g. [=>seamjira://123], which should be resolved and rendered
+ */
+ public static final String REGEX_CUSTOM_PROTOCOL = "^([a-zA-Z]+)://(.+)$";
+
+ /**
+ * Matches WikiNode.getName() constraint.
+ */
+ public static final String REGEX_NODE_NAME = "[a-zA-Z0-9]+[^/#\\|\\]\\[]*";
+
+ /**
+ * Matches URL fragments, punctuation is limited, so not all fragments are reachable.
+ */
+ public static final String REGEX_FRAGMENT = "#[\\w\\s\\.\\,\\;\\-\\?\\!\\(\\)\\&\\/]+";
+
+ /**
+ * Matches "Node Name#Fragment123" with two groups.
+ */
+ public static final String REGEX_NODE_NAME_FRAGMENT = "("+REGEX_NODE_NAME+")(" + REGEX_FRAGMENT + ")?";
+
+ /**
+ * Prepended to primary identifiers when links are stored, e.g. [This is a stored link=>wiki://5]
+ */
+ public static final String REGEX_WIKI_PROTOCOL = "wiki://([0-9]+)("+REGEX_FRAGMENT+")?";
+
+ /**
+ * Match [GROUP1=>GROUP1], used to replace links from user input with wiki:// URLs - used
+ * in <tt>convertToWikiProtocol()</tt>.
+ */
+ public static final String REGEX_WIKILINK_FORWARD =
+ Pattern.quote("[") + "([^" + Pattern.quote("]") + "|" + Pattern.quote("[") + "]*)" +
+ "=>([^" + Pattern.quote("]") + Pattern.quote("[") + "]+)" + Pattern.quote("]");
+
+ /**
+ * Match [GROUP1=>wiki://GROUP2], used to replace wiki:// URLs with page names
+ */
+ public static final String REGEX_WIKILINK_REVERSE =
+ Pattern.quote("[") + "([^" + Pattern.quote("]") + "|" + Pattern.quote("[") + "]*)" +
+ "=>" + REGEX_WIKI_PROTOCOL + Pattern.quote("]");
+
+ /**
+ * Match "Foo Bar|Baz Brrr#Fragment" as three groups
+ */
+ public static final String REGEX_WIKILINK_CROSSAREA = "^(" + REGEX_NODE_NAME +")"+ Pattern.quote("|") + REGEX_NODE_NAME_FRAGMENT + "$";
+
+ /**
+ * Replaces clear text links such as <tt>[Link description=>Target Name]</tt> in <tt>wikiText</tt> with
+ * <tt>[Link description=>wiki://id]</tt> strings, usually resolves the target name as a unique wiki name
+ * in some data store.
+ * The <tt>currentAreaNumber</tt> of the current document is supplied and can be used as the namespace for scoped resolving.
+ * <p>
+ * This method should be called whenever a wiki document is stored, we want to store the permanent
+ * identifiers of a target node. That way, the target node can be renamed and the document that links
+ * to that target node still contains the valid link.
+ * </p><p>
+ * Either parse the <tt>wikiText</tt> by hand to find and replace links, or use the
+ * <tt>REGEX_WIKILINK_FORWARD</tt> pattern which matches <tt>[GROUP1=>GROUP2]</tt>.
+ * Convert the target name (<tt>GROUP2</tt>) to a unique wiki name, and then to some primary
+ * identifier which you can lookup again in the future in a reliable fashion. <tt>GROUP1</tt> is
+ * the optional link description entered by the user, you need to keep this string and only replace
+ * <tt>GROUP2</tt> with a permanent identifier (prefixed with the <tt>wiki://</tt> protocol).
+ * </p><p>
+ * Note that cross-namespace linking should be supported, so in addition to <tt>[=>Target Name]</tt>,
+ * links can be entered by the user as <tt>[=>Target Area|Target Name]</tt>. To resolve these link
+ * texts, use <tt>REGEX_WIKILINK_CROSSAREA</tt> on the original <tt>GROUP2</tt>, which produces
+ * two groups. Ignore the given <tt>currentAreaNumber</tt> parameter and resolve in the target namespace entered by
+ * the user on the link tag.
+ * </p><p>
+ * Example pseudo code:
+ * </p><p>
+ * <pre>
+ * if (targetName = wikiText.match(REGEX_WIKI_LINK_FORWARD)) {
+ *
+ * if (targetNamespace, newTargetName = targetName.match(REGEX_WIKILINK_CROSSAREA) {
+ *
+ * wikiText.replace( resolveNodeId(targetNamespace, newTargetName) );
+ *
+ * } else {
+ * wikiText.replace( resolveNodeId(givenNamespace, targetName) );
+ * }
+ * }
+ * </pre>
+ *
+ * @param linkTargets This collection will be filled with <tt>WikiFile</tt> instances which are the link targets in the wiki text
+ * @param currentAreaNumber The currennt area useable as the namespace for scoped resolving
+ * @param wikiText Text with wiki markup containing [=>Target Name] links
+ * @return The <tt>wikiText</tt> with all <tt>[=>Target Name]<tt> links replaced with <tt>[=>wiki://id]</tt>
+ */
+ public String convertToWikiProtocol(Set<WikiFile> linkTargets, Long currentAreaNumber, String wikiText);
+
+ /**
+ * Replace stored text links such as <tt>[Link description=>wiki://id]</tt> with clear text target names, so
+ * users can edit the link again in clear text.
+ * </p><p>
+ * Either parse by hand or use the <tt>REGEX_WIKILINK_REVERSE</tt> pattern, which matches
+ * <tt>[GROUP1=>(wiki://GROUP2)]. Replace with <tt>[GROUP1=>Target Name]</tt> or, if the target is not in
+ * the same namespace as the given <tt>area</tt> parameter, append the area:
+ * <tt>[GROUP1=>Target Area|Target Name]</tt>.
+ *
+ * @param currentAreaNumber The current area useable as the namespace for scoped resolving
+ * @param wikiText Text with wiki markup containing [=>wiki://id] links
+ * @return The <tt>wikiText</tt> with all <tt>[=>wiki://id]<tt> links replaced with <tt>[=>Target Name]</tt>
+ */
+ public String convertFromWikiProtocol(Long currentAreaNumber, String wikiText);
+
+ /**
+ * Resolve the given <tt>linkText</tt> to an instance of <tt>WikiLink</tt> and put it in the <tt>links</tt> map.
+ * <p>
+ * The <tt>WikiLink</tt> objects are used during rendering, the rules are as follows:
+ * <ul>
+ * <li>If the <tt>linkText</tt> matches <tt>REGEX_KNOWN_PROTOCOL</tt>, don't resolve but create
+ * a <tt>WikiLink</tt> instance that contains <tt>url</tt>, <tt>description</tt> (same as <tt>url</tt>),
+ * <tt>broken=false</tt>, <tt>external=true</tt>. The <tt>url</tt> is the actual <tt>linkText</tt>, as-is.
+ * </li>
+ * <li>If the <tt>linkText</tt> matches <tt>REGEX_WIKI_PROTOCOL</tt>, resolve it and create
+ * a <tt>WikiLink</tt> instance that contains the resolved <tt>Node</tt> instance, the node name
+ * as <tt>description</tt>, no <tt>url</tt>, and <tt>external=false</tt>. If the <tt>linkText</tt>
+ * can't be resolved to a <tt>Node</tt>, set <tt>broken=true</tt>, a null <tt>node</tt>, and whatever
+ * <tt>url</tt> and <tt>description</tt> you want to render for a broken link.
+ * </li>
+ * <li>Otherwise, the <tt>linkText</tt> represents a clear text link such as <tt>Target Name</tt> or
+ * <tt>Target Area|TargetName</tt>, which you can resolve if you want and return a
+ * <tt>WikiLink</tt> instance as in the previous rule. If it can't be resolved, return a broken link
+ * indicator as described in the previous rule. If it has been resolved, you may indicate that the
+ * original document that contains this <tt>linkText</tt> should be updated in the datastore (usually
+ * by passing its wiki text content through <tt>convertToWikiProtocol</tt>) - set <tt>requiresUpdating=true</tt>
+ * on the <tt>WikiLink</tt> instance. It's the job of the client of this resolver to handle this flag
+ * (or to ignore it).
+ *</li>
+ * </ul>
+ *
+ * @param currentAreaNumber The current area useable as the namespace for scoped resolving
+ * @param links A map of all resolved <tt>WikiLink</tt> objects, keyed by <tt>linkText</tt>
+ * @param linkText A stored link text, such as "wiki://123" or "http://foo.bar" or "Target Area|Target Name]"
+ */
+ public void resolveLinkText(Long currentAreaNumber, Map<String, WikiLink> links, String linkText);
+
+ public Long resolveWikiDirectoryId(Long currentAreaNumber, String linkText);
+
+ public Long resolveWikiDocumentId(Long currentAreaNumber, String linktext);
+
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiLinkResolver.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiTextParser.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/engine/WikiTextParser.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiTextParser.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiTextParser.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,231 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.wikitext.engine;
+
+import antlr.ANTLRException;
+import antlr.SemanticException;
+import org.jboss.seam.text.SeamTextLexer;
+import org.jboss.seam.text.SeamTextParser;
+import org.jboss.seam.wiki.core.model.*;
+import org.jboss.seam.wiki.core.wikitext.renderer.WikiTextRenderer;
+
+import java.io.StringReader;
+import java.util.*;
+
+/**
+ * Parses SeamText markup and also resolves link and macro tags as wiki links and wiki plugins.
+ * <p>
+ * Don't forget to set the resolver and renderer base with <tt>setCurrentAreaNumber()</tt>!
+ * </p><p>
+ * Picks the <tt>WikiLinkResolver</tt> present in the contextual variable <tt>wikiLinkResolver</tt>. Calls
+ * out to a <tt>WikiTextRender</tt> for the actual in-document rendering of wiki links and wiki plugins. Might update
+ * the <tt>currentDocument</tt>'s content, this change should be flushed to the datastore after calling
+ * the parser.
+ * </p><p>
+ * After parsing, all links to attachments and all external links are pushed onto the renderer, where they
+ * can be used to render an attachment list or appendixes to the text.
+ * </p>
+ *
+ * @see org.jboss.seam.wiki.core.wikitext.renderer.WikiTextRenderer
+ *
+ * @author Christian Bauer
+ */
+public class WikiTextParser extends SeamTextParser {
+
+ private int macroPosition = 0;
+ private int linkCounter = 0;
+
+ private WikiTextRenderer renderer;
+
+ private boolean resolveLinks;
+ private WikiLinkResolver resolver;
+ private Long currentAreaNumber;
+
+ private Map<String, WikiLink> resolvedLinks = new HashMap<String, WikiLink>();
+ private List<WikiLink> attachments = new ArrayList<WikiLink>();
+ private List<WikiLink> externalLinks = new ArrayList<WikiLink>();
+ private Set<String> macroNames = new HashSet<String>();
+ private boolean renderDuplicateMacros;
+
+ public WikiTextParser(String wikiText, boolean renderDuplicateMacros, boolean resolveLinks) {
+ super(new SeamTextLexer(new StringReader(wikiText)));
+ this.renderDuplicateMacros = renderDuplicateMacros;
+ this.resolveLinks = resolveLinks;
+
+ setSanitizer(
+ new DefaultSanitizer() {
+ @Override
+ public void validateLinkTagURI(String s) throws SemanticException {
+ // NOOP, we validate that later in linkTag()
+ }
+ }
+ );
+ }
+
+ /**
+ * Mandatory, you need to set a renderer before starting the parer.
+ *
+ * @param renderer an implementation of WikiTextRenderer
+ * @return the called instance
+ */
+ public WikiTextParser setRenderer(WikiTextRenderer renderer) {
+ this.renderer = renderer;
+ return this;
+ }
+
+ /**
+ * Mandatory, you need to set a resolver before starting the parer.
+ *
+ * @param resolver an implementation of WikiLinkresolver
+ * @return the called instance
+ */
+ public WikiTextParser setResolver(WikiLinkResolver resolver) {
+ this.resolver = resolver;
+ return this;
+ }
+
+ /*
+ * The render/link resolving base
+ * @return the called instance
+ */
+
+ public void setCurrentAreaNumber(Long currentAreaNumber) {
+ this.currentAreaNumber = currentAreaNumber;
+ }
+
+ /**
+ * Start parsing the wiki text and resolve wiki links and wiki plugins.
+ * <p>
+ * @throws ANTLRException if lexer or parser errors occur, see
+ */
+ public void parse() throws ANTLRException {
+ if (renderer == null) throw new IllegalStateException("WikiTextParser requires not null setRenderer()");
+
+ if (resolveLinks) {
+ if (resolver == null) throw new IllegalStateException("WikiTextParser requires not null setResolver()");
+ if (currentAreaNumber == null) throw new IllegalStateException("WikiTextParser requires not null setCurrentAreaNumber()");
+ }
+
+ startRule();
+
+ renderer.setAttachmentLinks(attachments);
+ renderer.setExternalLinks(externalLinks);
+ }
+
+ protected String linkTag(String descriptionText, String linkText) {
+ if (!resolveLinks) {
+ // Don't resolve links, just call back to renderer for simple inline rendering of what we have
+ WikiLink unresolvedLink = new WikiLink(false, false);
+ unresolvedLink.setDescription(descriptionText);
+ unresolvedLink.setUrl(linkText);
+ return renderer.renderInternalLink(unresolvedLink);
+ }
+
+ resolver.resolveLinkText(currentAreaNumber, resolvedLinks, linkText);
+ WikiLink link = resolvedLinks.get((linkText));
+ if (link == null) return "";
+
+ // Set an internal identifier, used for attachments and external links we later push into a hashmap into the contexts
+ link.setIdentifier(linkCounter++);
+
+ // Override the description of the WikiLink with description found in tag
+ String finalDescriptionText =
+ (descriptionText!=null && descriptionText.length() > 0 ? descriptionText : link.getDescription());
+ link.setDescription(finalDescriptionText);
+
+ // Link to upload (inline or attached)
+ if (link.getFile() != null && link.getFile().isInstance(WikiUpload.class)) {
+ WikiUpload upload = (WikiUpload)link.getFile();
+ if (upload.isAttachedToDocuments()) {
+ if (!attachments.contains(link)) {
+ attachments.add(link);
+ }
+ return renderer.renderFileAttachmentLink((attachments.indexOf(link)+1), link);
+ } else {
+ return renderer.renderThumbnailImageLink(link);
+ }
+ }
+
+ // External link
+ if (link.isExternal()) {
+ if (!externalLinks.contains(link)) externalLinks.add(link);
+ return renderer.renderExternalLink(link);
+ }
+
+ // Regular link
+ return renderer.renderInternalLink(link);
+ }
+
+ protected String paragraphOpenTag() {
+ return renderer.renderParagraphOpenTag();
+ }
+
+ protected String preformattedOpenTag() {
+ return renderer.renderPreformattedOpenTag();
+ }
+
+ protected String blockquoteOpenTag() {
+ return renderer.renderBlockquoteOpenTag();
+ }
+
+ protected String headline1(String headline) {
+ return renderer.renderHeadline1(headline);
+ }
+
+ protected String headline2(String headline) {
+ return renderer.renderHeadline2(headline);
+ }
+
+ protected String headline3(String headline) {
+ return renderer.renderHeadline3(headline);
+ }
+
+ protected String headline4(String headline) {
+ return renderer.renderHeadline4(headline);
+ }
+
+ protected String orderedListOpenTag() {
+ return renderer.renderOrderedListOpenTag();
+ }
+
+ protected String orderedListItemOpenTag() {
+ return renderer.renderOrderedListItemOpenTag();
+ }
+
+ protected String unorderedListOpenTag() {
+ return renderer.renderUnorderedListOpenTag();
+ }
+
+ protected String unorderedListItemOpenTag() {
+ return renderer.renderUnorderedListItemOpenTag();
+ }
+
+ protected String emphasisOpenTag() {
+ return renderer.renderEmphasisOpenTag();
+ }
+
+ protected String emphasisCloseTag() {
+ return renderer.renderEmphasisCloseTag();
+ }
+
+ protected String macroInclude(Macro macro) {
+ if (macro.name == null || macro.name.length() == 0) return "";
+
+ if ( (macroNames.contains(macro.name) && renderDuplicateMacros) || !macroNames.contains(macro.name)) {
+ macroNames.add(macro.name);
+
+ WikiTextMacro wikiTextMacro = new WikiTextMacro(macro.name, macroPosition++);
+ wikiTextMacro.setParams(macro.params);
+
+ return renderer.renderMacro(wikiTextMacro);
+ } else {
+ macroPosition++;
+ return "[Can't use the same macro twice!]";
+ }
+ }
+
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/engine/WikiTextParser.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/DefaultWikiTextRenderer.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/renderer/DefaultWikiTextRenderer.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/DefaultWikiTextRenderer.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/DefaultWikiTextRenderer.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,124 @@
+package org.jboss.seam.wiki.core.wikitext.renderer;
+
+import org.jboss.seam.wiki.core.wikitext.renderer.WikiTextRenderer;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLink;
+import org.jboss.seam.wiki.core.model.WikiTextMacro;
+import org.jboss.seam.wiki.core.ui.WikiURLRenderer;
+import org.jboss.seam.Component;
+
+import java.util.List;
+
+/**
+ * Convenience class that renders some sensible defaults that apply for the wiki.
+ *
+ * @author Christian Bauer
+ */
+public class DefaultWikiTextRenderer implements WikiTextRenderer {
+
+ protected WikiURLRenderer wikiURLRenderer = (WikiURLRenderer) Component.getInstance(WikiURLRenderer.class);
+
+ public static enum Headline {
+ H1, H2, H3, H4
+ }
+
+ public String renderInternalLink(WikiLink internalLink) {
+ return !internalLink.isBroken() ?
+ "<a href=\""
+ + wikiURLRenderer.renderURL(internalLink.getFile())
+ + "\">"
+ + internalLink.getDescription()
+ + "</a>" : "[Broken Link]";
+ }
+
+ public String renderExternalLink(WikiLink externalLink) {
+ return "<a href=\""
+ + externalLink.getUrl()
+ + "\">"
+ + externalLink.getDescription()
+ + "</a>";
+ }
+
+ public String renderFileAttachmentLink(int attachmentNumber, WikiLink attachmentLink) {
+ return "[Attachment]";
+ }
+
+ public String renderThumbnailImageLink(WikiLink link) {
+ return "[Embedded Image]";
+ }
+
+ public String renderMacro(WikiTextMacro macro) {
+ return "[Macro]";
+ }
+
+ public void setAttachmentLinks(List<WikiLink> attachmentLinks) {}
+ public void setExternalLinks(List<WikiLink> externalLinks) {}
+
+ public String renderParagraphOpenTag() {
+ return "<p class=\"wikiPara\">\n";
+ }
+
+ public String renderPreformattedOpenTag() {
+ return "<pre class=\"wikiPreformatted\">\n";
+ }
+
+ public String renderBlockquoteOpenTag() {
+ return "<blockquote class=\"wikiBlockquote\">\n";
+ }
+
+ public String renderHeadline1(String headline) {
+ return "<h1 class=\"wikiHeadline1\" id=\""+getHeadlineId(Headline.H1, headline)+"\">"
+ + getHeadlineLink(Headline.H1, headline)
+ + "</h1>";
+ }
+
+ public String renderHeadline2(String headline) {
+ return "<h2 class=\"wikiHeadline2\" id=\""+getHeadlineId(Headline.H2, headline)+"\">"
+ + getHeadlineLink(Headline.H2, headline)
+ + "</h2>";
+ }
+
+ public String renderHeadline3(String headline) {
+ return "<h3 class=\"wikiHeadline3\" id=\""+getHeadlineId(Headline.H3, headline)+"\">"
+ + getHeadlineLink(Headline.H3, headline)
+ + "</h3>";
+ }
+
+ public String renderHeadline4(String headline) {
+ return "<h4 class=\"wikiHeadline4\" id=\""+getHeadlineId(Headline.H4, headline)+"\">"
+ + getHeadlineLink(Headline.H4, headline)
+ + "</h4>";
+ }
+
+
+ public String renderOrderedListOpenTag() {
+ return "<ol class=\"wikiOrderedList\">\n";
+ }
+
+ public String renderOrderedListItemOpenTag() {
+ return "<li class=\"wikiOrderedListItem\">";
+ }
+
+ public String renderUnorderedListOpenTag() {
+ return "<ul class=\"wikiUnorderedList\">\n";
+ }
+
+ public String renderUnorderedListItemOpenTag() {
+ return "<li class=\"wikiUnorderedListItem\">";
+ }
+
+ public String renderEmphasisOpenTag() {
+ return "<i class=\"wikiEmphasis\">";
+ }
+
+ public String renderEmphasisCloseTag() {
+ return "</i>";
+ }
+
+ protected String getHeadlineId(Headline h, String headline) {
+ return "";
+ }
+
+ protected String getHeadlineLink(Headline h, String headline) {
+ return headline;
+ }
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/DefaultWikiTextRenderer.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/MacroWikiTextRenderer.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/renderer/MacroWikiTextRenderer.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/MacroWikiTextRenderer.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/MacroWikiTextRenderer.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,39 @@
+package org.jboss.seam.wiki.core.wikitext.renderer;
+
+import java.util.Set;
+import java.util.LinkedHashSet;
+
+import antlr.RecognitionException;
+import antlr.ANTLRException;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiTextParser;
+import org.jboss.seam.wiki.core.model.WikiTextMacro;
+
+public class MacroWikiTextRenderer extends NullWikiTextRenderer {
+
+ private Set<WikiTextMacro> macros = new LinkedHashSet<WikiTextMacro>();
+
+ @Override
+ public String renderMacro(WikiTextMacro macro) {
+ macros.add(macro);
+ return null;
+ }
+
+ public Set<WikiTextMacro> getMacros() {
+ return macros;
+ }
+
+ public static MacroWikiTextRenderer renderMacros(String wikiText) {
+ WikiTextParser parser = new WikiTextParser(wikiText, false, false);
+ MacroWikiTextRenderer renderer = new MacroWikiTextRenderer();
+ try {
+ parser.setRenderer(renderer).parse();
+ } catch (RecognitionException rex) {
+ // Swallowing, we don't really care if there was a parse error
+ } catch (ANTLRException ex) {
+ // All other errors are fatal;
+ throw new RuntimeException(ex);
+ }
+ return renderer;
+ }
+
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/MacroWikiTextRenderer.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/NullWikiTextRenderer.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/renderer/NullWikiTextRenderer.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/NullWikiTextRenderer.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/NullWikiTextRenderer.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,37 @@
+package org.jboss.seam.wiki.core.wikitext.renderer;
+
+import org.jboss.seam.wiki.core.wikitext.renderer.WikiTextRenderer;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLink;
+import org.jboss.seam.wiki.core.model.WikiTextMacro;
+
+import java.util.List;
+
+/**
+ * Renders nothing for links and macros and unstyled HTML for anything else.
+ *
+ * @author Christian Bauer
+ */
+public class NullWikiTextRenderer implements WikiTextRenderer {
+
+ public String renderInternalLink(WikiLink internalLink) { return null; }
+ public String renderExternalLink(WikiLink externalLink) { return null; }
+ public String renderFileAttachmentLink(int attachmentNumber, WikiLink attachmentLink) { return null; }
+ public String renderThumbnailImageLink(WikiLink link) { return null; }
+ public void setAttachmentLinks(List<WikiLink> attachmentLinks) {}
+ public void setExternalLinks(List<WikiLink> externalLinks) {}
+ public String renderMacro(WikiTextMacro macro) { return null; }
+ public String renderParagraphOpenTag() { return "<p>\n"; }
+ public String renderPreformattedOpenTag() { return "<pre>\n"; }
+ public String renderBlockquoteOpenTag() { return "<blockquote>\n"; }
+ public String renderHeadline1(String headline) { return "<h1>"+headline+"</h1>"; }
+ public String renderHeadline2(String headline) { return "<h2>"+headline+"</h2>"; }
+ public String renderHeadline3(String headline) { return "<h3>"+headline+"</h3>"; }
+ public String renderHeadline4(String headline) { return "<h4>"+headline+"</h4>"; }
+ public String renderOrderedListOpenTag() { return "<ol>\n"; }
+ public String renderOrderedListItemOpenTag() { return "<li>"; }
+ public String renderUnorderedListOpenTag() { return "<ul>\n"; }
+ public String renderUnorderedListItemOpenTag() { return "<li>"; }
+ public String renderEmphasisOpenTag() { return "<i>"; }
+ public String renderEmphasisCloseTag() { return "</i>"; }
+
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/NullWikiTextRenderer.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/WikiTextRenderer.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/engine/WikiTextRenderer.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/WikiTextRenderer.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/WikiTextRenderer.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,39 @@
+package org.jboss.seam.wiki.core.wikitext.renderer;
+
+import org.jboss.seam.wiki.core.model.WikiTextMacro;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLink;
+
+import java.util.List;
+
+/**
+ * Called by the WikiTextParser to render [A Link=>Target] and [<=MacroName].
+ *
+ * @author Christian Bauer
+ */
+public interface WikiTextRenderer {
+
+ public static final String HEADLINE_ID_PREFIX = "H-";
+
+ public String renderInternalLink(WikiLink internalLink);
+ public String renderExternalLink(WikiLink externalLink);
+ public String renderThumbnailImageLink(WikiLink link);
+ public String renderFileAttachmentLink(int attachmentNumber, WikiLink attachmentLink);
+ public String renderMacro(WikiTextMacro macro);
+
+ public String renderParagraphOpenTag();
+ public String renderPreformattedOpenTag();
+ public String renderBlockquoteOpenTag();
+ public String renderHeadline1(String headline);
+ public String renderHeadline2(String headline);
+ public String renderHeadline3(String headline);
+ public String renderHeadline4(String headline);
+ public String renderOrderedListOpenTag();
+ public String renderOrderedListItemOpenTag();
+ public String renderUnorderedListOpenTag();
+ public String renderUnorderedListItemOpenTag();
+ public String renderEmphasisOpenTag();
+ public String renderEmphasisCloseTag();
+
+ public void setAttachmentLinks(List<WikiLink> attachmentLinks);
+ public void setExternalLinks(List<WikiLink> externalLinks);
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/WikiTextRenderer.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/MacroComponentHandler.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/MacroComponentHandler.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/MacroComponentHandler.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/MacroComponentHandler.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,26 @@
+package org.jboss.seam.wiki.core.wikitext.renderer.jsf;
+
+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 in the JSF component tree.
+ *
+ * @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()));
+ }
+
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/MacroComponentHandler.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Added: 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/MacroIncludeTextRenderer.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/MacroIncludeTextRenderer.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,257 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.wikitext.renderer.jsf;
+
+import org.jboss.seam.wiki.core.wikitext.renderer.NullWikiTextRenderer;
+import org.jboss.seam.wiki.core.plugin.PluginRegistry;
+import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
+import org.jboss.seam.wiki.core.plugin.metamodel.MacroPluginModule;
+import org.jboss.seam.wiki.core.model.WikiTextMacro;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.core.ResourceLoader;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.Component;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.log.Logging;
+import org.ajax4jsf.component.html.HtmlLoadStyle;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+import java.io.IOException;
+import java.net.URL;
+
+import com.sun.facelets.FaceletContext;
+import com.sun.facelets.el.VariableMapperWrapper;
+import com.sun.facelets.tag.jsf.ComponentSupport;
+
+import javax.faces.component.UIComponent;
+import javax.el.VariableMapper;
+
+/**
+ * Creates the included macro template components as first-class components in the JSF view
+ * as children of the <tt>UIWikiFormattedText</tt> component.
+ *
+ * <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. This map of macros can be pulled out later, when we render the JSF view
+ * tree.
+ * </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>
+ * <p>
+ * This code is complicated, because Facelets is complicated. Do not touch it unless you
+ * are absolutely sure you know what you are doing.
+ * </p>
+ *
+ * @author Christian Bauer
+ */
+public class MacroIncludeTextRenderer extends NullWikiTextRenderer {
+
+ private Log log = Logging.getLog(WikiFormattedTextHandler.class);
+
+ public static final String MACRO_STACK_PAGE_VARIABLE = "macroStack";
+
+ // A collection of all macros (whether they have templates or not) that we found in this piece of wiki text
+ private Set<String> macrosFoundInWikiText = new HashSet<String>();
+
+ UIWikiFormattedText parent;
+ FaceletContext context;
+ boolean enableTransientMacros;
+
+ public MacroIncludeTextRenderer(UIWikiFormattedText parent, FaceletContext context, boolean enableTransientMacros) {
+ this.parent = parent;
+ this.context = context;
+ this.enableTransientMacros = enableTransientMacros;
+ }
+
+ @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, context, parent);
+
+ // Now get the identifier of the newly created UIMacro instance and set it for future use
+ Object macroId = parent.getAttributes().get(UIMacro.NEXT_MACRO);
+ if (macroId != null) {
+ pluginMacro.setClientId(macroId.toString());
+ parent.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 =
+ parent.getChildren().get(
+ parent.getChildCount() - 1
+ ).getClientId(context.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, parent);
+
+ // 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 (enableTransientMacros) {
+ log.debug("setting macro to transient rendering, not storing its state between renderings: " + pluginMacro);
+ UIMacro uiMacro = (UIMacro) ComponentSupport.findChild(parent, 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();
+ parent.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 <link> 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");
+ }
+ }
+
+ 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;
+ }
+
+}
+
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIMacro.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIMacro.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIMacro.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIMacro.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,35 @@
+package org.jboss.seam.wiki.core.wikitext.renderer.jsf;
+
+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><wiki:macro></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;
+ }
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIMacro.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIWikiFormattedText.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/UIWikiFormattedText.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIWikiFormattedText.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIWikiFormattedText.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,296 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.wiki.core.wikitext.renderer.jsf;
+
+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.model.WikiFile;
+import org.jboss.seam.wiki.core.model.WikiUploadImage;
+import org.jboss.seam.wiki.core.model.WikiTextMacro;
+import org.jboss.seam.wiki.core.wikitext.renderer.DefaultWikiTextRenderer;
+import org.jboss.seam.wiki.util.WikiUtil;
+import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
+import org.jboss.seam.wiki.core.wikitext.editor.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.renderer.WikiTextRenderer;
+
+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.
+ *
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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"));
+
+ // TODO: Externalize this to separate class, extensible
+ // 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) + "&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) + "&thumbnail=true&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);
+ }
+
+}
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/UIWikiFormattedText.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Copied: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/WikiFormattedTextHandler.java (from rev 8330, trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiFormattedTextHandler.java)
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/WikiFormattedTextHandler.java (rev 0)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/WikiFormattedTextHandler.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.core.wikitext.renderer.jsf;
+
+import antlr.ANTLRException;
+import antlr.RecognitionException;
+import com.sun.facelets.FaceletContext;
+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 org.jboss.seam.log.Log;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiTextParser;
+
+import javax.el.ELException;
+import javax.faces.FacesException;
+import javax.faces.component.UIComponent;
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * 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 {
+
+ 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();
+ }
+
+ 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);
+
+ // This is a special flag that disables/enables caching of ValueExpressions inside macro templates,
+ // see the MacroIncludeTextRenderer for an explanation...
+ boolean enableTransientMacros =
+ (getAttribute(UIWikiFormattedText.ATTR_ENABLE_TRANSIENT_MACROS) != null &&
+ getAttribute(UIWikiFormattedText.ATTR_ENABLE_TRANSIENT_MACROS).getBoolean(ctx));
+
+ // We use a renderer to implement the callbacks from the parsing and to create the components in the tree
+ parser.setRenderer(
+ new MacroIncludeTextRenderer(wikiFormattedTextComponent, ctx, enableTransientMacros)
+ );
+
+ 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);
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
Property changes on: trunk/examples/wiki/src/main/org/jboss/seam/wiki/core/wikitext/renderer/jsf/WikiFormattedTextHandler.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/preferences/metamodel/PreferenceEntity.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/preferences/metamodel/PreferenceEntity.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/preferences/metamodel/PreferenceEntity.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -195,7 +195,6 @@
*/
public class Property implements Comparable, Serializable {
- private Field field;
private String fieldName;
private Class fieldType;
private String description;
@@ -207,7 +206,6 @@
public Property(String fieldName, Class fieldType, String description,
PreferenceVisibility[] visibility,
String editorIncludeName, String templateComponentName, String mappedTo) {
- this.field = Reflections.getField(getClazz(), fieldName);
this.fieldName = fieldName;
this.fieldType = fieldType;
this.description = description;
@@ -218,7 +216,7 @@
}
public Field getField() {
- return field;
+ return Reflections.getField(getClazz(), fieldName);
}
public String getOwningEntityName() {
@@ -266,12 +264,13 @@
}
public void write(Object preferenceEntityInstance, Object value) throws Exception {
+ Field field = getField();
field.setAccessible(true);
Reflections.set(field, preferenceEntityInstance, value);
}
public boolean isNullable() {
- return !field.isAnnotationPresent(NotNull.class);
+ return !getField().isAnnotationPresent(NotNull.class);
}
public InvalidValue[] validate(Object value) {
Modified: trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java
===================================================================
--- trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/main/org/jboss/seam/wiki/util/WikiUtil.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -295,12 +295,35 @@
return spaces.toString();
}
+ public static Date toDate(Long time) {
+ return new Date(time);
+ }
+
+ public static String getTimeDifferenceToCurrent(Date d) {
+ return getTimeDifference(new Date(), d);
+ }
+
+ public static String getTimeDifference(Date a, Date b) {
+ long time = a.getTime() > b.getTime() ? a.getTime() - b.getTime() : b.getTime() - a.getTime();
+ int seconds = (int)((time/1000) % 60);
+ int minutes = (int)((time/60000) % 60);
+ int hours = (int)((time/3600000) % 24);
+ String secondsStr = (seconds<10 ? "0" : "")+seconds;
+ String minutesStr = (minutes<10 ? "0" : "")+minutes;
+ String hoursStr = (hours<10 ? "0" : "")+hours;
+ return hoursStr + ":" + minutesStr + ":" + secondsStr;
+ }
+
public static String formatDate(Date date) {
// TODO: Exceptional date formatting here...
SimpleDateFormat fmt = new SimpleDateFormat("MMM dd, yyyy HH:mm");
return fmt.format(date);
}
+ public static Date currentDate() {
+ return new Date();
+ }
+
public static String attachSignature(String wikiText, String sig) {
StringBuilder builder = new StringBuilder();
builder.append(wikiText).append("\n\n-- ").append(sig);
@@ -312,12 +335,8 @@
!(user.getUsername().equals(User.ADMIN_USERNAME) || user.getUsername().equals(User.GUEST_USERNAME));
}
- /**
- * Used for conditional rendering of JSF messages, again, inflexible EL can't take value bindings with arguments
- * or support simple String concat...
- */
- public static boolean hasMessage(String namingContainer, String componentId) {
- return FacesContext.getCurrentInstance().getMessages(namingContainer.replaceAll("\\\\", "") + ":" + componentId).hasNext();
+ public static boolean isGuestOrAdminUsername(String username) {
+ return User.ADMIN_USERNAME.equals(username) || User.GUEST_USERNAME.equals(username);
}
/**
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirMenu.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirMenu.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirMenu.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -32,18 +32,15 @@
@In
WikiDirectory currentDirectory;
- @In
- WikiNodeDAO wikiNodeDAO;
-
public NestedSetNodeWrapper<WikiDirectory> getRoot(WikiPluginMacro macro) {
// We cache the result in the macro, so that when the getter is called over and over during rendering, we have it
if (macro.getAttributes().get(MACRO_ATTR_ROOT) == null) {
NestedSetNodeWrapper<WikiDirectory> root;
DirMenuPreferences prefs = Preferences.instance().get(DirMenuPreferences.class, macro);
if (prefs.getOnlyMenuItems() != null && prefs.getOnlyMenuItems()) {
- root = wikiNodeDAO.findMenuItemTree(currentDirectory, 3l, 3l, false);
+ root = WikiNodeDAO.instance().findMenuItemTree(currentDirectory, 3l, 3l, false);
} else {
- root = wikiNodeDAO.findWikiDirectoryTree(currentDirectory, 3l, 3l, false);
+ root = WikiNodeDAO.instance().findWikiDirectoryTree(currentDirectory, 3l, 3l, false);
}
macro.getAttributes().put(MACRO_ATTR_ROOT, root);
}
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirTocQuery.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirTocQuery.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DirTocQuery.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -14,7 +14,7 @@
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.wiki.core.dao.WikiNodeDAO;
-import org.jboss.seam.wiki.core.engine.WikiLinkResolver;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLinkResolver;
import org.jboss.seam.wiki.core.model.WikiDirectory;
import org.jboss.seam.wiki.core.model.WikiDocument;
import org.jboss.seam.wiki.core.nestedset.query.NestedSetNodeWrapper;
@@ -44,10 +44,6 @@
@In
WikiDirectory currentDirectory;
- @In
- WikiNodeDAO wikiNodeDAO;
-
-
public NestedSetNodeWrapper<WikiDirectory> getTocRoot(WikiPluginMacro macro) {
NestedSetNodeWrapper<WikiDirectory> tocRoot =
@@ -58,13 +54,13 @@
if (prefs.getRootDocumentLink() != null) {
Long id = ((WikiLinkResolver)Component.getInstance("wikiLinkResolver"))
.resolveWikiDirectoryId(currentDirectory.getAreaNumber(), prefs.getRootDocumentLink());
- WikiDirectory foundDir = wikiNodeDAO.findWikiDirectory(id);
+ WikiDirectory foundDir = WikiNodeDAO.instance().findWikiDirectory(id);
if (foundDir != null)
currentDirectory = foundDir;
}
// Query the directory tree
- tocRoot = wikiNodeDAO.findWikiDirectoryTree(currentDirectory);
+ tocRoot = WikiNodeDAO.instance().findWikiDirectoryTree(currentDirectory);
Set<Long> directoryIds = new HashSet<Long>(tocRoot.getFlatTree().keySet());
if (prefs.getShowRootDocuments() != null && prefs.getShowRootDocuments()) {
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DocPager.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DocPager.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/DocPager.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -27,15 +27,12 @@
public static final String MACRO_ATTR_PAGER_NEXT = "docPagerNext";
@In
- WikiNodeDAO wikiNodeDAO;
-
- @In
WikiDocument currentDocument;
public WikiDocument getPrevious(WikiPluginMacro macro) {
WikiDocument previous = (WikiDocument) macro.getAttributes().get(MACRO_ATTR_PAGER_PREVIOUS);
if (previous == null) {
- previous = wikiNodeDAO.findSiblingWikiDocumentInDirectory(currentDocument, getSortingProperty(macro), true);
+ previous = WikiNodeDAO.instance().findSiblingWikiDocumentInDirectory(currentDocument, getSortingProperty(macro), true);
macro.getAttributes().put(MACRO_ATTR_PAGER_PREVIOUS, previous);
}
return previous;
@@ -44,7 +41,7 @@
public WikiDocument getNext(WikiPluginMacro macro) {
WikiDocument next = (WikiDocument) macro.getAttributes().get(MACRO_ATTR_PAGER_NEXT);
if (next == null) {
- next = wikiNodeDAO.findSiblingWikiDocumentInDirectory(currentDocument, getSortingProperty(macro), false);
+ next = WikiNodeDAO.instance().findSiblingWikiDocumentInDirectory(currentDocument, getSortingProperty(macro), false);
macro.getAttributes().put(MACRO_ATTR_PAGER_NEXT, next);
}
return next;
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/LastModifiedDocuments.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/LastModifiedDocuments.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/basic/LastModifiedDocuments.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -21,12 +21,9 @@
@Scope(ScopeType.PAGE)
public class LastModifiedDocuments implements Serializable {
- @In
- WikiNodeDAO wikiNodeDAO;
-
public List<WikiDocument> getListOfDocuments(LastModifiedDocumentsPreferences prefs) {
return
- wikiNodeDAO.findWikiDocuments(
+ WikiNodeDAO.instance().findWikiDocuments(
Long.valueOf(prefs.getNumberOfItems()).intValue(),
WikiNode.SortableProperty.lastModifiedOn,
false
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/faqBrowser/templates/faqQuestionForm.xhtml
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/faqBrowser/templates/faqQuestionForm.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/faqBrowser/templates/faqQuestionForm.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -29,7 +29,6 @@
<ui:include src="/includes/wikiTextEditor.xhtml">
<ui:param name="textEditorId" value="faqQuestion"/>
- <ui:param name="textPreviewId" value="faqQuestionPreview"/>
<ui:param name="namingContainer" value="faqBrowserPlugin\\\\:faqQuestionForm"/>
<ui:param name="label" value="#{messages['fb.faqBrowser.label.QuestionText']}"/>
<ui:param name="valueBinding" value="#{faqQuestionHome.formContent}"/>
@@ -41,7 +40,7 @@
<s:div styleClass="marginLeft">
<ui:include src="/includes/wikiTextPreview.xhtml">
- <ui:param name="textPreviewId" value="faqQuestionPreview"/>
+ <ui:param name="textEditorId" value="faqQuestion"/>
<ui:param name="valueBinding" value="#{faqQuestionHome.instance.content}"/>
<ui:param name="baseDocument" value="#{faqQuestionHome.instance}"/>
<ui:param name="baseDirectory" value="#{currentDirectory}"/>
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumQuery.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumQuery.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ForumQuery.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -8,8 +8,8 @@
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.log.Log;
import org.jboss.seam.wiki.core.action.Pager;
-import org.jboss.seam.wiki.core.engine.WikiLink;
-import org.jboss.seam.wiki.core.engine.WikiLinkResolver;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLink;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiLinkResolver;
import org.jboss.seam.wiki.core.model.User;
import org.jboss.seam.wiki.core.model.WikiDirectory;
import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ReplyHome.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ReplyHome.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/ReplyHome.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -7,6 +7,7 @@
import org.jboss.seam.international.StatusMessages;
import org.jboss.seam.security.Identity;
import org.jboss.seam.wiki.core.action.CommentHome;
+import org.jboss.seam.wiki.core.wikitext.editor.WikiTextValidator;
import org.jboss.seam.wiki.core.model.WikiComment;
import org.jboss.seam.wiki.core.model.WikiNode;
import org.jboss.seam.wiki.core.ui.WikiRedirect;
@@ -100,8 +101,23 @@
return "forumReplyFeedEntryManager";
}
- protected String getTextAreaId() {
- return "replyTextArea";
+ @Override
+ protected WikiTextValidator.ValidationCommand[] getPersistValidationCommands() {
+ return new WikiTextValidator.ValidationCommand[] {
+ new WikiTextValidator.ValidationCommand() {
+ public String getKey() {
+ return "reply";
+ }
+
+ public String getWikiTextValue() {
+ return getInstance().getContent();
+ }
+
+ public boolean getWikiTextRequired() {
+ return true;
+ }
+ }
+ };
}
/* -------------------------- Messages ------------------------------ */
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/TopicHome.java
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/TopicHome.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/TopicHome.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -8,19 +8,16 @@
import org.jboss.seam.faces.Renderer;
import org.jboss.seam.international.StatusMessages;
import org.jboss.seam.wiki.core.action.DocumentHome;
+import org.jboss.seam.wiki.core.wikitext.editor.WikiTextValidator;
import org.jboss.seam.wiki.core.model.WikiDirectory;
import org.jboss.seam.wiki.core.model.WikiDocument;
import org.jboss.seam.wiki.core.model.WikiTextMacro;
import org.jboss.seam.wiki.core.ui.WikiRedirect;
import org.jboss.seam.wiki.core.plugin.PluginRegistry;
-import org.jboss.seam.wiki.core.engine.WikiFormattedTextValidator;
import org.jboss.seam.wiki.preferences.Preferences;
-import static org.jboss.seam.international.StatusMessage.Severity.WARN;
import static org.jboss.seam.international.StatusMessage.Severity.INFO;
-import javax.faces.validator.ValidatorException;
-
@Name("topicHome")
@Scope(ScopeType.CONVERSATION)
public class TopicHome extends DocumentHome {
@@ -68,23 +65,6 @@
}
@Override
- protected boolean preparePersist() {
- // TODO: Why here again?
- WikiFormattedTextValidator validator = new WikiFormattedTextValidator();
- try {
- validator.validate(null, null, getInstance().getContent());
- } catch (ValidatorException e) {
- StatusMessages.instance().addToControl(
- "topicTextArea",
- WARN,
- e.getFacesMessage().getSummary()
- );
- return false;
- }
- return super.preparePersist();
- }
-
- @Override
protected boolean beforePersist() {
// TODO: Use macro parameters for "sticky" and "notify" options instead of additional macros
if (isSticky()) {
@@ -136,6 +116,33 @@
return null; // Prevent navigation
}
+ @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 "topic";
+ }
+
+ public String getWikiTextValue() {
+ return getInstance().getContent();
+ }
+
+ public boolean getWikiTextRequired() {
+ return true;
+ }
+ }
+ };
+ }
+
/* -------------------------- Messages ------------------------------ */
protected void createdMessage() {
Modified: 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/lastTopicPost.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/lastTopicPost.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -10,7 +10,7 @@
<s:div>
<h:outputLink value="#{link}" tabindex="1">
- <h:outputText value="#{wiki:truncateString(name, 15, '...')}"/>
+ <h:outputText value="#{wiki:truncateString(name, 25, '...')}"/>
<h:graphicImage styleClass="topicGotoIcon" value="#{currentMacro.requestImagePath}/icon.posting_goto.gif" width="18" height="9"/>
</h:outputLink>
</s:div>
Modified: 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/replyForm.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/replyForm.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -76,7 +76,6 @@
<a:region>
<ui:include src="/includes/wikiTextEditor.xhtml">
<ui:param name="textEditorId" value="reply"/>
- <ui:param name="textPreviewId" value="replyPreview"/>
<ui:param name="namingContainer" value="forumRepliesPlugin\\\\:replyForm"/>
<ui:param name="label" value="#{messages['forum.label.replyForm.Message']}"/>
<ui:param name="valueBinding" value="#{replyHome.instance.content}"/>
@@ -87,7 +86,7 @@
</ui:include>
<ui:include src="/includes/wikiTextPreview.xhtml">
- <ui:param name="textPreviewId" value="replyPreview"/>
+ <ui:param name="textEditorId" value="reply"/>
<ui:param name="valueBinding" value="#{replyHome.instance.content}"/>
<ui:param name="baseDocument" value="#{currentDocument}"/>
<ui:param name="baseDirectory" value="#{currentDocument.parent}"/>
Modified: trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/topicForm.xhtml
===================================================================
--- trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/topicForm.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/plugin/org/jboss/seam/wiki/plugin/forum/templates/topicForm.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -30,7 +30,6 @@
<a:region>
<ui:include src="/includes/wikiTextEditor.xhtml">
<ui:param name="textEditorId" value="topic"/>
- <ui:param name="textPreviewId" value="topicPreview"/>
<ui:param name="namingContainer" value="forumTopicsPlugin\\\\:topicForm"/>
<ui:param name="label" value="#{messages['forum.label.Message']}"/>
<ui:param name="valueBinding" value="#{topicHome.formContent}"/>
@@ -42,7 +41,7 @@
<s:div styleClass="marginLeft">
<ui:include src="/includes/wikiTextPreview.xhtml">
- <ui:param name="textPreviewId" value="topicPreview"/>
+ <ui:param name="textEditorId" value="topic"/>
<ui:param name="valueBinding" value="#{topicHome.instance.content}"/>
<ui:param name="baseDocument" value="#{topicHome.instance}"/>
<ui:param name="baseDirectory" value="#{currentDirectory}"/>
Modified: trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/editing/Linking.java
===================================================================
--- trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/editing/Linking.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/editing/Linking.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -8,9 +8,9 @@
import org.dbunit.operation.DatabaseOperation;
import org.jboss.seam.wiki.core.action.DocumentHome;
-import org.jboss.seam.wiki.core.engine.WikiLink;
-import org.jboss.seam.wiki.core.engine.WikiLinkResolver;
-import org.jboss.seam.wiki.core.engine.WikiTextRenderer;
+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.renderer.WikiTextRenderer;
import org.jboss.seam.wiki.core.model.WikiDocument;
import org.jboss.seam.wiki.core.model.WikiUpload;
import org.jboss.seam.wiki.test.util.DBUnitSeamTest;
Modified: trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/preferences/InstancePreferencesTests.java
===================================================================
--- trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/preferences/InstancePreferencesTests.java 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/src/test/org/jboss/seam/wiki/test/preferences/InstancePreferencesTests.java 2008-06-07 00:25:03 UTC (rev 8348)
@@ -9,11 +9,11 @@
import org.dbunit.operation.DatabaseOperation;
import org.jboss.seam.core.Conversation;
import org.jboss.seam.wiki.core.action.DocumentHome;
-import org.jboss.seam.wiki.core.engine.WikiTextParser;
+import org.jboss.seam.wiki.core.wikitext.engine.WikiTextParser;
import org.jboss.seam.wiki.core.model.WikiTextMacro;
import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
import org.jboss.seam.wiki.core.plugin.PluginRegistry;
-import org.jboss.seam.wiki.core.renderer.NullWikiTextRenderer;
+import org.jboss.seam.wiki.core.wikitext.renderer.NullWikiTextRenderer;
import org.jboss.seam.wiki.plugin.basic.LastModifiedDocumentsPreferences;
import org.jboss.seam.wiki.preferences.Preferences;
import org.jboss.seam.wiki.test.util.DBUnitSeamTest;
Modified: trunk/examples/wiki/view/adminHome_d.xhtml
===================================================================
--- trunk/examples/wiki/view/adminHome_d.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/adminHome_d.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -93,6 +93,7 @@
<div id="systemStats">
<div class="formFields" style="padding: 20px;">
+
<a:region>
<a:jsFunction name="reloadIndexStatistics"
@@ -152,6 +153,14 @@
</h:dataTable>
</a:region>
+
+ <br/>
+ <br/>
+
+ <a:region>
+ <ui:include src="includes/admin/sessionManager.xhtml"/>
+ </a:region>
+
</div>
</div>
Modified: trunk/examples/wiki/view/docEdit_d.xhtml
===================================================================
--- trunk/examples/wiki/view/docEdit_d.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/docEdit_d.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -174,22 +174,23 @@
<ui:include src="includes/wikiTextEditor.xhtml">
<ui:param name="textEditorId" value="content"/>
- <ui:param name="textPreviewId" value="#{documentHome.enabledPreview ? 'contentPreview' : ''}"/>
+ <ui:param name="valueBinding" value="#{documentHome.formContent}"/>
+ <ui:param name="tabId" value="docContentTab"/>
<ui:param name="namingContainer" value="docEditForm"/>
<ui:param name="label" value="#{messages['lacewiki.label.docEdit.Content']}"/>
<ui:param name="textEditorColumns" value="#{preferences.get('DocEditor').regularEditAreaColumns}"/>
<ui:param name="textEditorRows" value="#{preferences.get('DocEditor').regularEditAreaRows}"/>
- <ui:param name="valueBinding" value="#{documentHome.formContent}"/>
<ui:param name="valueMaxLength" value="32767"/>
<ui:param name="valueRequired" value="true"/>
</ui:include>
-
+<!--
<s:div styleClass="entry" id="previewSwitchDiv">
<h:message for="previewSwitch"/>
<div class="label"> </div>
<div class="input">
- <h:selectBooleanCheckbox styleClass="ajaxSupport" value="#{documentHome.enabledPreview}" tabindex="1" id="previewSwitch">
- <a:support status="globalStatus"
+ <h:selectBooleanCheckbox styleClass="ajaxSupport" value="#{wikiTextPreview.isPreviewEnabled('content')}" tabindex="1" id="previewSwitch">
+ <a:support action="#{documentHome.wikiTextValidator.validate('content', documentHome.formContent, true)}"
+ status="globalStatus"
event="onchange"
oncomplete="onAjaxRequestComplete()"
reRender="contentPreview, docEditForm:contentTextEditor, pluginSwitch"/>
@@ -209,7 +210,7 @@
</div>
</s:div>
</s:div>
-
+-->
</div>
</a:region>
@@ -361,7 +362,7 @@
<br/>
<s:div id="contentPreview">
- <c:if test="#{documentHome.enabledPreview}">
+ <c:if test="#{wikiTextPreview.isPreviewEnabled('content') and wikiTextValidator.isValid('content')}">
<s:div id="documentDisplayContainer"
styleClass="box">
<s:fragment rendered="#{documentHome.instance.macroPresent('clearBackground')}">
@@ -391,10 +392,13 @@
</s:div>
</s:div>
- <s:div rendered="#{documentHome.enabledPreview}">
+ <s:div rendered="#{wikiTextPreview.isPreviewEnabled('content')}">
<ui:include src="includes/attachmentDisplay.xhtml"/>
</s:div>
</c:if>
+ <c:if test="#{wikiTextPreview.isPreviewEnabled('content') and not wikiTextValidator.isValid('content')}">
+ <h:outputText value="#{messages['lacewiki.msg.wikiTextValidator.InvalidWikiText']}"/>
+ </c:if>
</s:div>
</ui:define>
Added: trunk/examples/wiki/view/includes/admin/sessionManager.xhtml
===================================================================
--- trunk/examples/wiki/view/includes/admin/sessionManager.xhtml (rev 0)
+++ trunk/examples/wiki/view/includes/admin/sessionManager.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,175 @@
+<s:fragment
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:wiki="http://jboss.com/products/seam/wiki"
+ xmlns:a="https://ajax4jsf.dev.java.net/ajax"
+ xmlns:c="http://java.sun.com/jstl/core"
+ xmlns:rich="http://richfaces.ajax4jsf.org/rich"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+<script type="text/javascript">
+
+ function switchSessionControl() {
+ var sessionControlsEnabled = false
+ jQuery(".wikiSessionSelect").each(
+ function checkSelected() {
+ if (jQuery(this).attr("checked")) {
+ sessionControlsEnabled = true;
+ }
+ }
+ );
+ if (sessionControlsEnabled) {
+ jQuery(".sessionControl").show();
+ } else {
+ jQuery(".sessionControl").hide();
+ }
+ }
+</script>
+
+<s:div id="sessionManager">
+
+ <h:panelGrid columns="3" style="width:100%;"
+ columnClasses="twentyPercentColumn alignLeft,
+ twentyPercentColumn alignLeft,
+ defaultColumn alignRight">
+
+ <h:panelGroup styleClass="undecoratedLink">
+ <h:outputText value="Select: "/>
+
+ <h:outputLink value="javascript:selectCheckBoxes('wikiSessionSelect'); switchSessionControl();">
+ <h:outputText value="All"/>
+ </h:outputLink>
+ <h:outputText value=" | "/>
+ <h:outputLink value="javascript:selectCheckBoxes('wikiSessionSelectGuest'); switchSessionControl();">
+ <h:outputText value="Guests"/>
+ </h:outputLink>
+ <h:outputText value=" | "/>
+ <h:outputLink value="javascript:selectCheckBoxes('wikiSessionSelectRegularUser'); switchSessionControl();">
+ <h:outputText value="Regular Users"/>
+ </h:outputLink>
+ <h:outputText value=" | "/>
+ <h:outputLink value="javascript:deselectCheckBoxes('wikiSessionSelect'); switchSessionControl();">
+ <h:outputText value="None"/>
+ </h:outputLink>
+
+ </h:panelGroup>
+
+ <h:panelGroup styleClass="sessionControl" style="display:none;">
+
+ <a:commandLink action="#{wikiHttpSessionManager.calculateSelectedSessionsSize}"
+ reRender="sessionManager, messageBoxContainer"
+ status="globalStatus"
+ oncomplete="onAjaxRequestComplete()"
+ eventsQueue="ajaxEventQueue"
+ styleClass="buttonNonpersistent">
+ <h:outputText styleClass="buttonLabel" value="Calculate Size"/>
+ </a:commandLink>
+
+ <!--
+ <a:commandLink action="#{wikiHttpSessionManager.invalidateSelectedSessions}"
+ reRender="sessionManager, messageBoxContainer"
+ status="globalStatus"
+ oncomplete="onAjaxRequestComplete()"
+ eventsQueue="ajaxEventQueue"
+ styleClass="button">
+ <h:outputText styleClass="buttonLabel" value="Invalidate"/>
+ </a:commandLink>
+ -->
+
+ </h:panelGroup>
+
+ <h:panelGroup>
+ <h:outputText value="Active sessions: #{wikiHttpSessionManager.sessions.size()}"/>
+
+ <a:commandLink action="#{wikiHttpSessionManager.refresh()}"
+ reRender="sessionManager, messageBoxContainer"
+ status="globalStatus"
+ oncomplete="onAjaxRequestComplete()"
+ eventsQueue="ajaxEventQueue"
+ styleClass="buttonNonpersistent">
+ <h:outputText styleClass="buttonLabel" value="Refresh"/>
+ </a:commandLink>
+ </h:panelGroup>
+
+ </h:panelGrid>
+
+ <h:dataTable value="#{wikiHttpSessionManager.sessions}" var="s"
+ styleClass="datatable topLeftBottomBorder"
+ headerClass="regularHeader rightBorder smallFont"
+ columnClasses="onePercentColumn rightBorder alignLeft,
+ defaultColumn rightBorder alignCenter,
+ twentyPercentColumn rightBorder alignCenter,
+ twentyPercentColumn rightBorder alignCenter,
+ tenPercentColumn rightBorder alignCenter
+ tenPercentColumn rightBorder alignCenter
+ tenPercentColumn rightBorder alignCenter"
+ rowClasses="rowOdd,rowEven"
+ cellpadding="0" cellspacing="0" border="0">
+
+ <h:column>
+ <h:selectBooleanCheckbox value="#{wikiHttpSessionManager.selectedSessions[s.id]}"
+ styleClass="wikiSessionSelect
+ #{wikiHttpSessionManager.getUsername(s.id) == 'Guest'
+ ? 'wikiSessionSelectGuest'
+ : 'wikiSessionSelectRegularUser'}"
+ onchange="switchSessionControl()"/>
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="User"/>
+ </f:facet>
+ <h:outputText value="#{wikiHttpSessionManager.getUsername(s.id)}"/>
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Created"/>
+ </f:facet>
+ <h:outputText value="#{wiki:toDate(s.creationTime)}">
+ <f:convertDateTime pattern="dd. MMM yyyy, HH:mm:ss" timeZone="#{preferences.get('Wiki').timeZone}"/>
+ </h:outputText>
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Last Access"/>
+ </f:facet>
+ <h:outputText value="#{wiki:toDate(s.lastAccessedTime)}">
+ <f:convertDateTime pattern="dd. MMM yyyy, HH:mm:ss" timeZone="#{preferences.get('Wiki').timeZone}"/>
+ </h:outputText>
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Idle"/>
+ </f:facet>
+ <h:outputText value="#{wiki:getTimeDifferenceToCurrent(wiki:toDate(s.lastAccessedTime))}"/>
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Expires"/>
+ </f:facet>
+ <h:outputText value="#{wiki:getTimeDifferenceToCurrent(wiki:toDate(s.lastAccessedTime + s.maxInactiveInterval*1000))}"/>
+ <h:outputText value=" (EXPIRED!) "
+ rendered="#{wiki:toDate(s.lastAccessedTime + s.maxInactiveInterval*1000).time < wiki:currentDate().time}"/>
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Size"/>
+ </f:facet>
+ <h:outputText rendered="#{not empty wikiHttpSessionManager.sessionsSize[s.id]}"
+ value="#{wiki:displayFilesize(wikiHttpSessionManager.sessionsSize[s.id])}"/>
+ <h:outputText rendered="#{empty wikiHttpSessionManager.sessionsSize[s.id]}"
+ value="-"/>
+ </h:column>
+
+ </h:dataTable>
+
+</s:div>
+
+</s:fragment>
\ No newline at end of file
Modified: trunk/examples/wiki/view/includes/commentForm.xhtml
===================================================================
--- trunk/examples/wiki/view/includes/commentForm.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/includes/commentForm.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -85,18 +85,17 @@
<a:region>
<ui:include src="wikiTextEditor.xhtml">
<ui:param name="textEditorId" value="comment"/>
- <ui:param name="textPreviewId" value="commentPreview"/>
+ <ui:param name="valueBinding" value="#{commentHome.instance.content}"/>
<ui:param name="namingContainer" value="commentForm"/>
<ui:param name="label" value="#{messages['lacewiki.label.commentForm.Comment']}"/>
- <ui:param name="valueBinding" value="#{commentHome.instance.content}"/>
- <ui:param name="valueMaxLength" value="32767"/>
- <ui:param name="valueRequired" value="true"/>
<ui:param name="textEditorColumns" value="#{commentHome.instance.ownedByRegularUser ? '60' : '48'}"/>
<ui:param name="textEditorRows" value="10"/>
+ <ui:param name="valueMaxLength" value="32767"/>
+ <ui:param name="valueRequired" value="true"/>
</ui:include>
<ui:include src="wikiTextPreview.xhtml">
- <ui:param name="textPreviewId" value="commentPreview"/>
+ <ui:param name="textEditorId" value="comment"/>
<ui:param name="valueBinding" value="#{commentHome.instance.content}"/>
<ui:param name="baseDocument" value="#{currentDocument}"/>
<ui:param name="baseDirectory" value="#{currentDocument.parent}"/>
Added: trunk/examples/wiki/view/includes/onlineUsers.xhtml
===================================================================
--- trunk/examples/wiki/view/includes/onlineUsers.xhtml (rev 0)
+++ trunk/examples/wiki/view/includes/onlineUsers.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -0,0 +1,33 @@
+<s:fragment
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib">
+
+ <h:panelGrid styleClass="onlineUsersPanel" columns="4"
+ cellpadding="0" cellspacing="0" border="0">
+
+ <h:outputText styleClass="onlineLabel" value="Online: "/>
+
+ <s:fragment rendered="#{wikiHttpSessionManager.numberOfOnlineMembers > 0}">
+ <s:span styleClass="onlineValue">
+ <h:outputText value="#{wikiHttpSessionManager.numberOfOnlineMembers}"/>
+ <h:outputText value=" #{wikiHttpSessionManager.numberOfOnlineMembers > 1 ? 'Members' : 'Member'}"/>
+ </s:span>
+ </s:fragment>
+
+ <h:outputText styleClass="onlineSeparator" value=" | "
+ rendered="#{wikiHttpSessionManager.numberOfOnlineMembers > 0 and
+ wikiHttpSessionManager.numberOfOnlineGuests > 0}"/>
+
+ <s:fragment rendered="#{wikiHttpSessionManager.numberOfOnlineGuests > 0}">
+ <s:span styleClass="onlineValue">
+ <h:outputText value="#{wikiHttpSessionManager.numberOfOnlineGuests}"/>
+ <h:outputText value=" #{wikiHttpSessionManager.numberOfOnlineGuests> 1 ? 'Guests' : 'Guest'}"/>
+ </s:span>
+ </s:fragment>
+
+ </h:panelGrid>
+
+</s:fragment>
\ No newline at end of file
Modified: trunk/examples/wiki/view/includes/wikiTextEditor.xhtml
===================================================================
--- trunk/examples/wiki/view/includes/wikiTextEditor.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/includes/wikiTextEditor.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -31,33 +31,33 @@
</script>
<s:div id="#{textEditorId}MessageLabel"
- styleClass="#{wiki:hasMessage(namingContainer, wiki:concat(textEditorId, 'TextArea'))?'label errorEntry':'label'}">
+ styleClass="#{not wikiTextValidator.isValid(textEditorId) ? 'label errorEntry' : 'label'}">
<s:div>
<h:outputText value="#{label}:"/>
- <s:fragment rendered="#{not empty textPreviewId}">
+ <s:fragment rendered="#{wikiTextPreview.isPreviewEnabled(textEditorId)}">
<br/>
<h:outputText style="white-space:nowrap;"
value="(#{valueMaxLength - valueBinding.length()} #{messages['lacewiki.label.wikiTextEditor.CharactersLeft']})"/>
</s:fragment>
</s:div>
- <s:div styleClass="errorMessage" rendered="#{wiki:hasMessage(namingContainer, wiki:concat(textEditorId, 'TextArea'))}">
+ <s:div styleClass="errorMessage" rendered="#{not wikiTextValidator.isValid(textEditorId)}">
<h:panelGrid columns="2" cellpadding="0" cellspacing="0" border="0">
<h:graphicImage value="#{imagePath}/attention.gif"
width="18" height="18"
styleClass="attentionImage"/>
- <s:span styleClass="attentionMessage"> <span id="#{textEditorId}MessageText"><h:message for="#{textEditorId}TextArea"/></span></s:span>
+ <s:span styleClass="attentionMessage"><span id="#{textEditorId}MessageText"><h:outputText value="#{messages[wikiTextValidator.getValidationFailureMessageBundleKey(textEditorId)]}"/></span></s:span>
</h:panelGrid>
</s:div>
- <s:fragment rendered="#{!empty tabId}">
- <s:span rendered="#{wiki:hasMessage(namingContainer, wiki:concat(textEditorId, 'TextArea'))}">
+ <s:fragment rendered="#{not empty tabId}">
+ <s:span rendered="#{not wikiTextValidator.isValid(textEditorId)}">
<script type="text/javascript">jQuery(function() {
formTabRaiseError("#{tabId}", "#{textEditorId}TextArea", '#{label}: ' + jQuery("##{textEditorId}MessageText").html());
});</script>
</s:span>
- <s:span rendered="#{!wiki:hasMessage(namingContainer, wiki:concat(textEditorId, 'TextArea'))}">
+ <s:span rendered="#{wikiTextValidator.isValid(textEditorId)}">
<script type="text/javascript">jQuery(function() {
formTabClearError("#{tabId}", "#{textEditorId}TextArea");
});</script>
@@ -68,100 +68,138 @@
<div class="input">
- <s:validateAll>
+ <h:panelGrid columns="1" cellpadding="0" cellspacing="0" border="0">
- <h:panelGrid columns="1" cellpadding="0" cellspacing="0" border="0">
+ <h:panelGrid id="#{textEditorId}Controls" columns="4" cellpadding="0" cellspacing="0" border="0">
- <h:panelGrid columns="3" cellpadding="0" cellspacing="0" border="0">
+ <s:fragment>
+ <select id="#{textEditorId}Formatter"
+ onchange="formatText(
+ jQuery('##{namingContainer}\\:#{textEditorId}TextArea')[0],
+ jQuery('##{textEditorId}Formatter')[0].options[jQuery('##{textEditorId}Formatter')[0].selectedIndex].value
+ );
+ #{textEditorId}RefreshPreview();
+ jQuery('##{textEditorId}Formatter')[0].options[0].selected = true;">
+ <option value="">#{messages['lacewiki.msg.wikiTextEditor.FormatSelection']}</option>
+ <option value="">#{messages['lacewiki.msg.wikiTextEditor.FormatInline']}</option>
+ <option value="|{i}|">#{messages['lacewiki.msg.wikiTextEditor.FormatMonospace']}</option>
+ <option value="*{i}*">#{messages['lacewiki.msg.wikiTextEditor.FormatEmphasis']}</option>
+ <option value="_{i}_">#{messages['lacewiki.msg.wikiTextEditor.FormatUnderline']}</option>
+ <option value="~{i}~">#{messages['lacewiki.msg.wikiTextEditor.FormatStrikeout']}</option>
+ <option value="^{i}^">#{messages['lacewiki.msg.wikiTextEditor.FormatSuperscript']}</option>
+ <option value=""{i}"">#{messages['lacewiki.msg.wikiTextEditor.FormatQuote']}</option>
+ <option value="[My Link=>{i}]">#{messages['lacewiki.msg.wikiTextEditor.FormatLink']}</option>
+ <option value="">#{messages['lacewiki.msg.wikiTextEditor.FormatBlock']}</option>
+ <option value="`{b}`">#{messages['lacewiki.msg.wikiTextEditor.FormatCodeBlock']}</option>
+ <option value=""{b}"">#{messages['lacewiki.msg.wikiTextEditor.FormatQuoteBlock']}</option>
+ <option value="= {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatUnorderedList']}</option>
+ <option value="# {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatOrderedList']}</option>
+ <option value="+ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline1']}</option>
+ <option value="++ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline2']}</option>
+ <option value="+++ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline3']}</option>
+ <option value="++++ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline4']}</option>
+ </select>
- <s:fragment>
- <select id="#{textEditorId}Formatter"
- onchange="formatText(
- jQuery('##{namingContainer}\\:#{textEditorId}TextArea')[0],
- jQuery('##{textEditorId}Formatter')[0].options[jQuery('##{textEditorId}Formatter')[0].selectedIndex].value
- );
- #{textEditorId}RefreshPreview();
- jQuery('##{textEditorId}Formatter')[0].options[0].selected = true;">
- <option value="">#{messages['lacewiki.msg.wikiTextEditor.FormatSelection']}</option>
- <option value="">#{messages['lacewiki.msg.wikiTextEditor.FormatInline']}</option>
- <option value="|{i}|">#{messages['lacewiki.msg.wikiTextEditor.FormatMonospace']}</option>
- <option value="*{i}*">#{messages['lacewiki.msg.wikiTextEditor.FormatEmphasis']}</option>
- <option value="_{i}_">#{messages['lacewiki.msg.wikiTextEditor.FormatUnderline']}</option>
- <option value="~{i}~">#{messages['lacewiki.msg.wikiTextEditor.FormatStrikeout']}</option>
- <option value="^{i}^">#{messages['lacewiki.msg.wikiTextEditor.FormatSuperscript']}</option>
- <option value=""{i}"">#{messages['lacewiki.msg.wikiTextEditor.FormatQuote']}</option>
- <option value="[My Link=>{i}]">#{messages['lacewiki.msg.wikiTextEditor.FormatLink']}</option>
- <option value="">#{messages['lacewiki.msg.wikiTextEditor.FormatBlock']}</option>
- <option value="`{b}`">#{messages['lacewiki.msg.wikiTextEditor.FormatCodeBlock']}</option>
- <option value=""{b}"">#{messages['lacewiki.msg.wikiTextEditor.FormatQuoteBlock']}</option>
- <option value="= {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatUnorderedList']}</option>
- <option value="# {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatOrderedList']}</option>
- <option value="+ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline1']}</option>
- <option value="++ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline2']}</option>
- <option value="+++ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline3']}</option>
- <option value="++++ {b}">#{messages['lacewiki.msg.wikiTextEditor.FormatHeadline4']}</option>
- </select>
+ <a:jsFunction name="#{textEditorId}RefreshPreview" status="globalStatus"
+ action="#{wikiTextValidator.validate(textEditorId, valueBinding, valueRequired)}"
+ reRender="#{textEditorId}MessageLabel, #{textEditorId}Preview"/>
+ </s:fragment>
- <a:jsFunction name="#{textEditorId}RefreshPreview" status="globalStatus"
- reRender="#{textEditorId}MessageLabel, #{textPreviewId}"/>
- </s:fragment>
+ <ui:decorate template="helpPopupButton.xhtml">
+ <ui:param name="label" value="#{messages['lacewiki.button.help.Help']}"/>
+ <ui:param name="width" value="450"/>
+ <ui:param name="height" value="350"/>
+ <ui:param name="offsetId" value="#{namingContainer}\\\\:#{textEditorId}TextAreaDiv"/>
+ <ui:param name="helpDocument" value="Wiki Text Markup"/>
+ </ui:decorate>
- <ui:decorate template="helpPopupButton.xhtml">
- <ui:param name="label" value="#{messages['lacewiki.button.help.Help']}"/>
- <ui:param name="width" value="450"/>
- <ui:param name="height" value="350"/>
- <ui:param name="offsetId" value="#{namingContainer}\\\\:#{textEditorId}TextAreaDiv"/>
- <ui:param name="helpDocument" value="Wiki Text Markup"/>
- </ui:decorate>
+ <s:fragment>
- <s:fragment>
- <s:fragment rendered="#{not empty textPreviewId}">
- <h:outputLink value="javascript://no-op"
- tabindex="1" styleClass="buttonNonpersistent noWrapWhitespace"
- accesskey="#{messages['lacewiki.button.wikiTextEditor.UpdatePreview.accesskey']}"
- onclick="rememberCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea'); #{textEditorId}UpdatePreview(); return false;">
- <h:outputText styleClass="buttonLabel" escape="false" value="#{messages['lacewiki.button.wikiTextEditor.UpdatePreview']}"/>
- </h:outputLink>
+ <s:fragment rendered="#{not wikiTextPreview.isPreviewEnabled(textEditorId)}">
+ <h:outputLink value="javascript://no-op"
+ tabindex="1" styleClass="buttonNonpersistent noWrapWhitespace"
+ accesskey="#{messages['lacewiki.button.wikiTextEditor.Validate.accesskey']}"
+ onclick="rememberCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea'); #{textEditorId}Validate(); return false;">
+ <h:outputText styleClass="buttonLabel" escape="false" value="#{messages['lacewiki.button.wikiTextEditor.Validate']}"/>
+ </h:outputLink>
- <a:jsFunction name="#{textEditorId}UpdatePreview"
- action="#{wikiTextEditor.validate(textEditorId, valueBinding)}"
- status="globalStatus"
- reRender="#{textEditorId}MessageLabel, #{textPreviewId}"
- eventsQueue="ajaxEventQueue"
- oncomplete="onAjaxRequestComplete();setRememberedCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea');"/>
- </s:fragment>
+ <a:jsFunction name="#{textEditorId}Validate"
+ action="#{wikiTextValidator.validate(textEditorId, valueBinding, valueRequired)}"
+ reRender="#{textEditorId}MessageLabel, #{textEditorId}Preview"
+ status="globalStatus"
+ ignoreDupResponses="true"
+ eventsQueue="ajaxEventQueue"
+ oncomplete="onAjaxRequestComplete();
+ setRememberedCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea');"/>
+ </s:fragment>
+
+ </s:fragment>
+
+ <s:fragment>
+
+ <s:fragment rendered="#{not wikiTextPreview.isPreviewEnabled(textEditorId)}">
+ <h:outputLink value="javascript://no-op"
+ tabindex="1" styleClass="buttonNonpersistent noWrapWhitespace"
+ accesskey="#{messages['lacewiki.button.wikiTextEditor.EnablePreview.accesskey']}"
+ onclick="rememberCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea'); #{textEditorId}EnablePreview(); return false;">
+ <h:outputText styleClass="buttonLabel" escape="false" value="#{messages['lacewiki.button.wikiTextEditor.EnablePreview']}"/>
+ </h:outputLink>
+
+ <a:jsFunction name="#{textEditorId}EnablePreview"
+ action="#{wikiTextPreview.enablePreview(textEditorId, valueBinding, valueRequired)}"
+ status="globalStatus"
+ eventsQueue="ajaxEventQueue"
+ reRender="#{textEditorId}TextEditor, #{textEditorId}Preview"
+ oncomplete="onAjaxRequestComplete();setRememberedCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea');"/>
+
</s:fragment>
- </h:panelGrid>
+ <s:fragment rendered="#{wikiTextPreview.isPreviewEnabled(textEditorId)}">
+ <h:outputLink value="javascript://no-op"
+ tabindex="1" styleClass="buttonNonpersistent noWrapWhitespace"
+ accesskey="#{messages['lacewiki.button.wikiTextEditor.DisablePreview.accesskey']}"
+ onclick="rememberCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea'); #{textEditorId}DisablePreview(); return false;">
+ <h:outputText styleClass="buttonLabel" escape="false" value="#{messages['lacewiki.button.wikiTextEditor.DisablePreview']}"/>
+ </h:outputLink>
- <s:div id="#{textEditorId}TextAreaDiv" styleClass="textEditResizable">
+ <a:jsFunction name="#{textEditorId}DisablePreview"
+ action="#{wikiTextPreview.disablePreview(textEditorId)}"
+ status="globalStatus"
+ eventsQueue="ajaxEventQueue"
+ reRender="#{textEditorId}TextEditor, #{textEditorId}Preview"
+ oncomplete="onAjaxRequestComplete();setRememberedCursorPosition('##{namingContainer}\\\\:#{textEditorId}TextArea');"/>
- <h:inputTextarea id="#{textEditorId}TextArea"
- styleClass="ajaxSupport"
- tabindex="1"
- cols="#{empty textEditorColumns ? '58' : textEditorColumns}"
- rows="#{textEditorRows}"
- required="#{valueRequired}"
- value="#{valueBinding}">
- <a:support event="onkeyup"
- action="#{wikiTextEditor.validate(textEditorId, valueBinding)}"
- reRender="#{textEditorId}MessageLabel, #{textPreviewId}"
- status="globalStatus"
- ignoreDupResponses="true"
- requestDelay="3000"
- ajaxSingle="true"
- eventsQueue="ajaxEventQueue"
- oncomplete="onAjaxRequestComplete()"
- rendered="#{not empty textPreviewId}"/>
- </h:inputTextarea>
+ </s:fragment>
- <s:div id="#{textEditorId}TextEditResizeHandle" styleClass="textEditResizeHandle" style="display:none;float:right;"/>
- </s:div>
+ </s:fragment>
</h:panelGrid>
- </s:validateAll>
+ <s:div id="#{textEditorId}TextAreaDiv" styleClass="textEditResizable">
+ <h:inputTextarea id="#{textEditorId}TextArea"
+ styleClass="ajaxSupport"
+ tabindex="1"
+ cols="#{empty textEditorColumns ? '58' : textEditorColumns}"
+ rows="#{textEditorRows}"
+ value="#{valueBinding}">
+ <a:support event="onkeyup"
+ action="#{wikiTextValidator.validate(textEditorId, valueBinding, valueRequired)}"
+ reRender="#{textEditorId}MessageLabel, #{textEditorId}Preview"
+ status="globalStatus"
+ ignoreDupResponses="true"
+ requestDelay="3000"
+ ajaxSingle="true"
+ eventsQueue="ajaxEventQueue"
+ oncomplete="onAjaxRequestComplete()"
+ rendered="#{wikiTextPreview.isPreviewEnabled(textEditorId)}"/>
+ </h:inputTextarea>
+
+ <s:div id="#{textEditorId}TextEditResizeHandle" styleClass="textEditResizeHandle" style="display:none;float:right;"/>
+ </s:div>
+
+ </h:panelGrid>
+
</div>
</s:div>
Modified: trunk/examples/wiki/view/includes/wikiTextPreview.xhtml
===================================================================
--- trunk/examples/wiki/view/includes/wikiTextPreview.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/includes/wikiTextPreview.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -6,17 +6,24 @@
xmlns:a="https://ajax4jsf.dev.java.net/ajax"
xmlns:wiki="http://jboss.com/products/seam/wiki">
-<s:div id="#{textPreviewId}">
- <s:div styleClass="textPreview" rendered="#{not empty valueBinding}">
+<s:div id="#{textEditorId}Preview">
+ <s:div styleClass="textPreview"
+ rendered="#{not empty valueBinding
+ and wikiTextPreview.isPreviewEnabled(textEditorId)
+ and wikiTextValidator.isValid(textEditorId)}">
<wiki:formattedText value="#{valueBinding}"
linkStyleClass="regularLink"
brokenLinkStyleClass="brokenLink"
attachmentLinkStyleClass="regularLink"
thumbnailLinkStyleClass="regularLink"
- linkBaseFilet="#{baseDocument}"
+ linkBaseFile="#{baseDocument}"
currentAreaNumber="#{baseDirectory.areaNumber}"
enableMacroRendering="false"/>
</s:div>
+ <s:div styleClass="textPreview"
+ rendered="#{wikiTextPreview.isPreviewEnabled(textEditorId) and not wikiTextValidator.isValid(textEditorId)}">
+ <h:outputText value="#{messages['lacewiki.msg.wikiTextValidator.InvalidWikiText']}"/>
+ </s:div>
</s:div>
</s:fragment>
Modified: trunk/examples/wiki/view/themes/default/css/template.css
===================================================================
--- trunk/examples/wiki/view/themes/default/css/template.css 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/themes/default/css/template.css 2008-06-07 00:25:03 UTC (rev 8348)
@@ -698,6 +698,8 @@
margin-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
background-color: white;
margin-left: 80px;
margin-right: 80px;
@@ -1639,3 +1641,23 @@
font-size: 100%;
font-family: Verdana, Arial, Helvetica, sans-serif;
}
+
+/* Online Users Panel
+----------------------------------------------- */
+
+.onlineUsersPanel {
+ margin: 5px;
+ font-size: 85%;
+}
+
+.onlineUsersPanel .onlineLabel {
+ font-weight: bold;
+}
+
+.onlineUsersPanel .onlineValue {
+}
+
+.onlineUsersPanel .onlineSeparator {
+ color: #ccc;
+}
+
Modified: trunk/examples/wiki/view/themes/default/template.xhtml
===================================================================
--- trunk/examples/wiki/view/themes/default/template.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/themes/default/template.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -273,6 +273,8 @@
</ui:define>
</ui:decorate>
+ <ui:include src="../../includes/onlineUsers.xhtml"/>
+
<ui:insert name="sidebar"/>
</s:div>
Modified: trunk/examples/wiki/view/themes/inrelationto/css/inrelationto.css
===================================================================
--- trunk/examples/wiki/view/themes/inrelationto/css/inrelationto.css 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/themes/inrelationto/css/inrelationto.css 2008-06-07 00:25:03 UTC (rev 8348)
@@ -712,6 +712,8 @@
margin-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
background-color: white;
margin-left: 80px;
margin-right: 80px;
Modified: trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css
===================================================================
--- trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/themes/sfwkorg/css/sfwk.css 2008-06-07 00:25:03 UTC (rev 8348)
@@ -993,6 +993,8 @@
margin-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
background-color: white;
margin-left: 50px;
margin-right: 50px;
@@ -1804,4 +1806,26 @@
#mainMenu .mainMenuFooter .feedText {
color:#ca884e;
-}
\ No newline at end of file
+}
+
+/* Online Users Panel
+----------------------------------------------- */
+
+.onlineUsersPanel {
+ margin-left: auto;
+ margin-right: auto;
+ font-size: 85%;
+ color: #000;
+}
+
+.onlineUsersPanel .onlineLabel {
+ font-weight: bold;
+}
+
+.onlineUsersPanel .onlineValue {
+}
+
+.onlineUsersPanel .onlineSeparator {
+ color: #B6B6B6;
+}
+
Modified: trunk/examples/wiki/view/themes/sfwkorg/template.xhtml
===================================================================
--- trunk/examples/wiki/view/themes/sfwkorg/template.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/themes/sfwkorg/template.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -334,6 +334,12 @@
</div>
</div>
+ <s:div styleClass="membersAreaContainer" style="margin-top:15px;">
+ <b class="rtop"><b class="r1"></b><b class="r2"></b><b class="r3"></b><b class="r4"></b></b>
+ <ui:include src="../../includes/onlineUsers.xhtml"/>
+ <b class="rbottom"><b class="r4"></b><b class="r3"></b><b class="r2"></b><b class="r1"></b></b>
+ </s:div>
+
</div>
<!-- Main Content area -->
Modified: trunk/examples/wiki/view/userHome_d.xhtml
===================================================================
--- trunk/examples/wiki/view/userHome_d.xhtml 2008-06-07 00:00:46 UTC (rev 8347)
+++ trunk/examples/wiki/view/userHome_d.xhtml 2008-06-07 00:25:03 UTC (rev 8348)
@@ -216,7 +216,6 @@
<ui:include src="includes/wikiTextEditor.xhtml">
<ui:param name="tabId" value="userProfileTab"/>
<ui:param name="textEditorId" value="bio"/>
- <ui:param name="textPreviewId" value="bioPreview"/>
<ui:param name="namingContainer" value="userHomeForm"/>
<ui:param name="label" value="#{messages['lacewiki.label.userHome.Bio']}"/>
<ui:param name="valueBinding" value="#{userHome.instance.profile.bio}"/>
@@ -226,7 +225,7 @@
</ui:include>
<ui:include src="includes/wikiTextPreview.xhtml">
- <ui:param name="textPreviewId" value="bioPreview"/>
+ <ui:param name="textEditorId" value="bio"/>
<ui:param name="valueBinding" value="#{userHome.instance.profile.bio}"/>
<ui:param name="baseDocument" value="#{wikiStart}"/>
<ui:param name="baseDirectory" value="#{wikiStart.parent}"/>
@@ -262,7 +261,6 @@
<ui:include src="includes/wikiTextEditor.xhtml">
<ui:param name="tabId" value="userProfileTab"/>
<ui:param name="textEditorId" value="signature"/>
- <ui:param name="textPreviewId" value="signaturePreview"/>
<ui:param name="namingContainer" value="userHomeForm"/>
<ui:param name="label" value="#{messages['lacewiki.label.userHome.Signature']}"/>
<ui:param name="valueBinding" value="#{userHome.instance.profile.signature}"/>
@@ -272,7 +270,7 @@
</ui:include>
<ui:include src="includes/wikiTextPreview.xhtml">
- <ui:param name="textPreviewId" value="signaturePreview"/>
+ <ui:param name="textEditorId" value="signature"/>
<ui:param name="valueBinding" value="#{userHome.instance.profile.signature}"/>
<ui:param name="baseDocument" value="#{wikiStart}"/>
<ui:param name="baseDirectory" value="#{wikiStart.parent}"/>
16 years, 7 months
Seam SVN: r8347 - trunk/examples/seamspace/resources/WEB-INF.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2008-06-06 20:00:46 -0400 (Fri, 06 Jun 2008)
New Revision: 8347
Modified:
trunk/examples/seamspace/resources/WEB-INF/components.xml
Log:
updated
Modified: trunk/examples/seamspace/resources/WEB-INF/components.xml
===================================================================
--- trunk/examples/seamspace/resources/WEB-INF/components.xml 2008-06-06 23:09:28 UTC (rev 8346)
+++ trunk/examples/seamspace/resources/WEB-INF/components.xml 2008-06-07 00:00:46 UTC (rev 8347)
@@ -3,10 +3,7 @@
xmlns:core="http://jboss.com/products/seam/core"
xmlns:persistence="http://jboss.com/products/seam/persistence"
xmlns:security="http://jboss.com/products/seam/security"
- xmlns:identity-management="http://jboss.com/products/seam/security/management"
- xmlns:permission-management="http://jboss.com/products/seam/security/permission"
xmlns:drools="http://jboss.com/products/seam/drools"
- xmlns:captcha="http://jboss.com/products/seam/captcha"
xmlns:web="http://jboss.com/products/seam/web"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
@@ -14,10 +11,8 @@
http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.1.xsd
http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.1.xsd
http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.1.xsd
- http://jboss.com/products/seam/security/management http://jboss.com/products/seam/security-2.1.xsd
http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.1.xsd
- http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.1.xsd
- http://jboss.com/products/seam/captcha http://jboss.com/products/seam/captcha-2.1.xsd">
+ http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.1.xsd">
<core:init jndi-pattern="@jndiPattern@" debug="false"/>
@@ -27,14 +22,14 @@
<security:rule-based-permission-resolver security-rules="#{securityRules}"/>
- <identity-management:jpa-identity-store
+ <security:jpa-identity-store
user-class="org.jboss.seam.example.seamspace.MemberAccount"
role-class="org.jboss.seam.example.seamspace.MemberRole"
/>
- <!--identity-management:identity-manager identity-store="#{ldapIdentityStore}"/-->
+ <!--security:identity-manager identity-store="#{ldapIdentityStore}"/-->
- <identity-management:ldap-identity-store
+ <!--security:ldap-identity-store
server-address="60.241.32.50"
bind-DN="cn=Manager,dc=bryzak,dc=com"
bind-credentials="secret"
@@ -48,9 +43,9 @@
role-name-attribute="cn"
user-object-classes="person,uidObject"
enabled-attribute="enabled"
- />
+ /-->
- <permission-management:jpa-permission-store user-permission-class="org.jboss.seam.example.seamspace.AccountPermission"/>
+ <security:jpa-permission-store user-permission-class="org.jboss.seam.example.seamspace.AccountPermission"/>
<drools:rule-base name="securityRules">
<drools:rule-files>
16 years, 7 months
Seam SVN: r8346 - trunk/src/main/org/jboss/seam/contexts.
by seam-commits@lists.jboss.org
Author: norman.richards(a)jboss.com
Date: 2008-06-06 19:09:28 -0400 (Fri, 06 Jun 2008)
New Revision: 8346
Modified:
trunk/src/main/org/jboss/seam/contexts/ServerConversationContext.java
Log:
JBSEAM-3078
Modified: trunk/src/main/org/jboss/seam/contexts/ServerConversationContext.java
===================================================================
--- trunk/src/main/org/jboss/seam/contexts/ServerConversationContext.java 2008-06-06 21:44:58 UTC (rev 8345)
+++ trunk/src/main/org/jboss/seam/contexts/ServerConversationContext.java 2008-06-06 23:09:28 UTC (rev 8346)
@@ -276,19 +276,26 @@
//force update for dirty mutable objects
for (String key: getNamesForAllConversationsFromSession()) {
Object attribute = session.get(key);
-
- if ( attribute!=null && isAttributeDirty(attribute) ) {
- session.put(key, attribute);
+
+ if (attribute!=null) {
+ if (passivate(attribute) || isAttributeDirty(attribute)) {
+ session.put(key, attribute);
+ }
}
}
+
//remove removed objects
for (String name: removals) {
session.remove(getKey(name));
}
removals.clear();
+
//add new objects
for (Map.Entry<String, Object> entry: additions.entrySet()) {
- session.put( getKey( entry.getKey() ), entry.getValue() );
+ Object attribute = entry.getValue();
+
+ passivate(attribute);
+ session.put(getKey(entry.getKey()), attribute);
}
additions.clear();
}
@@ -302,12 +309,18 @@
}
}
- private boolean isAttributeDirty(Object attribute)
- {
- return Contexts.isAttributeDirty(attribute) ||
- ( attribute instanceof Wrapper && ( (Wrapper) attribute ).passivate() );
- }
-
+ private boolean passivate(Object attribute) {
+ if (attribute instanceof Wrapper) {
+ return ((Wrapper) attribute).passivate();
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isAttributeDirty(Object attribute) {
+ return Contexts.isAttributeDirty(attribute);
+ }
+
private boolean isCurrent()
{
return id==null || id.equals( Manager.instance().getCurrentConversationId() );
16 years, 7 months
Seam SVN: r8345 - branches/Seam_2_0/src/main/org/jboss/seam/contexts.
by seam-commits@lists.jboss.org
Author: norman.richards(a)jboss.com
Date: 2008-06-06 17:44:58 -0400 (Fri, 06 Jun 2008)
New Revision: 8345
Modified:
branches/Seam_2_0/src/main/org/jboss/seam/contexts/ServerConversationContext.java
Log:
JBSEAM-3078
Modified: branches/Seam_2_0/src/main/org/jboss/seam/contexts/ServerConversationContext.java
===================================================================
--- branches/Seam_2_0/src/main/org/jboss/seam/contexts/ServerConversationContext.java 2008-06-06 21:12:45 UTC (rev 8344)
+++ branches/Seam_2_0/src/main/org/jboss/seam/contexts/ServerConversationContext.java 2008-06-06 21:44:58 UTC (rev 8345)
@@ -277,18 +277,25 @@
for (String key: getNamesForAllConversationsFromSession()) {
Object attribute = session.get(key);
- if ( attribute!=null && isAttributeDirty(attribute) ) {
- session.put(key, attribute);
+ if (attribute!=null) {
+ if (passivate(attribute) || isAttributeDirty(attribute)) {
+ session.put(key, attribute);
+ }
}
}
+
//remove removed objects
for (String name: removals) {
session.remove(getKey(name));
}
removals.clear();
+
//add new objects
for (Map.Entry<String, Object> entry: additions.entrySet()) {
- session.put( getKey( entry.getKey() ), entry.getValue() );
+ Object attribute = entry.getValue();
+
+ passivate(attribute);
+ session.put(getKey(entry.getKey()), attribute);
}
additions.clear();
}
@@ -302,12 +309,18 @@
}
}
- private boolean isAttributeDirty(Object attribute)
- {
- return Contexts.isAttributeDirty(attribute) ||
- ( attribute instanceof Wrapper && ( (Wrapper) attribute ).passivate() );
- }
+ private boolean passivate(Object attribute) {
+ if (attribute instanceof Wrapper) {
+ return ((Wrapper) attribute).passivate();
+ } else {
+ return false;
+ }
+ }
+ private boolean isAttributeDirty(Object attribute) {
+ return Contexts.isAttributeDirty(attribute);
+ }
+
private boolean isCurrent()
{
return id==null || id.equals( Manager.instance().getCurrentConversationId() );
16 years, 7 months
Seam SVN: r8344 - in branches/Seam_2_0/src/test/mail: unit and 6 other directories.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-06-06 17:12:45 -0400 (Fri, 06 Jun 2008)
New Revision: 8344
Added:
branches/Seam_2_0/src/test/mail/unit/
branches/Seam_2_0/src/test/mail/unit/org/
branches/Seam_2_0/src/test/mail/unit/org/jboss/
branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/
branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/
branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/
branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/
branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java
branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/testng.xml
Log:
Backport JBSEAM-3071
Added: branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java
===================================================================
--- branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java (rev 0)
+++ branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java 2008-06-06 21:12:45 UTC (rev 8344)
@@ -0,0 +1,105 @@
+package org.jboss.seam.test.mail.unit;
+
+import org.jboss.seam.mail.ui.Header;
+import org.testng.annotations.Test;
+
+public class HeaderTest
+{
+ @Test
+ public void testHeader()
+ {
+ String name = "foo";
+ String value = "bar";
+
+ Header header = new Header(name, value);
+
+ assert header.getSanitizedName().equals(name);
+ assert header.getSanitizedValue().equals(value);
+ }
+
+ @Test
+ public void testHeaderWithLineFeed()
+ {
+ String name = "foo\nnewline";
+ String value = "bar\nnewline";
+
+ Header header = new Header(name, value);
+
+ assert !header.getSanitizedName().equals(name);
+ assert !header.getSanitizedValue().equals(value);
+
+ assert "foo".equals(header.getSanitizedName());
+ assert "bar".equals(header.getSanitizedValue());
+ }
+
+ @Test
+ public void testHeaderWithCarrigeReturnLineBreak()
+ {
+ String name = "foo\r\nnewline";
+ String value = "bar\r\nnewline";
+
+ Header header = new Header(name, value);
+
+ assert !header.getSanitizedName().equals(name);
+ assert !header.getSanitizedValue().equals(value);
+
+ assert "foo".equals(header.getSanitizedName());
+ assert "bar".equals(header.getSanitizedValue());
+ }
+
+ @Test
+ public void testHeaderWithCarriageReturn()
+ {
+ String name = "foo\rnewline";
+ String value = "bar\rnewline";
+
+ Header header = new Header(name, value);
+
+ assert !header.getSanitizedName().equals(name);
+ assert !header.getSanitizedValue().equals(value);
+
+ assert "foo".equals(header.getSanitizedName());
+ assert "bar".equals(header.getSanitizedValue());
+ }
+
+ @Test
+ public void testHeaderWithFolding1()
+ {
+ String name = "header";
+ String value = "\"Joe & J. Harvey\" <ddd @ Org>,\n JJV @ BBN";
+ String sanitizedValue = "\"Joe & J. Harvey\" <ddd @ Org>, JJV @ BBN";
+
+ Header header = new Header(name, value);
+
+ assert header.getSanitizedName().equals(name);
+ assert header.getSanitizedValue().equals(sanitizedValue);
+
+ }
+
+ @Test
+ public void testHeaderWithFolding2()
+ {
+ String name = "header";
+ String value = "\"Joe & J. Harvey\"\n <ddd @ Org>, JJV\n @ BBN";
+ String sanitizedValue = "\"Joe & J. Harvey\" <ddd @ Org>, JJV @ BBN";
+
+ Header header = new Header(name, value);
+
+ assert header.getSanitizedName().equals(name);
+ assert header.getSanitizedValue().equals(sanitizedValue);
+
+ }
+
+ @Test
+ public void testHeaderWithFolding3()
+ {
+ String name = "header";
+ String value = "\"Joe &\n J. Harvey\" <ddd @ Org>, JJV @ BBN";
+ String sanitizedValue = "\"Joe & J. Harvey\" <ddd @ Org>, JJV @ BBN";
+ Header header = new Header(name, value);
+
+ assert header.getSanitizedName().equals(name);
+ assert header.getSanitizedValue().equals(sanitizedValue);
+
+ }
+}
Property changes on: branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/testng.xml
===================================================================
--- branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/testng.xml (rev 0)
+++ branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/testng.xml 2008-06-06 21:12:45 UTC (rev 8344)
@@ -0,0 +1,9 @@
+<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
+
+<suite name="Seam Mail Unit Testsuite" verbose="2" parallel="false">
+ <test name="Seam Unit Tests: Mail">
+ <classes>
+ <class name="org.jboss.seam.test.mail.unit.HeaderTest"/>
+ </classes>
+ </test>
+</suite>
Property changes on: branches/Seam_2_0/src/test/mail/unit/org/jboss/seam/test/mail/unit/testng.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
16 years, 7 months
Seam SVN: r8343 - in branches/Seam_2_0: build and 3 other directories.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-06-06 17:12:24 -0400 (Fri, 06 Jun 2008)
New Revision: 8343
Added:
branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/sanitization.xhtml
branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/Header.java
branches/Seam_2_0/src/test/mail/
Modified:
branches/Seam_2_0/build.xml
branches/Seam_2_0/build/mail.pom.xml
branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/MailTest.java
branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/AddressComponent.java
branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIAttachment.java
branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIBody.java
branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIHeader.java
branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIMessage.java
branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UISubject.java
Log:
Backport JBSEAM-3071
Modified: branches/Seam_2_0/build/mail.pom.xml
===================================================================
--- branches/Seam_2_0/build/mail.pom.xml 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/build/mail.pom.xml 2008-06-06 21:12:24 UTC (rev 8343)
@@ -59,6 +59,19 @@
<artifactId>el-api</artifactId>
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>5.6</version>
+ <optional>true</optional>
+ <exclusions>
+ <exclusion>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
Modified: branches/Seam_2_0/build.xml
===================================================================
--- branches/Seam_2_0/build.xml 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/build.xml 2008-06-06 21:12:24 UTC (rev 8343)
@@ -22,6 +22,7 @@
<property name="classes.remoting.dir" value="${classes.dir}/remotingclasses" />
<property name="classes.gen.dir" value="${classes.dir}/genclasses" />
<property name="classes.test.dir" value="${classes.dir}/testclasses" />
+ <property name="classes.mail.test.dir" value="${classes.dir}/mailtestclasses" />
<property name="ui.dir" value="${basedir}/ui" />
<property name="seamgen.dir" value="${basedir}/seam-gen" />
@@ -38,6 +39,7 @@
<property name="src.remoting.dir" value="src/remoting" />
<property name="src.test.dir" value="src/test" />
<property name="src.unit.test.dir" value="${src.test.dir}/unit" />
+ <property name="src.mail.unit.test.dir" value="${src.test.dir}/mail/unit" />
<!-- Library directories -->
<property name="eejb.conf.dir" value="${basedir}/bootstrap" />
@@ -626,7 +628,7 @@
</target>
- <target name="testcore" depends="inittestcore,compiletest,getemma" description="Run the core tests">
+ <target name="testcore" depends="inittestcore,compiletest,getemma,unittestmail" description="Run the core tests">
<taskdef resource="testngtasks" classpathref="test.core.path" />
<testng outputdir="${test.dir}">
<jvmarg line="-Xmx800M" />
@@ -646,7 +648,37 @@
<testexample name="integration" path="${seam.dir}/src/test/integration" message=""/>
<echo>You can increase the logging by editing bootstrap/log4j.xml</echo>
</target>
+
+ <target name="inittestmail" depends="build">
+ <init classesdir="${classes.mail.test.dir}" srcdir="${src.mail.unit.test.dir}" modulename="mail" pom="${mail.pom}" scope="test" message="" />
+ <path id="test.mail.compile.path">
+ <path refid="test.mail.path" />
+ <path path="${classes.mail.test.dir}" />
+ <path location="${classes.mail.dir}" />
+ </path>
+ </target>
+
+ <target name="compiletestmail" depends="inittestmail,select-compiler,antlr">
+ <compile classesdir="${classes.mail.test.dir}" srcdir="${src.mail.unit.test.dir}" classpath="test.mail.compile.path" />
+ </target>
+
+ <target name="unittestmail" depends="inittestmail,compiletestmail,getemma">
+ <taskdef resource="testngtasks" classpathref="test.mail.path" />
+ <testng outputdir="${test.dir}">
+ <jvmarg value="-Demma.coverage.out.file=${coverage.ec}" />
+ <jvmarg line="-Djava.awt.headless=true" />
+ <classpath>
+ <path path="${classes.mail.test.dir}" />
+ <path location="${classes.mail.dir}" />
+ <path refid="runtime.emma.path" />
+ <path refid="test.mail.path" />
+ </classpath>
+ <xmlfileset dir="${classes.mail.test.dir}" includes="**/testng.xml" />
+ </testng>
+ <echo>You can increase the logging by editing bootstrap/log4j.xml</echo>
+ </target>
+
<target name="testreport" description="Create a pretty report">
<mkdir dir="${report.dir}" />
<junitreport todir="${report.dir}">
Modified: branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/MailTest.java
===================================================================
--- branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/MailTest.java 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/MailTest.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -4,6 +4,7 @@
import static javax.mail.Message.RecipientType.CC;
import java.io.InputStream;
+import java.util.Enumeration;
import javax.faces.FacesException;
import javax.faces.context.FacesContext;
@@ -91,6 +92,8 @@
}
+
+
@Test
public void testAttachment() throws Exception
{
@@ -528,6 +531,40 @@
}
@Test
+ public void testSanitization() throws Exception
+ {
+
+ new FacesRequest()
+ {
+
+ @Override
+ protected void updateModelValues() throws Exception
+ {
+
+ }
+
+ @Override
+ protected void invokeApplication() throws Exception
+ {
+ Contexts.getEventContext().set("name", "Pete\nMuir");
+ MimeMessage renderedMessage = getRenderedMailMessage("/org/jboss/seam/example/mail/test/sanitization.xhtml");
+ assert "Try out".equals(renderedMessage.getSubject());
+ InternetAddress to = (InternetAddress) renderedMessage.getAllRecipients()[0];
+ assert to.getAddress().equals("peter(a)email.tld");
+ assert to.getPersonal().equals("Pete");
+ assert renderedMessage.getFrom().length == 1;
+ assert renderedMessage.getFrom()[0] instanceof InternetAddress;
+ InternetAddress from = (InternetAddress) renderedMessage.getFrom()[0];
+ assert from.getAddress().equals("peter(a)example.com");
+ assert from.getPersonal().equals("Pete");
+ assert renderedMessage.getHeader("Pete") != null;
+ assert renderedMessage.getHeader("Pete").length == 1;
+ assert "roll".equals(renderedMessage.getHeader("Pete")[0]);
+ }
+ }.run();
+ }
+
+ @Test
public void testTemplating() throws Exception
{
Added: branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/sanitization.xhtml
===================================================================
--- branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/sanitization.xhtml (rev 0)
+++ branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/sanitization.xhtml 2008-06-06 21:12:24 UTC (rev 8343)
@@ -0,0 +1,14 @@
+<m:message xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:m="http://jboss.com/products/seam/mail"
+ xmlns:h="http://java.sun.com/jsf/html">
+
+ <m:from name="#{name}">peter(a)example.com
+foo</m:from>
+ <m:to name="#{name}">peter(a)email.tld
+bar</m:to>
+ <m:subject>Try out
+Seam!</m:subject>
+ <m:header name="#{name}">roll
+over</m:header>
+ <m:body>A mail message to test sanitization</m:body>
+</m:message>
\ No newline at end of file
Property changes on: branches/Seam_2_0/examples/mail/src/org/jboss/seam/example/mail/test/sanitization.xhtml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/AddressComponent.java
===================================================================
--- branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/AddressComponent.java 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/AddressComponent.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -25,15 +25,16 @@
protected InternetAddress getInternetAddress(FacesContext facesContext) throws IOException, AddressException
{
InternetAddress address = new InternetAddress();
- address.setAddress(getAddress() != null ? getAddress() : encode(facesContext));
+ address.setAddress(new Header(getAddress() != null ? getAddress() : encode(facesContext)).getSanitizedValue());
String charset = findMessage().getCharset();
+ String personal = new Header(getName()).getSanitizedValue();
if (charset == null)
{
- address.setPersonal(getName());
+ address.setPersonal(personal);
}
else
{
- address.setPersonal(getName(), charset);
+ address.setPersonal(personal, charset);
}
address.validate();
return address;
@@ -70,7 +71,7 @@
*/
public String getName()
{
- if (address == null)
+ if (name == null)
{
return getString("name");
}
Added: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/Header.java
===================================================================
--- branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/Header.java (rev 0)
+++ branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/Header.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -0,0 +1,82 @@
+package org.jboss.seam.mail.ui;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.mail.internet.MimeUtility;
+
+public class Header
+{
+
+ private final String name;
+ private final String value;
+
+ private String sanitizedName;
+ private String sanitizedValue;
+
+ public Header(String name, String value)
+ {
+ this.name = name;
+ this.value = value;
+ }
+
+ public Header(String value)
+ {
+ this.value = value;
+ this.name = null;
+ }
+
+ public String getSanitizedName()
+ {
+ if (sanitizedName == null && name != null)
+ {
+ try
+ {
+ sanitizedName = sanitize(name);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("Error santizing Header name " + name, e);
+ }
+ }
+ return sanitizedName;
+ }
+
+ public String getSanitizedValue()
+ {
+ if (sanitizedValue == null && value != null)
+ {
+ try
+ {
+ sanitizedValue = sanitizeValue(value);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("Error santizing Header " + name + " value " + value, e);
+ }
+ }
+ return sanitizedValue;
+ }
+
+ /**
+ * Remove any line feed/new line characters
+ * @throws IOException
+ */
+ public static String sanitize(String value) throws IOException
+ {
+ BufferedReader reader = new BufferedReader(new StringReader(value));
+ return reader.readLine();
+ }
+
+ /**
+ * Remove any line feed/new line characters from a (possibly) folded header
+ * @throws IOException
+ */
+ public static String sanitizeValue(String value) throws IOException
+ {
+ // The user might have folded the header (stupid SMTP idiocy)
+ return sanitize(MimeUtility.unfold(value));
+ }
+
+}
Property changes on: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/Header.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIAttachment.java
===================================================================
--- branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIAttachment.java 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIAttachment.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -163,10 +163,10 @@
MimeBodyPart attachment = new MimeBodyPart();
// Need to manually set the contentid
String contentId = RandomStringUtils.randomAlphabetic(20).toLowerCase();
- attachment.setContentID("<" + contentId + ">");
+ attachment.setContentID(new Header("<" + contentId + ">").getSanitizedValue());
attachment.setDataHandler(new DataHandler(ds));
- attachment.setFileName(getName(ds.getName()));
- attachment.setDisposition(getDisposition());
+ attachment.setFileName(new Header(getName(ds.getName())).getSanitizedValue());
+ attachment.setDisposition(new Header(getDisposition()).getSanitizedValue());
super.getRootMultipart().addBodyPart(attachment);
if (getStatus() != null)
{
Modified: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIBody.java
===================================================================
--- branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIBody.java 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIBody.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -88,13 +88,13 @@
throws MessagingException
{
MimeBodyPart bodyPart = new MimeBodyPart();
- bodyPart.setDisposition("inline");
+ bodyPart.setDisposition(new Header("inline").getSanitizedValue());
String charset = findMessage().getCharset();
if ( charset != null)
{
//bodyPart.setContent(body, "text/plain; charset="
// + charset + "; format=flowed");
- bodyPart.setText(body, charset);
+ bodyPart.setText(body, new Header(charset).getSanitizedValue());
}
else
{
@@ -107,16 +107,16 @@
throws MessagingException
{
MimeBodyPart bodyPart = new MimeBodyPart();
- bodyPart.setDisposition("inline");
+ bodyPart.setDisposition(new Header("inline").getSanitizedValue());
String charset = findMessage().getCharset();
if ( charset != null)
{
- bodyPart.setContent(body, "text/html; charset="
- + charset);
+ bodyPart.setContent(body, new Header("text/html; charset="
+ + charset).getSanitizedValue());
}
else
{
- bodyPart.setContent(body, "text/html");
+ bodyPart.setContent(body, new Header("text/html").getSanitizedValue());
}
return bodyPart;
Modified: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIHeader.java
===================================================================
--- branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIHeader.java 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIHeader.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -17,11 +17,16 @@
{
try
{
- if (getValue() != null) {
- findMimeMessage().addHeader(getName(), getValue());
- } else {
- findMimeMessage().addHeader(getName(), encode(facesContext));
+ if (getValue() != null)
+ {
+ Header header = new Header(getName(), getValue());
+ findMimeMessage().addHeader(header.getSanitizedName(), header.getSanitizedValue());
}
+ else
+ {
+ Header header = new Header(getName(), encode(facesContext));
+ findMimeMessage().addHeader(header.getSanitizedName(), header.getSanitizedValue());
+ }
}
catch (MessagingException e)
{
Modified: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIMessage.java
===================================================================
--- branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIMessage.java 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UIMessage.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -108,7 +108,8 @@
}
if (getPrecedence() != null)
{
- getMimeMessage().addHeader("Precedence", getPrecedence());
+ Header header = new Header("Precedence", getPrecedence());
+ getMimeMessage().addHeader(header.getSanitizedName(), header.getSanitizedValue());
}
}
catch (MessagingException e)
@@ -131,8 +132,9 @@
if (isRequestReadReceipt() && getMimeMessage().getFrom() != null
&& getMimeMessage().getFrom().length == 1)
{
- getMimeMessage().addHeader("Disposition-Notification-To",
- getMimeMessage().getFrom()[0].toString());
+ Header header = new Header("Disposition-Notification-To",
+ getMimeMessage().getFrom()[0].toString());
+ getMimeMessage().addHeader(header.getSanitizedName(), header.getSanitizedValue());
}
// Do the send manually, Transport.send gets the wrong transport
getMimeMessage().saveChanges();
Modified: branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UISubject.java
===================================================================
--- branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UISubject.java 2008-06-06 20:36:35 UTC (rev 8342)
+++ branches/Seam_2_0/src/mail/org/jboss/seam/mail/ui/UISubject.java 2008-06-06 21:12:24 UTC (rev 8343)
@@ -22,11 +22,11 @@
String charset = findMessage().getCharset();
if (charset == null)
{
- findMimeMessage().setSubject(subject);
+ findMimeMessage().setSubject(new Header(subject).getSanitizedValue());
}
else
{
- findMimeMessage().setSubject(subject, charset);
+ findMimeMessage().setSubject(new Header(subject).getSanitizedValue(), charset);
}
}
catch (MessagingException e)
16 years, 7 months
Seam SVN: r8342 - in trunk/src: test/mail/unit/org/jboss/seam/test/mail/unit and 1 other directory.
by seam-commits@lists.jboss.org
Author: pete.muir(a)jboss.org
Date: 2008-06-06 16:36:35 -0400 (Fri, 06 Jun 2008)
New Revision: 8342
Modified:
trunk/src/mail/org/jboss/seam/mail/ui/Header.java
trunk/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java
Log:
Add line folding
Modified: trunk/src/mail/org/jboss/seam/mail/ui/Header.java
===================================================================
--- trunk/src/mail/org/jboss/seam/mail/ui/Header.java 2008-06-06 16:07:16 UTC (rev 8341)
+++ trunk/src/mail/org/jboss/seam/mail/ui/Header.java 2008-06-06 20:36:35 UTC (rev 8342)
@@ -4,6 +4,8 @@
import java.io.IOException;
import java.io.StringReader;
+import javax.mail.internet.MimeUtility;
+
public class Header
{
@@ -47,7 +49,7 @@
{
try
{
- sanitizedValue = sanitize(value);
+ sanitizedValue = sanitizeValue(value);
}
catch (IOException e)
{
@@ -66,5 +68,15 @@
BufferedReader reader = new BufferedReader(new StringReader(value));
return reader.readLine();
}
+
+ /**
+ * Remove any line feed/new line characters from a (possibly) folded header
+ * @throws IOException
+ */
+ public static String sanitizeValue(String value) throws IOException
+ {
+ // The user might have folded the header (stupid SMTP idiocy)
+ return sanitize(MimeUtility.unfold(value));
+ }
}
Modified: trunk/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java
===================================================================
--- trunk/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java 2008-06-06 16:07:16 UTC (rev 8341)
+++ trunk/src/test/mail/unit/org/jboss/seam/test/mail/unit/HeaderTest.java 2008-06-06 20:36:35 UTC (rev 8342)
@@ -61,4 +61,45 @@
assert "foo".equals(header.getSanitizedName());
assert "bar".equals(header.getSanitizedValue());
}
+
+ @Test
+ public void testHeaderWithFolding1()
+ {
+ String name = "header";
+ String value = "\"Joe & J. Harvey\" <ddd @ Org>,\n JJV @ BBN";
+ String sanitizedValue = "\"Joe & J. Harvey\" <ddd @ Org>, JJV @ BBN";
+
+ Header header = new Header(name, value);
+
+ assert header.getSanitizedName().equals(name);
+ assert header.getSanitizedValue().equals(sanitizedValue);
+
+ }
+
+ @Test
+ public void testHeaderWithFolding2()
+ {
+ String name = "header";
+ String value = "\"Joe & J. Harvey\"\n <ddd @ Org>, JJV\n @ BBN";
+ String sanitizedValue = "\"Joe & J. Harvey\" <ddd @ Org>, JJV @ BBN";
+
+ Header header = new Header(name, value);
+
+ assert header.getSanitizedName().equals(name);
+ assert header.getSanitizedValue().equals(sanitizedValue);
+
+ }
+
+ @Test
+ public void testHeaderWithFolding3()
+ {
+ String name = "header";
+ String value = "\"Joe &\n J. Harvey\" <ddd @ Org>, JJV @ BBN";
+ String sanitizedValue = "\"Joe & J. Harvey\" <ddd @ Org>, JJV @ BBN";
+ Header header = new Header(name, value);
+
+ assert header.getSanitizedName().equals(name);
+ assert header.getSanitizedValue().equals(sanitizedValue);
+
+ }
}
16 years, 7 months
Seam SVN: r8341 - trunk/src/main/org/jboss/seam/security.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2008-06-06 12:07:16 -0400 (Fri, 06 Jun 2008)
New Revision: 8341
Modified:
trunk/src/main/org/jboss/seam/security/RememberMe.java
Log:
ensure the user account is enabled
Modified: trunk/src/main/org/jboss/seam/security/RememberMe.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/RememberMe.java 2008-06-06 15:57:22 UTC (rev 8340)
+++ trunk/src/main/org/jboss/seam/security/RememberMe.java 2008-06-06 16:07:16 UTC (rev 8341)
@@ -73,7 +73,7 @@
@Override
public String getCookieName()
{
- return "org.jboss.seam.security.token";
+ return "org.jboss.seam.security.authtoken";
}
}
@@ -246,20 +246,23 @@
if (tokenStore.validateToken(identity.getCredentials().getUsername(),
identity.getCredentials().getPassword()))
{
- // Success, authenticate the user
- identity.getSubject().getPrincipals().add(new SimplePrincipal(
- identity.getCredentials().getUsername()));
- // And populate the roles
- for (String role : IdentityManager.instance().getImpliedRoles(
- identity.getCredentials().getUsername()))
+ // Success, authenticate the user (if their account is enabled)
+ if (IdentityManager.instance().isUserEnabled(identity.getCredentials().getUsername()))
{
- identity.addRole(role);
+ identity.getSubject().getPrincipals().add(new SimplePrincipal(
+ identity.getCredentials().getUsername()));
+ // And populate the roles
+ for (String role : IdentityManager.instance().getImpliedRoles(
+ identity.getCredentials().getUsername()))
+ {
+ identity.addRole(role);
+ }
+
+ identity.postAuthenticate();
+
+ autoLoggedIn = true;
}
-
- identity.postAuthenticate();
-
- autoLoggedIn = true;
- }
+ }
}
}
16 years, 7 months
Seam SVN: r8340 - trunk/src/main/org/jboss/seam/security.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2008-06-06 11:57:22 -0400 (Fri, 06 Jun 2008)
New Revision: 8340
Added:
trunk/src/main/org/jboss/seam/security/JpaTokenStore.java
trunk/src/main/org/jboss/seam/security/RememberMe.java
trunk/src/main/org/jboss/seam/security/TokenStore.java
Modified:
trunk/src/main/org/jboss/seam/security/Credentials.java
trunk/src/main/org/jboss/seam/security/FacesSecurityEvents.java
trunk/src/main/org/jboss/seam/security/Identity.java
Log:
JBSEAM-2079
Modified: trunk/src/main/org/jboss/seam/security/Credentials.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/Credentials.java 2008-06-06 15:20:22 UTC (rev 8339)
+++ trunk/src/main/org/jboss/seam/security/Credentials.java 2008-06-06 15:57:22 UTC (rev 8340)
@@ -15,7 +15,6 @@
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
-import org.jboss.seam.annotations.Startup;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.core.Events;
import org.jboss.seam.log.LogProvider;
@@ -25,9 +24,9 @@
@Scope(SESSION)
@Install(precedence = BUILT_IN)
@BypassInterceptors
-@Startup
public class Credentials implements Serializable
{
+ public static final String EVENT_INIT_CREDENTIALS = "org.jboss.seam.security.initCredentials";
public static final String EVENT_CREDENTIALS_UPDATED = "org.jboss.seam.security.credentialsUpdated";
private static final LogProvider log = Logging.getLogProvider(Credentials.class);
@@ -37,8 +36,16 @@
private boolean invalid = false;
+ private boolean initialized;
+
public String getUsername()
{
+ if (!initialized && Events.exists())
+ {
+ initialized = true;
+ Events.instance().raiseEvent(EVENT_INIT_CREDENTIALS, this);
+ }
+
return username;
}
Modified: trunk/src/main/org/jboss/seam/security/FacesSecurityEvents.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/FacesSecurityEvents.java 2008-06-06 15:20:22 UTC (rev 8339)
+++ trunk/src/main/org/jboss/seam/security/FacesSecurityEvents.java 2008-06-06 15:57:22 UTC (rev 8340)
@@ -3,7 +3,6 @@
import static org.jboss.seam.ScopeType.APPLICATION;
import static org.jboss.seam.annotations.Install.BUILT_IN;
-import javax.faces.context.FacesContext;
import javax.security.auth.login.LoginException;
import org.jboss.seam.annotations.Install;
@@ -12,13 +11,12 @@
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
-import org.jboss.seam.faces.Selector;
import org.jboss.seam.international.StatusMessages;
import org.jboss.seam.international.StatusMessage.Severity;
/**
- * Produces FacesMessages for certain security events, and decouples the
- * Identity component from JSF - and also handles cookie functionality.
+ * Produces FacesMessages in response of certain security events, and helps to decouple the
+ * Identity component from JSF.
*
* @author Shane Bryzak
*/
@@ -27,58 +25,15 @@
@Install(precedence = BUILT_IN, classDependencies = "javax.faces.context.FacesContext")
@BypassInterceptors
@Startup
-public class FacesSecurityEvents extends Selector
+public class FacesSecurityEvents
{
- @Override
- public String getCookieName()
- {
- return "org.jboss.seam.security.username";
- }
-
- @Observer("org.jboss.seam.postCreate.org.jboss.seam.security.identity")
- public void initCredentialsFromCookie(Identity identity)
- {
- FacesContext ctx = FacesContext.getCurrentInstance();
- if (ctx != null)
- {
- setCookiePath(ctx.getExternalContext().getRequestContextPath());
- }
-
- identity.setRememberMe(isCookieEnabled());
-
- String username = getCookieValue();
- if (username!=null)
- {
- setCookieEnabled(true);
- identity.setUsername(username);
- postRememberMe(identity);
- }
-
- setDirty();
- }
-
- @Observer(Credentials.EVENT_CREDENTIALS_UPDATED)
- public void credentialsUpdated()
- {
- setDirty();
- }
-
@Observer(Identity.EVENT_POST_AUTHENTICATE)
public void postAuthenticate(Identity identity)
- {
- // Password is set to null during authentication, so we set dirty
- setDirty();
-
- if ( !identity.isRememberMe() ) clearCookieValue();
- setCookieValueIfEnabled( identity.getUsername() );
+ {
+ //org.jboss.security.saml.SSOManager.processManualLoginNotification(
+ //ServletContexts.instance().getRequest(), identity.getPrincipal().getName());
}
- @Observer(Identity.EVENT_REMEMBER_ME)
- public void postRememberMe(Identity identity)
- {
- setCookieEnabled(identity.isRememberMe());
- }
-
@Observer(Identity.EVENT_LOGIN_FAILED)
public void addLoginFailedMessage(LoginException ex)
{
@@ -111,7 +66,7 @@
getLoginSuccessfulMessageSeverity(),
getLoginSuccessfulMessageKey(),
getLoginSuccessfulMessage(),
- Identity.instance().getUsername());
+ Identity.instance().getCredentials().getUsername());
}
@Observer(Identity.EVENT_NOT_LOGGED_IN)
Modified: trunk/src/main/org/jboss/seam/security/Identity.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/Identity.java 2008-06-06 15:20:22 UTC (rev 8339)
+++ trunk/src/main/org/jboss/seam/security/Identity.java 2008-06-06 15:57:22 UTC (rev 8340)
@@ -56,8 +56,8 @@
public static final String EVENT_PRE_AUTHENTICATE = "org.jboss.seam.security.preAuthenticate";
public static final String EVENT_POST_AUTHENTICATE = "org.jboss.seam.security.postAuthenticate";
public static final String EVENT_LOGGED_OUT = "org.jboss.seam.security.loggedOut";
- public static final String EVENT_REMEMBER_ME = "org.jboss.seam.security.rememberMe";
- public static final String EVENT_ALREADY_LOGGED_IN = "org.jboss.seam.security.alreadyLoggedIn";
+ public static final String EVENT_ALREADY_LOGGED_IN = "org.jboss.seam.security.alreadyLoggedIn";
+ public static final String EVENT_QUIET_LOGIN = "org.jboss.seam.security.quietLogin";
protected static boolean securityEnabled = true;
@@ -76,7 +76,7 @@
private Principal principal;
private Subject subject;
- private boolean rememberMe;
+ private RememberMe rememberMe;
private String jaasConfigName = null;
@@ -99,7 +99,8 @@
permissionMapper = (PermissionMapper) Component.getInstance(PermissionMapper.class);
}
- credentials = (Credentials) Component.getInstance(Credentials.class);
+ rememberMe = (RememberMe) Component.getInstance(RememberMe.class, true);
+ credentials = (Credentials) Component.getInstance(Credentials.class);
}
public static boolean isSecurityEnabled()
@@ -258,12 +259,18 @@
{
try
{
- if (credentials.isSet())
+ if (Events.exists()) Events.instance().raiseEvent(EVENT_QUIET_LOGIN, this);
+
+ // Ensure that we haven't been authenticated as a result of the EVENT_QUIET_LOGIN event
+ if (!isLoggedIn(false))
{
- authenticate();
- if (isLoggedIn(false) && Contexts.isEventContextActive())
+ if (credentials.isSet())
{
- Contexts.getEventContext().set(SILENT_LOGIN, true);
+ authenticate();
+ if (isLoggedIn(false) && Contexts.isEventContextActive())
+ {
+ Contexts.getEventContext().set(SILENT_LOGIN, true);
+ }
}
}
}
@@ -323,7 +330,7 @@
* authenticated user. This method may be overridden by a subclass if
* different post-authentication logic should occur.
*/
- protected void postAuthenticate()
+ void postAuthenticate()
{
// Populate the working memory with the user's principals
for ( Principal p : getSubject().getPrincipals() )
@@ -630,8 +637,26 @@
public void setPassword(String password)
{
credentials.setPassword(password);
+ }
+
+ /**
+ * @see org.jboss.seam.security.RememberMe#isEnabled()
+ */
+ @Deprecated
+ public boolean isRememberMe()
+ {
+ return rememberMe != null ? rememberMe.isEnabled() : false;
}
+ /**
+ * @see org.jboss.seam.security.RememberMe#setEnabled(boolean)
+ */
+ @Deprecated
+ public void setRememberMe(boolean remember)
+ {
+ if (rememberMe != null) rememberMe.setEnabled(remember);
+ }
+
public Credentials getCredentials()
{
return credentials;
@@ -647,20 +672,6 @@
this.authenticateMethod = authMethod;
}
- public boolean isRememberMe()
- {
- return rememberMe;
- }
-
- public void setRememberMe(boolean remember)
- {
- if (this.rememberMe != remember)
- {
- this.rememberMe = remember;
- if (Events.exists()) Events.instance().raiseEvent(EVENT_REMEMBER_ME, this);
- }
- }
-
public String getJaasConfigName()
{
return jaasConfigName;
Added: trunk/src/main/org/jboss/seam/security/JpaTokenStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/JpaTokenStore.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/JpaTokenStore.java 2008-06-06 15:57:22 UTC (rev 8340)
@@ -0,0 +1,162 @@
+package org.jboss.seam.security;
+
+import static org.jboss.seam.ScopeType.APPLICATION;
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.io.Serializable;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.Query;
+
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.annotations.security.TokenUsername;
+import org.jboss.seam.annotations.security.TokenValue;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.core.Expressions.ValueExpression;
+import org.jboss.seam.security.management.IdentityManagementException;
+import org.jboss.seam.util.AnnotatedBeanProperty;
+
+/**
+ * A TokenStore implementation, stores tokens inside a database table.
+ *
+ * @author Shane Bryzak
+ */
+@Name("org.jboss.seam.security.tokenStore")
+@Install(precedence = BUILT_IN, value=false)
+@Scope(APPLICATION)
+@BypassInterceptors
+public class JpaTokenStore implements TokenStore, Serializable
+{
+ private Class tokenClass;
+
+ private ValueExpression<EntityManager> entityManager;
+
+ private AnnotatedBeanProperty<TokenUsername> tokenUsernameProperty;
+ private AnnotatedBeanProperty<TokenValue> tokenValueProperty;
+
+ @Create
+ public void create()
+ {
+ if (entityManager == null)
+ {
+ entityManager = Expressions.instance().createValueExpression("#{entityManager}", EntityManager.class);
+ }
+
+ tokenUsernameProperty = AnnotatedBeanProperty.scanForProperty(tokenClass, TokenUsername.class);
+ tokenValueProperty = AnnotatedBeanProperty.scanForProperty(tokenClass, TokenValue.class);
+
+ if (tokenUsernameProperty == null)
+ {
+ throw new IllegalStateException("Invalid tokenClass " + tokenClass.getName() +
+ " - required annotation @TokenUsername not found on any Field or Method.");
+ }
+
+ if (tokenValueProperty == null)
+ {
+ throw new IllegalStateException("Invalid tokenClass " + tokenClass.getName() +
+ " - required annotation @TokenValue not found on any Field or Method.");
+ }
+ }
+
+ public void createToken(String username, String value)
+ {
+ if (tokenClass == null)
+ {
+ throw new IllegalStateException("Could not create token, tokenClass not set");
+ }
+
+ try
+ {
+ Object token = tokenClass.newInstance();
+
+ tokenUsernameProperty.setValue(token, username);
+ tokenValueProperty.setValue(token, value);
+
+ lookupEntityManager().persist(token);
+ }
+ catch (Exception ex)
+ {
+ if (ex instanceof IdentityManagementException)
+ {
+ throw (IdentityManagementException) ex;
+ }
+ else
+ {
+ throw new IdentityManagementException("Could not create account", ex);
+ }
+ }
+ }
+
+ public boolean validateToken(String username, String value)
+ {
+ return lookupToken(username, value) != null;
+ }
+
+ public void invalidateToken(String username, String value)
+ {
+ Object token = lookupToken(username, value);
+ lookupEntityManager().remove(token);
+ }
+
+ public void invalidateAll(String username)
+ {
+ Query query = lookupEntityManager().createQuery(
+ "select t from " + tokenClass.getName() + " t where " + tokenUsernameProperty.getName() +
+ " = :username")
+ .setParameter("username", username);
+
+ for (Object token : query.getResultList())
+ {
+ lookupEntityManager().remove(token);
+ }
+ }
+
+ public Object lookupToken(String username, String value)
+ {
+ try
+ {
+ Object token = lookupEntityManager().createQuery(
+ "select t from " + tokenClass.getName() + " t where " + tokenUsernameProperty.getName() +
+ " = :username and " + tokenValueProperty.getName() + " = :value")
+ .setParameter("username", username)
+ .setParameter("value", value)
+ .getSingleResult();
+
+ return token;
+ }
+ catch (NoResultException ex)
+ {
+ return null;
+ }
+ }
+
+ public Class getTokenClass()
+ {
+ return tokenClass;
+ }
+
+ public void setTokenClass(Class tokenClass)
+ {
+ this.tokenClass = tokenClass;
+ }
+
+ private EntityManager lookupEntityManager()
+ {
+ return entityManager.getValue();
+ }
+
+ public ValueExpression getEntityManager()
+ {
+ return entityManager;
+ }
+
+ public void setEntityManager(ValueExpression expression)
+ {
+ this.entityManager = expression;
+ }
+}
Added: trunk/src/main/org/jboss/seam/security/RememberMe.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/RememberMe.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/RememberMe.java 2008-06-06 15:57:22 UTC (rev 8340)
@@ -0,0 +1,322 @@
+package org.jboss.seam.security;
+
+import static org.jboss.seam.ScopeType.SESSION;
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.rmi.server.UID;
+import java.util.Random;
+
+import javax.faces.context.FacesContext;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.faces.Selector;
+import org.jboss.seam.security.management.IdentityManager;
+import org.jboss.seam.util.Base64;
+
+/**
+ * Remember-me functionality is provided by this class, in two different flavours. The first mode
+ * provides username-only persistence, and is considered to be secure as the user (or their browser)
+ * is still required to provide a password. The second mode provides an auto-login feature, however
+ * is NOT considered to be secure and is vulnerable to XSS attacks compromising the user's account.
+ *
+ * Use the auto-login mode with caution!
+ *
+ * @author Shane Bryzak
+ */
+@Name("org.jboss.seam.security.rememberMe")
+@Scope(SESSION)
+@Install(precedence = BUILT_IN, classDependencies = "javax.faces.context.FacesContext")
+@BypassInterceptors
+public class RememberMe
+{
+ class UsernameSelector extends Selector
+ {
+ @Override
+ public String getCookieName()
+ {
+ return "org.jboss.seam.security.username";
+ }
+
+ @Override
+ public void setDirty()
+ {
+ super.setDirty();
+ }
+
+ @Override
+ public String getCookieValue()
+ {
+ return super.getCookieValue();
+ }
+
+ @Override
+ public void clearCookieValue()
+ {
+ super.clearCookieValue();
+ }
+
+ @Override
+ public void setCookieValueIfEnabled(String value)
+ {
+ super.setCookieValueIfEnabled(value);
+ }
+ }
+
+ class TokenSelector extends UsernameSelector
+ {
+ @Override
+ public String getCookieName()
+ {
+ return "org.jboss.seam.security.token";
+ }
+ }
+
+ private class DecodedToken
+ {
+ private String username;
+ private String value;
+
+ public DecodedToken(String cookieValue)
+ {
+ String decoded = new String(Base64.decode(cookieValue));
+
+ username = decoded.substring(0, decoded.indexOf(':'));
+ value = decoded.substring(decoded.indexOf(':') + 1);
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+ }
+
+ private UsernameSelector usernameSelector;
+
+ private TokenSelector tokenSelector;
+ private TokenStore tokenStore;
+
+ private boolean enabled;
+
+ private boolean autoLoggedIn;
+
+ private Random random = new Random(System.currentTimeMillis());
+
+ public enum Mode { disabled, usernameOnly, autoLogin}
+
+ private Mode mode = Mode.usernameOnly;
+
+ public Mode getMode()
+ {
+ return mode;
+ }
+
+ public void setMode(Mode mode)
+ {
+ this.mode = mode;
+ }
+
+ public boolean isEnabled()
+ {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled)
+ {
+ if (this.enabled != enabled)
+ {
+ this.enabled = enabled;
+ usernameSelector.setCookieEnabled(enabled);
+ usernameSelector.setDirty();
+ }
+ }
+
+ public TokenStore getTokenStore()
+ {
+ return tokenStore;
+ }
+
+ public void setTokenStore(TokenStore tokenStore)
+ {
+ this.tokenStore = tokenStore;
+ }
+
+ @Create
+ public void create()
+ {
+ if (mode.equals(Mode.usernameOnly))
+ {
+ usernameSelector = new UsernameSelector();
+ }
+ else if (mode.equals(Mode.autoLogin))
+ {
+ tokenSelector = new TokenSelector();
+
+ // Default to JpaTokenStore
+ if (tokenStore == null)
+ {
+ tokenStore = (TokenStore) Component.getInstance(JpaTokenStore.class, true);
+ }
+ }
+ }
+
+ protected String generateTokenValue()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(new UID().toString());
+ sb.append(":");
+ sb.append(random.nextLong());
+ return sb.toString();
+ }
+
+ protected String encodeToken(String username, String value)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(username);
+ sb.append(":");
+ sb.append(value);
+ return Base64.encodeBytes(sb.toString().getBytes());
+ }
+
+ @Observer(Credentials.EVENT_INIT_CREDENTIALS)
+ public void initCredentials(Credentials credentials)
+ {
+ if (mode.equals(Mode.usernameOnly))
+ {
+ FacesContext ctx = FacesContext.getCurrentInstance();
+ if (ctx != null)
+ {
+ usernameSelector.setCookiePath(ctx.getExternalContext().getRequestContextPath());
+ }
+
+ String username = usernameSelector.getCookieValue();
+ if (username!=null)
+ {
+ setEnabled(true);
+ credentials.setUsername(username);
+ }
+
+ usernameSelector.setDirty();
+ }
+ else if (mode.equals(Mode.autoLogin))
+ {
+ FacesContext ctx = FacesContext.getCurrentInstance();
+ if (ctx != null)
+ {
+ tokenSelector.setCookiePath(ctx.getExternalContext().getRequestContextPath());
+ }
+
+ String token = usernameSelector.getCookieValue();
+ if (token != null)
+ {
+ setEnabled(true);
+
+ DecodedToken decoded = new DecodedToken(token);
+
+ if (tokenStore.validateToken(decoded.getUsername(), decoded.getValue()))
+ {
+ credentials.setUsername(decoded.getUsername());
+ credentials.setPassword(decoded.getValue());
+ }
+ else
+ {
+ // Have we been compromised? Just in case, invalidate all authentication tokens
+ tokenStore.invalidateAll(decoded.getUsername());
+ }
+ }
+ }
+ }
+
+ @Observer(Identity.EVENT_QUIET_LOGIN)
+ public void quietLogin(Identity identity)
+ {
+ if (mode.equals(Mode.autoLogin) && isEnabled())
+ {
+ // Double check our credentials again
+ if (tokenStore.validateToken(identity.getCredentials().getUsername(),
+ identity.getCredentials().getPassword()))
+ {
+ // Success, authenticate the user
+ identity.getSubject().getPrincipals().add(new SimplePrincipal(
+ identity.getCredentials().getUsername()));
+ // And populate the roles
+ for (String role : IdentityManager.instance().getImpliedRoles(
+ identity.getCredentials().getUsername()))
+ {
+ identity.addRole(role);
+ }
+
+ identity.postAuthenticate();
+
+ autoLoggedIn = true;
+ }
+ }
+ }
+
+ @Observer(Identity.EVENT_LOGGED_OUT)
+ public void loggedOut()
+ {
+ if (mode.equals(Mode.autoLogin))
+ {
+ tokenSelector.getCookieValue();
+ }
+ }
+
+ @Observer(Identity.EVENT_POST_AUTHENTICATE)
+ public void postAuthenticate(Identity identity)
+ {
+ if (mode.equals(Mode.usernameOnly))
+ {
+ // Password is set to null during authentication, so we set dirty
+ usernameSelector.setDirty();
+
+ if ( !enabled ) usernameSelector.clearCookieValue();
+ usernameSelector.setCookieValueIfEnabled( Identity.instance().getCredentials().getUsername() );
+ }
+ else if (mode.equals(Mode.autoLogin))
+ {
+ tokenSelector.setDirty();
+
+ DecodedToken decoded = new DecodedToken(tokenSelector.getCookieValue());
+
+ // Invalidate the current token whether enabled or not
+ tokenStore.invalidateToken(decoded.getUsername(), decoded.getValue());
+
+ if ( !enabled )
+ {
+ tokenSelector.clearCookieValue();
+ }
+ else
+ {
+ String value = generateTokenValue();
+ tokenStore.createToken(decoded.getUsername(), value);
+ tokenSelector.setCookieValueIfEnabled(encodeToken(decoded.getUsername(), value));
+ }
+ }
+ }
+
+ @Observer(Credentials.EVENT_CREDENTIALS_UPDATED)
+ public void credentialsUpdated()
+ {
+ usernameSelector.setDirty();
+ }
+
+ /**
+ * A flag that an application can use to protect sensitive operations if the user has been
+ * auto-authenticated.
+ */
+ public boolean isAutoLoggedIn()
+ {
+ return autoLoggedIn;
+ }
+}
\ No newline at end of file
Added: trunk/src/main/org/jboss/seam/security/TokenStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/TokenStore.java (rev 0)
+++ trunk/src/main/org/jboss/seam/security/TokenStore.java 2008-06-06 15:57:22 UTC (rev 8340)
@@ -0,0 +1,15 @@
+package org.jboss.seam.security;
+
+/**
+ * A store containing user authentication tokens. Used in conjunction with the RememberMe
+ * component to auto-login users that present a valid cookie-based token.
+ *
+ * @author Shane Bryzak
+ */
+public interface TokenStore
+{
+ void createToken(String username, String value);
+ boolean validateToken(String username, String value);
+ void invalidateToken(String username, String value);
+ void invalidateAll(String username);
+}
16 years, 7 months