diff --git a/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml b/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml
index b7ab76c41..3f6bc94a3 100644
--- a/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml
+++ b/ccm-bundle-devel-wildfly-web/src/main/resources/log4j2.xml
@@ -9,6 +9,12 @@
+
+
+
+
@@ -19,6 +25,9 @@
level="debug">
+
+
diff --git a/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/web.xml b/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/web.xml
index ac7f9ed0c..4390f3b4e 100644
--- a/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/web.xml
+++ b/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/web.xml
@@ -7,6 +7,12 @@
LibreCCM Devel Bundle for Wildfly
+
+
+ COOKIE
+
+
+
ShiroFilter
org.apache.shiro.web.servlet.ShiroFilter
@@ -15,10 +21,10 @@
ShiroFilter
/*
- REQUEST
+
diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/BebopConfig.java b/ccm-core/src/main/java/com/arsdigita/bebop/BebopConfig.java
index 3ad67cdff..4e3d6fbf7 100755
--- a/ccm-core/src/main/java/com/arsdigita/bebop/BebopConfig.java
+++ b/ccm-core/src/main/java/com/arsdigita/bebop/BebopConfig.java
@@ -28,7 +28,6 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
-import java.util.StringJoiner;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.Configuration;
@@ -83,9 +82,8 @@ public final class BebopConfig {
private Boolean showClassName = false;
public static BebopConfig getConfig() {
- final CdiUtil cdiUtil = new CdiUtil();
- final ConfigurationManager confManager = cdiUtil.findBean(
- ConfigurationManager.class);
+ final ConfigurationManager confManager = CdiUtil.createCdiUtil()
+ .findBean(ConfigurationManager.class);
return confManager.findConfiguration(BebopConfig.class);
}
diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/page/BebopApplicationServlet.java b/ccm-core/src/main/java/com/arsdigita/bebop/page/BebopApplicationServlet.java
index 12e248c1d..ba8a49f7f 100644
--- a/ccm-core/src/main/java/com/arsdigita/bebop/page/BebopApplicationServlet.java
+++ b/ccm-core/src/main/java/com/arsdigita/bebop/page/BebopApplicationServlet.java
@@ -25,7 +25,9 @@ import com.arsdigita.util.Assert;
import com.arsdigita.web.BaseApplicationServlet;
import com.arsdigita.xml.Document;
-import org.apache.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.shiro.subject.Subject;
import org.libreccm.web.CcmApplication;
import java.io.IOException;
@@ -34,6 +36,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import javax.enterprise.inject.spi.CDI;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -61,7 +64,7 @@ public class BebopApplicationServlet extends BaseApplicationServlet {
private static final long serialVersionUID = -6004503025521189639L;
- private static final Logger s_log = Logger.getLogger(
+ private static final Logger LOGGER = LogManager.getLogger(
BebopApplicationServlet.class);
/**
@@ -149,6 +152,11 @@ public class BebopApplicationServlet extends BaseApplicationServlet {
final String pathInfo = sreq.getPathInfo();
Assert.exists(pathInfo, "String pathInfo");
+ final Subject subject = CDI.current().select(Subject.class).get();
+ LOGGER.debug("Current session is: {}", sreq.getSession().getId());
+ LOGGER.debug("Current Shiro session is {}",
+ subject.getSession().getId().toString());
+
final Page page = (Page) m_pages.get(pathInfo);
if (page == null) {
diff --git a/ccm-core/src/main/java/com/arsdigita/kernel/KernelConfig.java b/ccm-core/src/main/java/com/arsdigita/kernel/KernelConfig.java
index 528c5bd0e..5e3f2d79a 100644
--- a/ccm-core/src/main/java/com/arsdigita/kernel/KernelConfig.java
+++ b/ccm-core/src/main/java/com/arsdigita/kernel/KernelConfig.java
@@ -70,9 +70,11 @@ public final class KernelConfig {
private String defaultLanguage = "en";
public static KernelConfig getConfig() {
- final CdiUtil cdiUtil = new CdiUtil();
- final ConfigurationManager confManager = cdiUtil.findBean(
- ConfigurationManager.class);
+// final CdiUtil cdiUtil = new CdiUtil();
+// final ConfigurationManager confManager = cdiUtil.findBean(
+// ConfigurationManager.class);
+ final ConfigurationManager confManager = CdiUtil.createCdiUtil()
+ .findBean(ConfigurationManager.class);
return confManager.findConfiguration(KernelConfig.class);
}
@@ -259,9 +261,10 @@ public final class KernelConfig {
if (supportedLanguages == null) {
languages = "";
} else {
- languages = supportedLanguages.stream().collect(Collectors.joining(", "));
+ languages = supportedLanguages.stream().collect(Collectors.joining(
+ ", "));
}
-
+
return String.format(
"%s{ "
+ "debugEnabled = %b, "
diff --git a/ccm-core/src/main/java/com/arsdigita/kernel/security/SecurityConfig.java b/ccm-core/src/main/java/com/arsdigita/kernel/security/SecurityConfig.java
index c2a302e53..8f609f54d 100644
--- a/ccm-core/src/main/java/com/arsdigita/kernel/security/SecurityConfig.java
+++ b/ccm-core/src/main/java/com/arsdigita/kernel/security/SecurityConfig.java
@@ -56,9 +56,8 @@ public final class SecurityConfig {
private Integer hashIterations = 50000;
public static SecurityConfig getConfig() {
- final CdiUtil cdiUtil = new CdiUtil();
- final ConfigurationManager confManager = cdiUtil.findBean(
- ConfigurationManager.class);
+ final ConfigurationManager confManager = CdiUtil.createCdiUtil()
+ .findBean(ConfigurationManager.class);
return confManager.findConfiguration(SecurityConfig.class);
}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java
index c64f275b1..67b1e1d90 100644
--- a/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java
@@ -30,6 +30,8 @@ import com.arsdigita.web.BaseApplicationServlet;
import com.arsdigita.web.LoginSignal;
import com.arsdigita.xml.Document;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.apache.shiro.subject.Subject;
import org.libreccm.security.PermissionChecker;
import org.libreccm.web.CcmApplication;
@@ -37,15 +39,16 @@ import org.libreccm.web.CcmApplication;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+
import javax.enterprise.inject.spi.CDI;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
-import
+import javax.servlet.http.HttpServletResponse;
- javax.servlet.http.HttpServletResponse;
import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.configuration.ConfigurationManager;
import static com.arsdigita.ui.admin.AdminConstants.*;
@@ -65,12 +68,14 @@ import static com.arsdigita.ui.admin.AdminConstants.*;
* @author pb
*/
@WebServlet(urlPatterns = {ADMIN_SERVLET_PATH})
-public class AdminServlet
+public class AdminServlet
extends BaseApplicationServlet
implements AdminConstants {
private static final long serialVersionUID = -3912367600768871630L;
+ private static final Logger LOGGER = LogManager.getLogger(AdminServlet.class);
+
/**
* Logger instance for debugging
*/
@@ -111,21 +116,40 @@ public class AdminServlet
ServletException, IOException {
// /////// Some preparational steps ///////////////
/* Determine access privilege: only logged in users may access */
- final CdiUtil cdiUtil = new CdiUtil();
+// final CdiUtil cdiUtil = new CdiUtil();
// final Subject subject = cdiUtil.findBean(Subject.class);
final Subject subject = CDI.current().select(Subject.class).get();
- final PermissionChecker permissionChecker = cdiUtil.findBean(
- PermissionChecker.class);
+// final PermissionChecker permissionChecker = cdiUtil.findBean(
+// PermissionChecker.class);
+ final PermissionChecker permissionChecker = CDI.current().select(
+ PermissionChecker.class).get();
+ final ConfigurationManager confManager = CDI.current().select(ConfigurationManager.class).get();
+ if (confManager == null) {
+ throw new IllegalStateException();
+ }
+
+ LOGGER.debug("Checking if subject {} is authenticated...",
+ subject.toString());
+ LOGGER.debug("Current session is: {}", sreq.getSession().getId());
+ LOGGER.debug("Current Shiro session is {}",
+ subject.getSession().getId().toString());
if (!subject.isAuthenticated()) {
+ LOGGER.debug("Subject {} is not authenticated, redirecting to login...",
+ subject.toString());
throw new LoginSignal(sreq);
}
+
/* Determine access privilege: Admin privileges must be granted */
+ LOGGER.debug("Subject is loggedin, checking if subject has required permissions...");
if (!permissionChecker.isPermitted("admin")) {
+ LOGGER.debug("Subject does *not* have required permissions. "
+ + "Access denied.");
throw new AccessDeniedException("User is not an administrator");
}
-
+
+ LOGGER.debug("Serving admin page...");
/* Want admin to always show the latest stuff... */
DispatcherHelper.cacheDisable(sresp);
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/login/ChangePasswordForm.java b/ccm-core/src/main/java/com/arsdigita/ui/login/ChangePasswordForm.java
index fe1772ad8..f8e071845 100644
--- a/ccm-core/src/main/java/com/arsdigita/ui/login/ChangePasswordForm.java
+++ b/ccm-core/src/main/java/com/arsdigita/ui/login/ChangePasswordForm.java
@@ -122,7 +122,7 @@ public class ChangePasswordForm extends Form
m_returnURL.setPassIn(true);
add(m_returnURL);
- final CdiUtil cdiUtil = new CdiUtil();
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final Subject subject = cdiUtil.findBean(Subject.class);
final Shiro shiro = cdiUtil.findBean(Shiro.class);
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/login/UserLoginForm.java b/ccm-core/src/main/java/com/arsdigita/ui/login/UserLoginForm.java
index cfa89236e..2299bd253 100644
--- a/ccm-core/src/main/java/com/arsdigita/ui/login/UserLoginForm.java
+++ b/ccm-core/src/main/java/com/arsdigita/ui/login/UserLoginForm.java
@@ -143,25 +143,27 @@ public class UserLoginForm extends Form implements LoginConstants,
// final ConfigurationManager confManager = CDI.current().select(
// ConfigurationManager.class).get();
- final BeanManager beanManager = CDI.current().getBeanManager();
- final Set> beans = beanManager.getBeans(
- ConfigurationManager.class);
- final Iterator> iterator = beans.iterator();
- final ConfigurationManager confManager;
- if (iterator.hasNext()) {
- @SuppressWarnings("unchecked")
- final Bean bean
- = (Bean) iterator
- .next();
- final CreationalContext ctx = beanManager.
- createCreationalContext(bean);
-
- confManager = (ConfigurationManager) beanManager.getReference(
- bean, ConfigurationManager.class, ctx);
- } else {
- throw new UncheckedWrapperException(
- "Failed to lookup ConfigurationManager");
- }
+// final BeanManager beanManager = CDI.current().getBeanManager();
+// final Set> beans = beanManager.getBeans(
+// ConfigurationManager.class);
+// final Iterator> iterator = beans.iterator();
+// final ConfigurationManager confManager;
+// if (iterator.hasNext()) {
+// @SuppressWarnings("unchecked")
+// final Bean bean
+// = (Bean) iterator
+// .next();
+// final CreationalContext ctx = beanManager.
+// createCreationalContext(bean);
+//
+// confManager = (ConfigurationManager) beanManager.getReference(
+// bean, ConfigurationManager.class, ctx);
+// } else {
+// throw new UncheckedWrapperException(
+// "Failed to lookup ConfigurationManager");
+// }
+ final ConfigurationManager confManager = CdiUtil.createCdiUtil()
+ .findBean(ConfigurationManager.class);
securityConfig = confManager.findConfiguration(SecurityConfig.class);
setMethod(Form.POST);
@@ -385,12 +387,19 @@ public class UserLoginForm extends Form implements LoginConstants,
);
token.setRememberMe(getPersistentLoginValue(state, false));
try {
+ LOGGER.debug("Trying to login user {}...", subject.toString());
subject.login(token);
} catch (AuthenticationException ex) {
onLoginFail(event, ex);
}
LOGGER.debug("User {} logged in successfully.", token.getUsername());
+ LOGGER.debug("subject = {}", subject.toString());
+ LOGGER.debug("Current session is: {}",
+ state.getRequest().getSession().getId());
+ LOGGER.debug("Current Shiro session is {}",
+ subject.getSession().getId().toString());
+
}
/**
diff --git a/ccm-core/src/main/java/com/arsdigita/web/URL.java b/ccm-core/src/main/java/com/arsdigita/web/URL.java
index a9b974b8f..aa542690a 100644
--- a/ccm-core/src/main/java/com/arsdigita/web/URL.java
+++ b/ccm-core/src/main/java/com/arsdigita/web/URL.java
@@ -21,15 +21,28 @@ package com.arsdigita.web;
import com.arsdigita.dispatcher.DispatcherHelper;
//import com.arsdigita.kernel.security.Util;
import com.arsdigita.util.Assert;
+import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.util.servlet.HttpHost;
+import oracle.jrockit.jfr.tools.ConCatRepository;
+
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
+import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.web.CcmApplication;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
/**
*
* URL models a future request according to the servlet worldview. Its principal
@@ -516,8 +529,8 @@ public class URL {
* starts with a "/". For example, "/ccm/forum/thread.jsp".
*
*
- * This method is defined to return the equivalent of * getWebContextPath() + getServletPath() +
- getPathInfo().
+ * This method is defined to return the equivalent of * getWebContextPath() + getServletPath() +
+ * getPathInfo().
*
* @see javax.servlet.http.HttpServletRequest#getRequestURI()
* @return a String comprised of the context path, servlet
@@ -679,7 +692,37 @@ public class URL {
public static final URL there(final HttpServletRequest sreq,
final String path,
final ParameterMap params) {
- final WebConfig config = Web.getConfig();
+ final BeanManager beanManager;
+ try {
+ final InitialContext context = new InitialContext();
+ beanManager = (BeanManager) context.lookup(
+ "java:comp/BeanManager");
+
+ } catch (NamingException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+
+ final Set> beans = beanManager.getBeans(
+ ConfigurationManager.class);
+ final Iterator> iterator = beans.iterator();
+ final ConfigurationManager confManager;
+ if (iterator.hasNext()) {
+ @SuppressWarnings("unchecked")
+ final Bean bean
+ = (Bean) iterator
+ .next();
+ final CreationalContext ctx = beanManager
+ .createCreationalContext(bean);
+ confManager = (ConfigurationManager) beanManager.getReference(
+ bean, ConfigurationManager.class, ctx);
+ } else {
+ throw new IllegalStateException("No configuration manager");
+ }
+
+// final ConfigurationManager confManager = CDI.current().select(
+// ConfigurationManager.class).get();
+ final WebConfig config = confManager.findConfiguration(WebConfig.class);
+// final WebConfig config = Web.getConfig();
Assert.exists(sreq, "HttpServletRequest sreq");
Assert.exists(config, "WebConfig config");
@@ -797,8 +840,8 @@ public class URL {
if (pathInfo == null) {
return URL.there(sreq, app.getPrimaryUrl().toString(), params);
} else {
- return URL.there(sreq, app.getPrimaryUrl().toString() + pathInfo,
- params);
+ return URL.there(sreq, app.getPrimaryUrl().toString() + pathInfo,
+ params);
}
}
@@ -913,7 +956,7 @@ public class URL {
static URL login(final HttpServletRequest sreq) {
//Replace register eventuelly...
- return URL.excursion(sreq,
+ return URL.excursion(sreq,
"/register/",
(ParameterMap) s_empty.get());
}
diff --git a/ccm-core/src/main/java/com/arsdigita/web/WebConfig.java b/ccm-core/src/main/java/com/arsdigita/web/WebConfig.java
index 03781ef07..1a5052d7c 100644
--- a/ccm-core/src/main/java/com/arsdigita/web/WebConfig.java
+++ b/ccm-core/src/main/java/com/arsdigita/web/WebConfig.java
@@ -84,29 +84,32 @@ public final class WebConfig {
private String dynamicHostProviderClass;
public static WebConfig getConfig() {
- final BeanManager beanManager = CDI.current().getBeanManager();
- final Set> beans = beanManager.getBeans(
- ConfigurationManager.class);
- final Iterator> iterator = beans.iterator();
- final ConfigurationManager confManager;
- if (iterator.hasNext()) {
- @SuppressWarnings("unchecked")
- final Bean bean
- = (Bean) iterator
- .next();
- final CreationalContext ctx = beanManager
- .createCreationalContext(bean);
+ final ConfigurationManager confManager = CDI.current().select(
+ ConfigurationManager.class).get();
- confManager = (ConfigurationManager) beanManager.getReference(
- bean, ConfigurationManager.class, ctx);
- } else {
- LOGGER.error(new ParameterizedMessage(
- "No CDI Bean for type {} found.",
- ConfigurationManager.class.getName()));
- throw new IllegalStateException(String.format(
- "No CDI Bean for type \"%s\" found",
- ConfigurationManager.class.getName()));
- }
+// final BeanManager beanManager = CDI.current().getBeanManager();
+// final Set> beans = beanManager.getBeans(
+// ConfigurationManager.class);
+// final Iterator> iterator = beans.iterator();
+// final ConfigurationManager confManager;
+// if (iterator.hasNext()) {
+// @SuppressWarnings("unchecked")
+// final Bean bean
+// = (Bean) iterator
+// .next();
+// final CreationalContext ctx = beanManager
+// .createCreationalContext(bean);
+//
+// confManager = (ConfigurationManager) beanManager.getReference(
+// bean, ConfigurationManager.class, ctx);
+// } else {
+// LOGGER.error(new ParameterizedMessage(
+// "No CDI Bean for type {} found.",
+// ConfigurationManager.class.getName()));
+// throw new IllegalStateException(String.format(
+// "No CDI Bean for type \"%s\" found",
+// ConfigurationManager.class.getName()));
+// }
// final CdiUtil cdiUtil = new CdiUtil();
// final ConfigurationManager confManager = cdiUtil.findBean(
diff --git a/ccm-core/src/main/java/org/libreccm/categorization/Domain.java b/ccm-core/src/main/java/org/libreccm/categorization/Domain.java
index 0db23b929..70b4a9aa4 100644
--- a/ccm-core/src/main/java/org/libreccm/categorization/Domain.java
+++ b/ccm-core/src/main/java/org/libreccm/categorization/Domain.java
@@ -24,9 +24,9 @@ import static org.libreccm.core.CoreConstants.*;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.URL;
import org.libreccm.core.CcmObject;
+import org.libreccm.core.DefaultEntityGraph;
import org.libreccm.l10n.LocalizedString;
import org.libreccm.web.CcmApplication;
-import org.omg.CORBA.DomainManager;
import java.io.Serializable;
import java.util.ArrayList;
@@ -91,6 +91,7 @@ import javax.xml.bind.annotation.XmlRootElement;
@NamedAttributeNode("subCategories")
})})
})
+@DefaultEntityGraph("Domain.allCategories")
@XmlRootElement(name = "domain", namespace = CAT_XML_NS)
public class Domain extends CcmObject implements Serializable {
diff --git a/ccm-core/src/main/java/org/libreccm/cdi/utils/CdiUtil.java b/ccm-core/src/main/java/org/libreccm/cdi/utils/CdiUtil.java
index b8cc28630..640c2934f 100644
--- a/ccm-core/src/main/java/org/libreccm/cdi/utils/CdiUtil.java
+++ b/ccm-core/src/main/java/org/libreccm/cdi/utils/CdiUtil.java
@@ -29,6 +29,8 @@ import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
/**
*
@@ -43,7 +45,24 @@ public class CdiUtil {
public CdiUtil() {
beanManager = CDI.current().getBeanManager();
}
+
+ private CdiUtil(final BeanManager beanManager) {
+ this.beanManager = beanManager;
+ }
+ public static CdiUtil createCdiUtil() {
+ try {
+ final InitialContext context = new InitialContext();
+ final BeanManager beanManager = (BeanManager) context.lookup(
+ "java:comp/BeanManager");
+ return new CdiUtil(beanManager);
+ } catch(NamingException ex) {
+ throw new IllegalStateException("Unable to lookup BeanManager.", ex);
+ }
+
+
+ }
+
@SuppressWarnings("unchecked")
public T findBean(final Class beanType) {
final Set> beans = beanManager.getBeans(beanType);
diff --git a/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java b/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java
index 3ded6522f..03b98980d 100644
--- a/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java
@@ -18,13 +18,18 @@
*/
package org.libreccm.core;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import javax.inject.Inject;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
+import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
@@ -39,7 +44,11 @@ import javax.persistence.criteria.Root;
*/
public abstract class AbstractEntityRepository {
- static final String FETCH_GRAPH_HINT_KEY = "javax.persistence.fetchgraph";
+ private static final Logger LOGGER = LogManager.getLogger(
+ AbstractEntityRepository.class);
+
+ protected static final String FETCH_GRAPH_HINT_KEY
+ = "javax.persistence.fetchgraph";
/**
* The {@link EntityManager} instance to use. Provided by the container via
@@ -57,12 +66,99 @@ public abstract class AbstractEntityRepository {
return entityManager;
}
+ /**
+ * Create an {@link EntityGraph} for the entity class of this repository.
+ *
+ * For more details about entity graphs/fetch graphs refer to the JPA
+ * documentation. Internally this method uses
+ * {@link EntityManager#createEntityGraph(java.lang.Class)}.
+ *
+ * @return An EntityGraph for this entity graph.
+ */
+ public EntityGraph createEntityGraph() {
+ return entityManager.createEntityGraph(getEntityClass());
+ }
+
+ protected void applyDefaultEntityGraph(final TypedQuery query) {
+ if (getEntityClass().isAnnotationPresent(DefaultEntityGraph.class)) {
+ LOGGER.debug("The following EntityGraphs are available for the "
+ + "entity class {}:",
+ getEntityClass().getName());
+ getEntityManager().getEntityGraphs(getEntityClass()).stream()
+ .forEach(g -> LOGGER.debug("\t{}", g.getName()));
+ LOGGER.debug("Entity class {} has default entity graphs:",
+ getEntityClass().getName());
+ LOGGER.debug("Applying entity graph {}",
+ getEntityClass().getAnnotation(
+ DefaultEntityGraph.class).value());
+ query.setHint(FETCH_GRAPH_HINT_KEY,
+ entityManager.getEntityGraph(
+ getEntityClass().getAnnotation(
+ DefaultEntityGraph.class).value()));
+ }
+ }
+
+ /**
+ * Helper method for retrieving a single result from a query.
+ *
+ * @param query The query from which the result is retrieved.
+ *
+ * @return A first result or the query or {@code null} of there is no
+ * result.
+ */
+ protected E getSingleResultOrNull(final TypedQuery query) {
+ final List result = query.getResultList();
+ if (result.isEmpty()) {
+ return null;
+ } else {
+ return result.get(0);
+ }
+ }
+
+ /**
+ * Helper method for retrieving a single result from a query. In contrast to
+ * {@link #getSingleResultOrNull(javax.persistence.TypedQuery)} this method
+ * return an {@link Optional} for the result.
+ *
+ * @param query The query from which the result is retrieved.
+ *
+ * @return An {@link Optional} instance wrapping the first result of the
+ * query. If there is no result the {@code Optional} is empty.
+ */
+ protected Optional getSingleResult(final TypedQuery query) {
+ final List result = query.getResultList();
+ if (result.isEmpty()) {
+ return Optional.empty();
+ } else {
+ return Optional.of(result.get(0));
+ }
+ }
+
+ /**
+ * Creates a mutable copy of a named entity graph which an be further
+ * customised.
+ *
+ * Internally this method uses
+ * {@link EntityManager#createEntityGraph(java.lang.String)}.
+ *
+ * @param entityGraphName The name of the named entity graph.
+ *
+ * @return A mutable copy of the named entity graph identified by the
+ * provided name or {@code null} if there is no such named entity
+ * graph.
+ */
+ @SuppressWarnings("unchecked")
+ public EntityGraph createEntityGraph(final String entityGraphName) {
+ return (EntityGraph) entityManager.createEntityGraph(
+ entityGraphName);
+ }
+
/**
* The class of entities for which this repository can be used. For creating
* a repository class overwrite this method.
*
* @return The {@code Class} of the Entity which are managed by this
- * repository.
+ * repository.
*/
public abstract Class getEntityClass();
@@ -72,15 +168,21 @@ public abstract class AbstractEntityRepository {
* @param entityId The ID of the entity to retrieve.
*
* @return The entity identified by the provided ID of {@code null} if there
- * is no such entity.
+ * is no such entity.
*/
public E findById(final K entityId) {
- return entityManager.find(getEntityClass(), entityId);
+ if (getEntityClass().isAnnotationPresent(DefaultEntityGraph.class)) {
+ return findById(entityId, getEntityClass().getAnnotation(
+ DefaultEntityGraph.class).value());
+ } else {
+ return entityManager.find(getEntityClass(), entityId);
+ }
}
public E findById(final K entityId, final String entityGraphName) {
+ @SuppressWarnings("unchecked")
final EntityGraph entityGraph = (EntityGraph) entityManager.
- getEntityGraph(entityGraphName);
+ getEntityGraph(entityGraphName);
return findById(entityId, entityGraph);
}
@@ -95,15 +197,15 @@ public abstract class AbstractEntityRepository {
* responsible for.
*
* @return The list of entities in the database which are of the type
- * provided by {@link #getEntityClass()}.
+ * provided by {@link #getEntityClass()}.
*/
public List findAll() {
// We are using the Critiera API here because otherwise we can't
// pass the type of the entity dynmacially.
final CriteriaBuilder criteriaBuilder = entityManager
- .getCriteriaBuilder();
+ .getCriteriaBuilder();
final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(
- getEntityClass());
+ getEntityClass());
final Root root = criteriaQuery.from(getEntityClass());
criteriaQuery.select(root);
@@ -117,8 +219,9 @@ public abstract class AbstractEntityRepository {
* entity is a a new one.
*
* @param entity The entity to check.
+ *
* @return {@code true} if the entity is new (isn't in the database yet),
- * {@code false} otherwise.
+ * {@code false} otherwise.
*/
public abstract boolean isNew(final E entity);
diff --git a/ccm-core/src/main/java/org/libreccm/core/DefaultEntityGraph.java b/ccm-core/src/main/java/org/libreccm/core/DefaultEntityGraph.java
new file mode 100644
index 000000000..2b90c28bf
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/core/DefaultEntityGraph.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.core;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.*;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Target({TYPE})
+public @interface DefaultEntityGraph {
+
+ String value();
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/security/Party.java b/ccm-core/src/main/java/org/libreccm/security/Party.java
index c5cba8d6b..32c544fb8 100644
--- a/ccm-core/src/main/java/org/libreccm/security/Party.java
+++ b/ccm-core/src/main/java/org/libreccm/security/Party.java
@@ -20,6 +20,8 @@ package org.libreccm.security;
import static org.libreccm.core.CoreConstants.*;
+import org.libreccm.core.DefaultEntityGraph;
+
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
@@ -33,6 +35,9 @@ import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
+import javax.persistence.NamedAttributeNode;
+import javax.persistence.NamedEntityGraph;
+import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
@@ -56,6 +61,12 @@ import javax.xml.bind.annotation.XmlElementWrapper;
@NamedQuery(name = "Party.findByName",
query = "SELECT p FROM Party p WHERE p.name = :name")
})
+@NamedEntityGraphs({
+ @NamedEntityGraph(name = "Party.withRoleMemberships",
+ attributeNodes = @NamedAttributeNode(
+ value = "roleMemberships"))
+})
+@DefaultEntityGraph("Party.withRoleMemberships")
public class Party implements Serializable {
private static final long serialVersionUID = 3319997992281332204L;
diff --git a/ccm-core/src/main/java/org/libreccm/security/Shiro.java b/ccm-core/src/main/java/org/libreccm/security/Shiro.java
index b90dee548..cbf2310a9 100644
--- a/ccm-core/src/main/java/org/libreccm/security/Shiro.java
+++ b/ccm-core/src/main/java/org/libreccm/security/Shiro.java
@@ -62,7 +62,8 @@ public class Shiro {
@Produces
@Named("securityManager")
public SecurityManager getSecurityManager() {
- return proxy(SecurityManager.class, new SubjectInvocationHandler());
+ return proxy(SecurityManager.class,
+ new SecurityManagerInvocationHandler());
}
/**
@@ -115,6 +116,7 @@ public class Shiro {
return publicUser;
}
+ @SuppressWarnings("unchecked")
private T proxy(final Class clazz, final InvocationHandler handler) {
return (T) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class>[]{clazz},
diff --git a/ccm-core/src/main/java/org/libreccm/security/User.java b/ccm-core/src/main/java/org/libreccm/security/User.java
index 44d5f1848..e92577363 100644
--- a/ccm-core/src/main/java/org/libreccm/security/User.java
+++ b/ccm-core/src/main/java/org/libreccm/security/User.java
@@ -20,6 +20,7 @@ package org.libreccm.security;
import static org.libreccm.core.CoreConstants.*;
+import org.libreccm.core.DefaultEntityGraph;
import org.libreccm.core.EmailAddress;
import java.io.Serializable;
@@ -37,9 +38,13 @@ import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
+import javax.persistence.NamedAttributeNode;
+import javax.persistence.NamedEntityGraph;
+import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
+import javax.persistence.OrderColumn;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlElement;
@@ -59,9 +64,18 @@ import javax.xml.bind.annotation.XmlTransient;
@NamedQuery(name = "User.findByName",
query = "SELECT u FROM User u WHERE u.name = :name"),
@NamedQuery(name = "User.findByEmailAddress",
- query = "SELECT u FROM User u WHERE " +
- "u.primaryEmailAddress.address = :emailAddress")
+ query = "SELECT u FROM User u WHERE "
+ + "u.primaryEmailAddress.address = :emailAddress")
})
+@NamedEntityGraphs({
+ @NamedEntityGraph(name = "User.withGroupAndRoleMemberships",
+ attributeNodes = {
+ @NamedAttributeNode(
+ value = "groupMemberships"),
+ @NamedAttributeNode(
+ value = "roleMemberships")})
+})
+@DefaultEntityGraph("User.withGroupAndRoleMemberships")
@XmlRootElement(name = "user", namespace = CORE_XML_NS)
//Supressing a few warnings from PMD because they misleading here.
//User is perfectly fine class name, and the complexity is not to high...
@@ -112,9 +126,9 @@ public class User extends Party implements Serializable {
private List emailAddresses;
/**
- * A user can be banned which means that he or she can't login into
- * the system anymore. We use this approach rather than simply deleting users
- * to preserve the edit history of several objects.
+ * A user can be banned which means that he or she can't login into the
+ * system anymore. We use this approach rather than simply deleting users to
+ * preserve the edit history of several objects.
*/
@Column(name = "BANNED")
@XmlElement(name = "banned", namespace = CORE_XML_NS)
diff --git a/ccm-core/src/main/java/org/libreccm/security/UserRepository.java b/ccm-core/src/main/java/org/libreccm/security/UserRepository.java
index 693a1c98d..41c523895 100644
--- a/ccm-core/src/main/java/org/libreccm/security/UserRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/security/UserRepository.java
@@ -21,8 +21,10 @@ package org.libreccm.security;
import org.libreccm.core.AbstractEntityRepository;
import java.util.List;
+import java.util.Optional;
import javax.enterprise.context.RequestScoped;
+import javax.persistence.EntityGraph;
import javax.persistence.TypedQuery;
/**
@@ -52,20 +54,59 @@ public class UserRepository extends AbstractEntityRepository {
* @param name The name of the user to find.
*
* @return The user identified by the provided name. If there are multiple
- * user matching the user name (should be possible) the first one is
- * returned. If there is no matching user {@code null} is returned.
+ * user matching the user name (should be possible) the first one is
+ * returned. If there is no matching user {@code null} is returned.
*/
public User findByName(final String name) {
final TypedQuery query = getEntityManager().createNamedQuery(
- "User.findByName",
- User.class);
+ "User.findByName", User.class);
+ applyDefaultEntityGraph(query);
query.setParameter("name", name);
- final List result = query.getResultList();
- if (result.isEmpty()) {
- return null;
- } else {
- return result.get(0);
- }
+
+ return getSingleResultOrNull(query);
+
+// final List result = query.getResultList();
+// if (result.isEmpty()) {
+// return null;
+// } else {
+// return result.get(0);
+// }
+ }
+
+ /**
+ * Finds a user by its name and applies the given named entity graph to the
+ * query.
+ *
+ * @param name The name of the user to find.
+ * @param entityGraphName The named entity graph to use.
+ *
+ * @return The user identified by the provided name. If there are multiple
+ * user matching the user name (should be possible) the first one is
+ * returned. If there is no matching user {@code null} is returned.
+ */
+ public User findByName(final String name, final String entityGraphName) {
+ @SuppressWarnings("unchecked")
+ final EntityGraph entityGraph
+ = (EntityGraph) getEntityManager()
+ .getEntityGraph(entityGraphName);
+ return findByName(name, entityGraph);
+ }
+
+ public User findByName(final String name,
+ final EntityGraph entityGraph) {
+ final TypedQuery query = getEntityManager().createNamedQuery(
+ "User.findByName", User.class);
+ query.setParameter("name", name);
+ query.setHint(FETCH_GRAPH_HINT_KEY, entityGraph);
+
+ return getSingleResultOrNull(query);
+
+// final List result = query.getResultList();
+// if (result.isEmpty()) {
+// return null;
+// } else {
+// return result.get(0);
+// }
}
/**
@@ -74,19 +115,42 @@ public class UserRepository extends AbstractEntityRepository {
* @param emailAddress The email address which identifies the user.
*
* @return The user identified by the provided email address. If there are
- * multiple matching users only the first one is returned. If there is no
- * matching user {@code null} is returned.
+ * multiple matching users only the first one is returned. If there
+ * is no matching user {@code null} is returned.
*/
public User findByEmailAddress(final String emailAddress) {
final TypedQuery query = getEntityManager().createNamedQuery(
- "User.findByEmailAddress", User.class);
+ "User.findByEmailAddress", User.class);
query.setParameter("emailAddress", emailAddress);
- final List result = query.getResultList();
- if (result.isEmpty()) {
- return null;
- } else {
- return result.get(0);
- }
+ applyDefaultEntityGraph(query);
+
+ return getSingleResultOrNull(query);
+
+// final List result = query.getResultList();
+// if (result.isEmpty()) {
+// return null;
+// } else {
+// return result.get(0);
+// }
}
-
+
+ public User findByEmailAddress(final String emailAddress,
+ final String entityGraphName) {
+ @SuppressWarnings("unchecked")
+ final EntityGraph entityGraph
+ = (EntityGraph) getEntityManager()
+ .getEntityGraph(entityGraphName);
+ return findByEmailAddress(emailAddress, entityGraph);
+ }
+
+ public User findByEmailAddress(final String emailAddress,
+ final EntityGraph entityGraph) {
+ final TypedQuery query = getEntityManager().createNamedQuery(
+ "User.findByEmailAddress", User.class);
+ query.setParameter("emailAddress", emailAddress);
+ query.setHint(FETCH_GRAPH_HINT_KEY, entityGraph);
+
+ return getSingleResultOrNull(query);
+ }
+
}