From 80479cde9f35a176926fc68d22714479bc4fea74 Mon Sep 17 00:00:00 2001 From: jensp Date: Mon, 23 Oct 2017 17:08:52 +0000 Subject: [PATCH] CCM NG: - Several bug fixes for potenial bugs found by FindBugs - Created StaticThemeProvider class git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5075 8810af33-2d31-482b-a856-94f89814c4df --- .../roles/RolesController.java | 34 +-- .../categorization/CategoryRepository.java | 2 +- .../configuration/ConfigurationManager.java | 23 ++- .../core/AbstractEntityRepository.java | 61 +++--- .../libreccm/files/NIOFileSystemAdapter.java | 20 +- .../libreccm/l10n/GlobalizationHelper.java | 12 +- .../l10n/ui/LocalizedStringEditor.java | 15 +- .../pagemodel/ComponentRendererManager.java | 2 +- .../libreccm/pagemodel/ui/PageTreeModel.java | 2 +- .../libreccm/security/PartyRepository.java | 4 +- .../libreccm/security/PermissionManager.java | 12 +- .../org/libreccm/security/RoleManager.java | 13 +- .../org/libreccm/security/RoleRepository.java | 2 + .../java/org/libreccm/security/Shiro.java | 22 +- .../main/java/org/libreccm/sites/Site.java | 4 + .../libreccm/theming/StaticThemeProvider.java | 195 ++++++++++++++++++ .../java/org/libreccm/theming/Themes.java | 2 +- .../libreccm/ui/LocalizedStringWidget.java | 4 +- .../ui/LocalizedStringWidgetController.java | 30 +-- .../org/libreccm/ui/TextEditorBuilder.java | 4 +- .../ui/admin/UserContextController.java | 2 +- .../main/java/org/libreccm/workflow/Task.java | 8 +- 22 files changed, 360 insertions(+), 113 deletions(-) create mode 100644 ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RolesController.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RolesController.java index b956bc746..6ca759966 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RolesController.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RolesController.java @@ -7,6 +7,7 @@ import org.libreccm.security.RoleManager; import org.libreccm.security.RoleMembership; import org.libreccm.security.RoleRepository; +import java.io.Serializable; import java.util.List; import java.util.stream.Collectors; @@ -19,17 +20,19 @@ import javax.transaction.Transactional; * @author Jens Pelzetter */ @RequestScoped -public class RolesController { - +public class RolesController implements Serializable { + + private static final long serialVersionUID = 4127664283856716723L; + @Inject private PartyRepository partyRepo; - + @Inject private RoleRepository roleRepo; - + @Inject private RoleManager roleManager; - + @Transactional(Transactional.TxType.REQUIRED) protected List getMembersOfRole(final Role role) { @@ -46,10 +49,10 @@ public class RolesController { .sorted((role1, role2) -> role1.getName().compareTo(role2.getName())) .collect(Collectors.toList()); } - + @Transactional(Transactional.TxType.REQUIRED) protected List getNamesOfMembersOfRole(final Role role) { - + final Role theRole = roleRepo .findById(role.getRoleId()) .orElseThrow(() -> new IllegalArgumentException(String @@ -63,26 +66,25 @@ public class RolesController { .map(Party::getName) .sorted((name1, name2) -> name1.compareTo(name2)) .collect(Collectors.toList()); - + } - + @Transactional(Transactional.TxType.REQUIRED) protected void assignRoleToParty(final Role role, final Party party) { - + final Party assignee = partyRepo - .findById(party.getPartyId()) - .orElseThrow(() -> new IllegalArgumentException(String + .findById(party.getPartyId()) + .orElseThrow(() -> new IllegalArgumentException(String .format("No Party with ID %d in the database.", party.getPartyId()))); - + final Role assignTo = roleRepo .findById(role.getRoleId()) .orElseThrow(() -> new IllegalArgumentException(String .format("No Role with ID %d in the database.", role.getRoleId()))); - + roleManager.assignRoleToParty(assignTo, assignee); } - + } - \ No newline at end of file diff --git a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java index 3bed87421..9251a0320 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java @@ -163,7 +163,7 @@ public class CategoryRepository extends AbstractEntityRepository final String[] tokens = normalizedPath.split("/"); Category current = domain.getRoot(); for (final String token : tokens) { - if (current.getSubCategories() == null) { + if (current.getSubCategories().isEmpty()) { return Optional.empty(); } final Optional result = current.getSubCategories() diff --git a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java index aba86b151..292c61b86 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java @@ -27,11 +27,20 @@ import org.libreccm.modules.Module; import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.RequiresPrivilege; +import java.io.Serializable; + import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.transaction.Transactional; + import java.lang.reflect.Field; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.stream.Collectors; /** @@ -40,7 +49,9 @@ import java.util.stream.Collectors; * @author Jens Pelzetter */ @RequestScoped -public class ConfigurationManager { +public class ConfigurationManager implements Serializable { + + private static final long serialVersionUID = 5453012565110339303L; private static final Logger LOGGER = LogManager.getLogger( ConfigurationManager.class); @@ -50,7 +61,7 @@ public class ConfigurationManager { @Inject private SettingConverter settingConverter; - + /** * Map used to cache configuration during a request. */ @@ -190,7 +201,7 @@ public class ConfigurationManager { ex); } } - + /** * If the configuration is cached remove the cached version. */ @@ -360,7 +371,7 @@ public class ConfigurationManager { final Map settings = settingList.stream() .collect(Collectors.toMap(setting -> setting.getName(), setting -> setting)); - + final Field[] fields = confClass.getDeclaredFields(); for (final Field field : fields) { field.setAccessible(true); @@ -378,7 +389,7 @@ public class ConfigurationManager { settingName, setting.getValue()); field.set(conf, setting.getValue()); - } catch(IllegalAccessException ex) { + } catch (IllegalAccessException ex) { LOGGER.warn( "Failed to set value of configuration class \"{}\". " + "Ignoring.", 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 0bce27bea..1af0b12ee 100644 --- a/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java +++ b/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java @@ -18,8 +18,13 @@ */ package org.libreccm.core; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import javax.inject.Inject; import javax.persistence.EntityGraph; @@ -29,7 +34,6 @@ import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import javax.transaction.Transactional; -import java.util.*; /** * A base class providing common method needed by every repository. @@ -38,13 +42,12 @@ import java.util.*; * @param Type of the primary key of the entity * @param Type of the entity. */ -public abstract class AbstractEntityRepository { +public abstract class AbstractEntityRepository implements Serializable { - private static final Logger LOGGER = LogManager.getLogger( - AbstractEntityRepository.class); + private static final long serialVersionUID = 8462548002420023652L; protected static final String FETCH_GRAPH_HINT_KEY - = "javax.persistence.fetchgraph"; + = "javax.persistence.fetchgraph"; /** * The {@link EntityManager} instance to use. Provided by the container via @@ -83,7 +86,7 @@ public abstract class AbstractEntityRepository { * @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. + * query. If there is no result the {@code Optional} is empty. */ protected Optional getSingleResult(final TypedQuery query) { final List result = query.getResultList(); @@ -104,12 +107,13 @@ public abstract class AbstractEntityRepository { * @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. + * 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); + entityGraphName); } /** @@ -117,7 +121,7 @@ public abstract class AbstractEntityRepository { * a repository class overwrite this method. * * @return The {@code Class} of the Entity which are managed by this - * repository. + * repository. */ public abstract Class getEntityClass(); @@ -127,28 +131,29 @@ public abstract class AbstractEntityRepository { * @param entityId The ID of the entity to retrieve. * * @return An {@link Optional} containing the entity identified by the - * provided ID or am empty {@link Optional} if there is no such entity. + * provided ID or am empty {@link Optional} if there is no such + * entity. */ @Transactional(Transactional.TxType.REQUIRED) public Optional findById(final K entityId) { - + return Optional.ofNullable(entityManager.find(getEntityClass(), entityId)); } @Transactional(Transactional.TxType.REQUIRED) public Optional findById(final K entityId, final String entityGraphName) { - + @SuppressWarnings("unchecked") final EntityGraph entityGraph = (EntityGraph) entityManager. - getEntityGraph(entityGraphName); + getEntityGraph(entityGraphName); return findById(entityId, entityGraph); } @Transactional(Transactional.TxType.REQUIRED) public Optional findById(final K entityId, final EntityGraph entityGraph) { - + final Map hints = new HashMap<>(); hints.put(FETCH_GRAPH_HINT_KEY, entityGraph); return Optional.ofNullable(entityManager.find(getEntityClass(), @@ -161,7 +166,7 @@ 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()}. */ @Transactional(Transactional.TxType.REQUIRED) public List findAll() { @@ -174,7 +179,7 @@ public abstract class AbstractEntityRepository { public List findAll(final String entityGraphName) { @SuppressWarnings("unchecked") final EntityGraph entityGraph = (EntityGraph) entityManager - .getEntityGraph(entityGraphName); + .getEntityGraph(entityGraphName); return findAll(entityGraph); } @@ -188,9 +193,9 @@ public abstract class AbstractEntityRepository { public CriteriaQuery createCriteriaQuery() { final CriteriaBuilder criteriaBuilder = entityManager - .getCriteriaBuilder(); + .getCriteriaBuilder(); final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( - getEntityClass()); + getEntityClass()); final Root root = criteriaQuery.from(getEntityClass()); return criteriaQuery.select(root); } @@ -208,8 +213,8 @@ public abstract class AbstractEntityRepository { final String graphName) { @SuppressWarnings("unchecked") final EntityGraph entityGraph = (EntityGraph< E>) entityManager - .getEntityGraph( - graphName); + .getEntityGraph( + graphName); return executeCriteriaQuery(criteriaQuery, entityGraph); } @@ -228,7 +233,7 @@ public abstract class AbstractEntityRepository { * @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); @@ -239,9 +244,9 @@ public abstract class AbstractEntityRepository { */ @Transactional(Transactional.TxType.REQUIRED) public void save(final E entity) { - + Objects.requireNonNull(entity, "Can't save null."); - + if (isNew(entity)) { initNewEntity(entity); entityManager.persist(entity); @@ -268,10 +273,10 @@ public abstract class AbstractEntityRepository { */ @Transactional(Transactional.TxType.REQUIRED) public void delete(final E entity) { - - Objects.requireNonNull(entity, + + Objects.requireNonNull(entity, "Can't delete a null entity."); - + //We need to make sure we use a none detached entity, therefore the merge entityManager.remove(entityManager.merge(entity)); } diff --git a/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java b/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java index 3f6f8acd3..22cb77ce4 100644 --- a/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java +++ b/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java @@ -23,7 +23,9 @@ import org.libreccm.configuration.ConfigurationManager; import javax.annotation.PostConstruct; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; + import java.io.*; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -78,14 +80,17 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { throw new InsufficientPermissionsException(path); } - final FileReader fileReader; + final InputStreamReader reader; try { - fileReader = new FileReader(nioPath.toFile()); + final FileInputStream inputStream = new FileInputStream( + nioPath.toFile()); + reader = new InputStreamReader(inputStream, + Charset.forName("UTF-8")); } catch (FileNotFoundException ex) { throw new FileDoesNotExistException(path, ex); } - return fileReader; + return reader; } @Override @@ -107,14 +112,17 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { throw new InsufficientPermissionsException(path); } - final FileWriter fileWriter; + final OutputStreamWriter writer; try { - fileWriter = new FileWriter(nioPath.toFile()); + final FileOutputStream outputStream = new FileOutputStream(nioPath + .toFile()); + writer = new OutputStreamWriter(outputStream, + Charset.forName("UTF-8")); } catch (IOException ex) { throw new FileAccessException(path, ex); } - return fileWriter; + return writer; } @Override diff --git a/ccm-core/src/main/java/org/libreccm/l10n/GlobalizationHelper.java b/ccm-core/src/main/java/org/libreccm/l10n/GlobalizationHelper.java index dcc3d365d..6ae9a1cb1 100644 --- a/ccm-core/src/main/java/org/libreccm/l10n/GlobalizationHelper.java +++ b/ccm-core/src/main/java/org/libreccm/l10n/GlobalizationHelper.java @@ -25,6 +25,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.libreccm.configuration.ConfigurationManager; +import java.io.Serializable; + import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; @@ -68,7 +70,9 @@ import java.util.ResourceBundle; * @author Jens Pelzetter */ @RequestScoped -public class GlobalizationHelper { +public class GlobalizationHelper implements Serializable { + + private static final long serialVersionUID = 3988918294651460360L; private static final Logger LOGGER = LogManager .getLogger(GlobalizationHelper.class); @@ -76,7 +80,7 @@ public class GlobalizationHelper { private static final String LANG_PARAM = "lang"; @Inject - private HttpServletRequest request; + private transient HttpServletRequest request; @Inject private ConfigurationManager confManager; @@ -178,9 +182,9 @@ public class GlobalizationHelper { return selected; } - + public void setSelectedLocale(final Locale locale) { - + final HttpSession session = request.getSession(true); session.setAttribute(LANG_PARAM, locale.toString()); } diff --git a/ccm-core/src/main/java/org/libreccm/l10n/ui/LocalizedStringEditor.java b/ccm-core/src/main/java/org/libreccm/l10n/ui/LocalizedStringEditor.java index f4d162ede..5d0fcda6d 100644 --- a/ccm-core/src/main/java/org/libreccm/l10n/ui/LocalizedStringEditor.java +++ b/ccm-core/src/main/java/org/libreccm/l10n/ui/LocalizedStringEditor.java @@ -1,7 +1,6 @@ package org.libreccm.l10n.ui; import com.vaadin.data.provider.QuerySortOrder; -import com.vaadin.server.SerializableSupplier; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Grid; import org.libreccm.l10n.GlobalizationHelper; @@ -10,7 +9,6 @@ import org.libreccm.l10n.LocalizedString; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Objects; import java.util.stream.Stream; @@ -55,7 +53,7 @@ public class LocalizedStringEditor extends CustomComponent { private static final String COL_VALUE = "col_value"; private static final String COL_EDIT = "col_edit"; private static final String COL_REMOVE = "col_remove"; - + private final GlobalizationHelper globalizationHelper; private boolean multiline; @@ -76,7 +74,7 @@ public class LocalizedStringEditor extends CustomComponent { grid.addColumn(LocalizedStringValue::getLocaleLabel) .setCaption("Language") .setId(COL_LOCALE); - + } public LocalizedStringEditor(final LocalizedString localizedString, @@ -145,15 +143,15 @@ public class LocalizedStringEditor extends CustomComponent { public String getValue() { return value; } - + public String getText() { if (multiline) { final String withoutHtml = value .replaceAll("<[\\w/]*>", " ") .replaceAll("\\s{2,}", " ").trim(); - + return String.format("%s...", withoutHtml.substring(0, 256)); - + } else { return value; } @@ -178,9 +176,8 @@ public class LocalizedStringEditor extends CustomComponent { .compareTo(Objects.toString(locale2)); }); - locales.subList(offset, limit); - return locales + .subList(offset, limit) .stream() .map(locale -> new LocalizedStringValue( locale, localizedString.getValue(locale))); diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentRendererManager.java b/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentRendererManager.java index e8a80fd02..455c9477f 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentRendererManager.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentRendererManager.java @@ -94,7 +94,7 @@ public class ComponentRendererManager { /** * Annotation literal for the {@link ComponentModelType} annotation. */ - private class ComponentModelTypeLiteral + private static class ComponentModelTypeLiteral extends AnnotationLiteral implements ComponentModelType { diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/ui/PageTreeModel.java b/ccm-core/src/main/java/org/libreccm/pagemodel/ui/PageTreeModel.java index c32b1738e..625e34093 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/ui/PageTreeModel.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/ui/PageTreeModel.java @@ -42,7 +42,7 @@ class PageTreeModel implements TreeModel { public boolean hasChildren(final TreeNode node, final PageState state) { if (node instanceof RootNode) { return true; - } else if (node instanceof ApplicationTypeTreeNode) { + } else if (node instanceof ApplicationTreeNode) { final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final PageModelRepository pageModelRepo = cdiUtil.findBean( PageModelRepository.class); diff --git a/ccm-core/src/main/java/org/libreccm/security/PartyRepository.java b/ccm-core/src/main/java/org/libreccm/security/PartyRepository.java index 714b64877..dbff2ab71 100644 --- a/ccm-core/src/main/java/org/libreccm/security/PartyRepository.java +++ b/ccm-core/src/main/java/org/libreccm/security/PartyRepository.java @@ -35,6 +35,8 @@ import java.util.Optional; @RequestScoped public class PartyRepository extends AbstractEntityRepository { + private static final long serialVersionUID = -8056652791690243141L; + @Override public Class getEntityClass() { return Party.class; @@ -72,7 +74,7 @@ public class PartyRepository extends AbstractEntityRepository { final TypedQuery query = getEntityManager() .createNamedQuery("Party.findByRole", Party.class); query.setParameter("role", role); - + return query.getResultList(); } diff --git a/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java b/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java index 90d653e63..b82e87f02 100644 --- a/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java +++ b/ccm-core/src/main/java/org/libreccm/security/PermissionManager.java @@ -416,12 +416,6 @@ public class PermissionManager { final Role grantee, final CcmObject object) { - LOGGER.debug("Revoking permission granting privilege \"{}\" " - + "on object \"{}\" to role \"{}\"...", - privilege, - grantee.getName(), - object.getUuid()); - if (privilege == null || privilege.isEmpty()) { throw new IllegalArgumentException( "Can't revoke a permission without a privilege."); @@ -436,6 +430,12 @@ public class PermissionManager { throw new IllegalArgumentException( "Can't revoke a permission from object NULL."); } + + LOGGER.debug("Revoking permission granting privilege \"{}\" " + + "on object \"{}\" to role \"{}\"...", + privilege, + grantee.getName(), + object.getUuid()); if (existsPermission(privilege, grantee, object) || existsInheritedPermission(privilege, grantee, object)) { diff --git a/ccm-core/src/main/java/org/libreccm/security/RoleManager.java b/ccm-core/src/main/java/org/libreccm/security/RoleManager.java index 84974c8b6..4fdb7997c 100644 --- a/ccm-core/src/main/java/org/libreccm/security/RoleManager.java +++ b/ccm-core/src/main/java/org/libreccm/security/RoleManager.java @@ -20,12 +20,15 @@ package org.libreccm.security; import org.libreccm.core.CoreConstants; +import java.io.Serializable; + import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; import javax.transaction.Transactional; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -39,7 +42,9 @@ import java.util.stream.Collectors; * @author Jens Pelzetter */ @RequestScoped -public class RoleManager { +public class RoleManager implements Serializable { + + private static final long serialVersionUID = -3012991584385998270L; @Inject private RoleRepository roleRepository; @@ -49,7 +54,7 @@ public class RoleManager { @Inject private EntityManager entityManager; - + @Inject private PermissionChecker permissionChecker; @@ -166,7 +171,7 @@ public class RoleManager { .map(membership -> membership.getRole()) .collect(Collectors.toList()); - final Set roles = new HashSet<>(); + final Set roles = new HashSet<>(directlyAssigned); final List groups = user .getGroupMemberships() @@ -181,7 +186,7 @@ public class RoleManager { .map(membership -> membership.getRole()) .collect(Collectors.toList())); } - + return new ArrayList<>(roles); } diff --git a/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java b/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java index db1993097..b02a1eea2 100644 --- a/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java +++ b/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java @@ -37,6 +37,8 @@ import java.util.Optional; @RequestScoped public class RoleRepository extends AbstractEntityRepository { + private static final long serialVersionUID = 2285369521940062504L; + @Override public Class getEntityClass() { return Role.class; 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 889b8240a..6d02dd41b 100644 --- a/ccm-core/src/main/java/org/libreccm/security/Shiro.java +++ b/ccm-core/src/main/java/org/libreccm/security/Shiro.java @@ -19,6 +19,7 @@ package org.libreccm.security; import com.arsdigita.kernel.KernelConfig; + import org.apache.shiro.SecurityUtils; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; @@ -26,10 +27,13 @@ import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; +import java.io.Serializable; + import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; import javax.inject.Inject; import javax.inject.Named; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -50,7 +54,9 @@ import java.util.Optional; * @author Jens Pelzetter */ @ApplicationScoped -public class Shiro { +public class Shiro implements Serializable { + + private static final long serialVersionUID = -3270585472267405099L; /** * Principal used for the public user if @@ -67,7 +73,8 @@ public class Shiro { * * @see #getPublicUser() */ - public static final String PUBLIC_USER_PRINCIPAL_EMAIL = "public-user@localhost"; + public static final String PUBLIC_USER_PRINCIPAL_EMAIL + = "public-user@localhost"; /** * Principal used for the system user if @@ -84,7 +91,8 @@ public class Shiro { * * @see #getSystemUser() */ - public static final String SYSTEM_USER_PRINCIPAL_EMAIL = "system-user@localhost"; + public static final String SYSTEM_USER_PRINCIPAL_EMAIL + = "system-user@localhost"; @Inject private UserRepository userRepository; @@ -171,8 +179,9 @@ public class Shiro { * subject. * * @return An {@link Optional} containing the {@link User} entity for the - * current subject. If the current subject is a virtual user which has no - * representation in the database the returned {@link Optional} is empty. + * current subject. If the current subject is a virtual user which + * has no representation in the database the returned + * {@link Optional} is empty. * * @see #getSubject() * @see #getSystemUser() @@ -223,6 +232,7 @@ public class Shiro { throw ex.getTargetException(); } } + } private static class SubjectInvocationHandler extends Handler { @@ -233,6 +243,7 @@ public class Shiro { final Object[] args) throws Throwable { return method.invoke(SecurityUtils.getSubject(), args); } + } private static class SecurityManagerInvocationHandler extends Handler { @@ -254,6 +265,7 @@ public class Shiro { final Object[] args) throws Throwable { return method.invoke(SecurityUtils.getSubject().getSession(), args); } + } } diff --git a/ccm-core/src/main/java/org/libreccm/sites/Site.java b/ccm-core/src/main/java/org/libreccm/sites/Site.java index 760c5390f..2a7dce615 100644 --- a/ccm-core/src/main/java/org/libreccm/sites/Site.java +++ b/ccm-core/src/main/java/org/libreccm/sites/Site.java @@ -116,6 +116,10 @@ public class Site extends CcmObject { return false; } final Site other = (Site) obj; + if (!other.canEqual(this)) { + return false; + } + if (defaultSite != other.isDefaultSite()) { return false; } diff --git a/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java b/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java new file mode 100644 index 000000000..2ba8616b4 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2017 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.theming; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.core.UnexpectedErrorException; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * A theme provider implementation which serves themes from the class path + * ({@code /themes)}. + * + * @author Jens Pelzetter + */ +public class StaticThemeProvider implements ThemeProvider { + + private static final Logger LOGGER = LogManager + .getLogger(StaticThemeProvider.class); + + private static final String THEMES_DIR = "/themes"; + private static final String THEME_XML = "theme.xml"; + private static final String THEME_JSON = "theme.json"; + + @Override + public List getThemes() { + + LOGGER.debug("Retrieving info about all static themes..."); + + final List themeInfos = new ArrayList<>(); + try (final FileSystem jarFileSystem = FileSystems.newFileSystem( + getJarUri(), Collections.emptyMap())) { + + final Path themesPath = jarFileSystem.getPath(THEMES_DIR); + if (!Files.isDirectory(themesPath)) { + LOGGER.warn(THEMES_DIR + " is not a directory. Returning " + + "empty list."); + return Collections.emptyList(); + } + + return Files + .list(themesPath) + .filter(this::isTheme) + .map(this::generateThemeInfo) + .collect(Collectors.toList()); + + } catch (IOException ex) { + throw new UnexpectedErrorException(ex); + } + } + + @Override + public List getLiveThemes() { + return getThemes(); + } + + @Override + public Optional getThemeInfo(String theme, ThemeVersion version) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean providesTheme(String theme, ThemeVersion version) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public List listThemeFiles(String theme, ThemeVersion version, + String path) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Optional getThemeFileAsStream(String theme, + ThemeVersion version, + String path) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public OutputStream getOutputStreamForThemeFile(String theme, String path) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean supportsChanges() { + return false; + } + + @Override + public boolean supportsDraftThemes() { + return false; + } + + @Override + public void publishTheme(final String theme) { + LOGGER.info("StaticThemeProvider#publishTheme(String) called, but " + + "StaticThemeProvider does not support draft/live " + + "themes."); + } + + private URI getJarUri() { + + LOGGER.debug("Getting URI of JAR..."); + + final String themesUrl = getClass().getResource(THEMES_DIR).toString(); + LOGGER.debug("Full URL of " + THEMES_DIR + " directory: {}", themesUrl); + + final int index = themesUrl.indexOf('!'); + final String pathToJar = themesUrl.substring(0, index); + + final URI uri = URI.create(pathToJar); + LOGGER.debug("URI to JAR is \"%s\".", uri.toString()); + return uri; + } + + private boolean isTheme(final Path path) { + + Objects.requireNonNull(path); + + if (!Files.isDirectory(path)) { + return false; + } + + final Path manifestPathJson = path.resolve(THEME_JSON); + final Path manifestPathXml = path.resolve(THEME_XML); + + return Files.exists(manifestPathJson) || Files.exists(manifestPathXml); + } + + private ThemeInfo generateThemeInfo(final Path path) { + + Objects.requireNonNull(path); + + if (!Files.exists(path)) { + throw new IllegalArgumentException(String + .format("The provided path \"%s\" does " + + "not exist.", + path.toString())); + } + + final Path manifestPathJson = path.resolve(THEME_JSON); + final Path manifestPathXml = path.resolve(THEME_XML); + + if (Files.exists(manifestPathJson)) { + return generateThemeInfoFromJson(manifestPathJson); + } else if (Files.exists(manifestPathXml)) { + return generateThemeInfoFromXml(manifestPathXml); + } else { + throw new IllegalArgumentException(String + .format("The provided path \"%s\" does " + + "contain a theme manifest file.", + path.toString())); + } + } + + private ThemeInfo generateThemeInfoFromJson(final Path path) { + throw new UnsupportedOperationException(); + } + + private ThemeInfo generateThemeInfoFromXml(final Path path) { + throw new UnsupportedOperationException(); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/theming/Themes.java b/ccm-core/src/main/java/org/libreccm/theming/Themes.java index ee85b6c2f..648a55a17 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/Themes.java +++ b/ccm-core/src/main/java/org/libreccm/theming/Themes.java @@ -126,7 +126,7 @@ public class Themes { return processor.process(page, theme, provider); } - private class ThemeTypeLiteral extends AnnotationLiteral + private static class ThemeTypeLiteral extends AnnotationLiteral implements ThemeType { private static final long serialVersionUID = 3377237291286175824L; diff --git a/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidget.java b/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidget.java index 17dba5dae..ffe8c00ad 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidget.java +++ b/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidget.java @@ -336,7 +336,9 @@ public class LocalizedStringWidget extends CustomComponent { UI.getCurrent().addWindow(window); } - private class SimpleTextEditor extends TextArea implements TextEditor { + private static class SimpleTextEditor + extends TextArea + implements TextEditor { private static final long serialVersionUID = -1189747199799719077L; diff --git a/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidgetController.java b/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidgetController.java index 6e1df89d2..f192ccbed 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidgetController.java +++ b/ccm-core/src/main/java/org/libreccm/ui/LocalizedStringWidgetController.java @@ -22,6 +22,7 @@ import com.arsdigita.kernel.KernelConfig; import org.libreccm.configuration.ConfigurationManager; +import java.io.Serializable; import java.util.List; import java.util.Locale; import java.util.stream.Collectors; @@ -38,7 +39,9 @@ import javax.inject.Inject; * @author Jens Pelzetter */ @RequestScoped -public class LocalizedStringWidgetController { +public class LocalizedStringWidgetController implements Serializable { + + private static final long serialVersionUID = -8390792440087872905L; @Inject private ConfigurationManager confManager; @@ -47,23 +50,22 @@ public class LocalizedStringWidgetController { final KernelConfig kernelConfig = confManager .findConfiguration(KernelConfig.class); - + return kernelConfig.getDefaultLocale(); } - + public List getSupportedLocales() { - - final KernelConfig kernelConfig = confManager + + final KernelConfig kernelConfig = confManager .findConfiguration(KernelConfig.class); - - return kernelConfig - .getSupportedLanguages() - .stream() - .sorted((lang1, lang2) -> lang1.compareTo(lang2)) - .map(Locale::new) - .collect(Collectors.toList()); - + + return kernelConfig + .getSupportedLanguages() + .stream() + .sorted((lang1, lang2) -> lang1.compareTo(lang2)) + .map(Locale::new) + .collect(Collectors.toList()); + } - } diff --git a/ccm-core/src/main/java/org/libreccm/ui/TextEditorBuilder.java b/ccm-core/src/main/java/org/libreccm/ui/TextEditorBuilder.java index eca52e439..bb23a4b66 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/TextEditorBuilder.java +++ b/ccm-core/src/main/java/org/libreccm/ui/TextEditorBuilder.java @@ -18,6 +18,8 @@ */ package org.libreccm.ui; +import java.io.Serializable; + /** * A functional interface which can be used by other components which embed * a text editor. @@ -25,7 +27,7 @@ package org.libreccm.ui; * @author Jens Pelzetter */ @FunctionalInterface -public interface TextEditorBuilder { +public interface TextEditorBuilder extends Serializable { /** * Create the text editor component. diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/UserContextController.java b/ccm-core/src/main/java/org/libreccm/ui/admin/UserContextController.java index e90782691..da7c10cbf 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/admin/UserContextController.java +++ b/ccm-core/src/main/java/org/libreccm/ui/admin/UserContextController.java @@ -43,7 +43,7 @@ public class UserContextController implements Serializable { private Shiro shiro; @Inject - private Subject subject; + private transient Subject subject; public boolean isLoggedIn() { return subject.isAuthenticated(); diff --git a/ccm-core/src/main/java/org/libreccm/workflow/Task.java b/ccm-core/src/main/java/org/libreccm/workflow/Task.java index 7c39019c0..b36aa6cbf 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/Task.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/Task.java @@ -376,10 +376,7 @@ public class Task implements Identifiable, Serializable { + "uuid = \"%s\", " + "label = %s, " + "active = %b, " - + "taskState = \"%s\", " -// + "workflow = %s, " -// + "dependentTasks = %s, " -// + "dependsOn = %s%s" + + "taskState = \"%s\"%s" + " }", super.toString(), taskId, @@ -387,9 +384,6 @@ public class Task implements Identifiable, Serializable { Objects.toString(label), active, taskState, -// Objects.toString(workflow), -// Objects.toString(dependentTasks), -// Objects.toString(dependsOn), data); }