package org.jboss.seam.wiki.core.dao;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.*;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.wiki.core.action.prefs.UserManagementPreferences;
import org.jboss.seam.wiki.core.model.Role;
import org.jboss.seam.wiki.core.model.User;
import org.jboss.seam.wiki.preferences.Preferences;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Name("userRoleAccessFactory")
public class UserRoleAccessFactory implements Serializable {
@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)
@BypassInterceptors // Don't inject the entityManager, this factory is called when the entityManager is created!
public Integer getCurrentAccessLevel() {
return Role.GUESTROLE_ACCESSLEVEL;
}
@Factory(value = "guestUser", scope = ScopeType.SESSION)
public User getGuestUser() {
try {
/*
This causes the following warning in Hibernate 3.3:
WARN [org.hibernate.hql.ast.QueryTranslatorImpl] firstResult/maxResults specified with collection fetch; applying in memory!
Of course that is just wrong and it looks like this warning was added in a hurry between 3.2 and 3.3. Or this is not the
query that is causing the warning - who knows! It probably would have been too easy printing the offending query string
with the message...
*/
User guestUser =
(User) entityManager
.createQuery("select u from User u left join fetch u.roles where u.username = '"+User.GUEST_USERNAME+"'")
.setHint("org.hibernate.cacheable", true)
.getSingleResult();
if (guestUser.getRoles().size() > 1 || guestUser.getRoles().size() == 0) {
throw new RuntimeException("Your '"+User.GUEST_USERNAME+"' user has none or more than one role assigned, illegal database state");
}
if (guestUser.getRoles().iterator().next().getAccessLevel() != Role.GUESTROLE_ACCESSLEVEL) {
throw new RuntimeException("Your '"+User.GUEST_USERNAME+"' user isn't assigned to the guest role (access level "+Role.GUESTROLE_ACCESSLEVEL+")");
}
return guestUser;
} catch (NoResultException ex) {
throw new RuntimeException("You need to INSERT a user with username '"+User.GUEST_USERNAME+"' into the database");
}
}
@Factory(value = "adminUser", scope = ScopeType.SESSION)
public User getAdminUser() {
try {
User adminUser =
(User) entityManager
.createQuery("select u from User u left join fetch u.roles where u.username = '"+User.ADMIN_USERNAME+"'")
.setHint("org.hibernate.cacheable", true)
.getSingleResult();
if (adminUser.getRoles().size() > 1 || adminUser.getRoles().size() == 0) {
throw new RuntimeException("Your '"+User.ADMIN_USERNAME+"' user has none or more than one role assigned, illegal database state");
}
if (adminUser.getRoles().iterator().next().getAccessLevel() != Role.ADMINROLE_ACCESSLEVEL) {
throw new RuntimeException("Your '"+User.ADMIN_USERNAME+"' user isn't assigned to the admin role (access level "+Role.ADMINROLE_ACCESSLEVEL+")");
}
return adminUser;
} catch (NoResultException ex) {
throw new RuntimeException("You need to INSERT a user with username '"+User.ADMIN_USERNAME+"' into the database");
}
}
@Factory(value = "guestRole", scope = ScopeType.SESSION)
public Role getGuestRole() {
try {
return (Role) entityManager
.createQuery("select r from Role r where r.accessLevel = '"+Role.GUESTROLE_ACCESSLEVEL+"'")
.setHint("org.hibernate.cacheable", true)
.getSingleResult();
} catch (NoResultException ex) {
throw new RuntimeException("You need to INSERT a role with accesslevel '"+Role.GUESTROLE_ACCESSLEVEL+"' (the guest role) into the database");
}
}
@Factory(value = "adminRole", scope = ScopeType.SESSION)
public Role getAdminRole() {
try {
return (Role) entityManager
.createQuery("select r from Role r where r.accessLevel = '"+Role.ADMINROLE_ACCESSLEVEL+"'")
.setHint("org.hibernate.cacheable", true)
.getSingleResult();
} catch (NoResultException ex) {
throw new RuntimeException("You need to INSERT a role with accesslevel '"+Role.ADMINROLE_ACCESSLEVEL+"' (the admin role) into the database");
}
}
@Factory(value = "newUserDefaultRole", scope = ScopeType.SESSION)
public Role getDefaultRole() {
UserManagementPreferences userPrefs = Preferences.instance().get(UserManagementPreferences.class);
try {
return (Role) entityManager
.createQuery("select r from Role r where r.name = '"+userPrefs.getNewUserInRole()+"'")
.setHint("org.hibernate.cacheable", true)
.getSingleResult();
} catch (NoResultException ex) {
throw new RuntimeException("Configured default role for new users '"+userPrefs.getNewUserInRole()+"' not found");
}
}
/**
* A <tt>List</tt> of all roles in the system.
*/
@Name("rolesList")
@Scope(ScopeType.CONVERSATION)
@AutoCreate
public static class RoleList implements Serializable {
@In
protected EntityManager entityManager;
protected List<Role> roles;
@Unwrap
@SuppressWarnings({"unchecked"})
public List<Role> getRoles() {
if (roles == null) {
roles = (List<Role>) entityManager
.createQuery("select r from Role r order by r.accessLevel desc, r.displayName asc")
.setHint("org.hibernate.cacheable", true)
.getResultList();
if (roles.size() < 2)
throw new RuntimeException("You need to INSERT at least two roles into the database, " +
"with access level '"+Role.GUESTROLE_ACCESSLEVEL+"' and '"+Role.ADMINROLE_ACCESSLEVEL+"'");
}
return roles;
}
}
/**
* Aggregates role names with access level integers, e.g.
* <pre>
* Access Level, Role Name
* 1 Foo
* 2 Bar
* 2 Baz
* 1000 Admin
* </pre>
* is aggregated for display into
* <pre>
* Access Level, Role Name
* 1 Foo
* 2 Bar, Baz
* 1000 Owner, Admin
* </pre>
*/
@Name("accessLevelsList")
@Scope(ScopeType.CONVERSATION)
@AutoCreate
public static class AccessLevelsList implements Serializable {
@In
List<Role> rolesList;
List<Role.AccessLevel> accessLevelsList;
@Unwrap
public List<Role.AccessLevel> getAccessLevelList() {
if (accessLevelsList == null) {
accessLevelsList = new ArrayList<Role.AccessLevel>(rolesList.size());
for (Role role : rolesList) {
// Create an access level object, append fake role name "Owner" if the
// access level is the superuser level
Role.AccessLevel newAccessLevel =
new Role.AccessLevel(
role.getAccessLevel(),
role.getAccessLevel() == Role.ADMINROLE_ACCESSLEVEL
? "Owner, " + role.getDisplayName()
: role.getDisplayName()
);
// Put into list, if this level already exists only append the role names
if (accessLevelsList.contains(newAccessLevel)) {
Role.AccessLevel existingAccessLevel =
accessLevelsList.get(accessLevelsList.indexOf(newAccessLevel));
existingAccessLevel.appendRoleName(newAccessLevel.getRoleNames());
} else {
accessLevelsList.add(newAccessLevel);
}
}
}
return accessLevelsList;
}
}
/**
* AccessLevel's that can be assigned by the current user, e.g. when editing a document.
*/
@Name("assignableAccessLevelsList")
@Scope(ScopeType.CONVERSATION)
@AutoCreate
public static class AssignableAccessLevelsList implements Serializable {
@In
List<Role.AccessLevel> accessLevelsList;
@In
Integer currentAccessLevel;
List<Role.AccessLevel> assignableAccessLevelsList;
@Unwrap
public List<Role.AccessLevel> getAssignableAccessLevelList() {
if (assignableAccessLevelsList == null) {
assignableAccessLevelsList = new ArrayList<Role.AccessLevel>(accessLevelsList.size());
for (Role.AccessLevel accessLevel : accessLevelsList) {
// Only make access levels assignable if the current user has at least this access level
if (accessLevel.getAccessLevel() <= currentAccessLevel)
assignableAccessLevelsList.add(accessLevel);
}
}
return assignableAccessLevelsList;
}
}
}