diff --git a/ccm-core/src/main/java/org/libreccm/categorization/CategorizationConstants.java b/ccm-core/src/main/java/org/libreccm/categorization/CategorizationConstants.java new file mode 100644 index 000000000..fe9c28c39 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/categorization/CategorizationConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 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.categorization; + +/** + * + * @author Jens Pelzetter + */ +public final class CategorizationConstants { + + public static final String CAT_XML_NS = "http://categorization.libreccm.org"; + + private CategorizationConstants() { + //Nothing + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java b/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java index 5721858a2..be369c1de 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java @@ -273,7 +273,7 @@ public class CategoryManager { * {@code null}. * * @throws NotASubCategoryException If one or both categories are not - * subcategories of the provided parent category. + * subcategories of the provided parent category.qq */ public void swapCategories(final Category subCategoryA, final Category subCategoryB, 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 829161d56..5ee846c31 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/Domain.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/Domain.java @@ -20,9 +20,13 @@ package org.libreccm.categorization; import org.hibernate.validator.constraints.NotBlank; import org.hibernate.validator.constraints.URL; + +import static org.libreccm.categorization.CategorizationConstants.*; + import org.libreccm.core.CcmObject; import org.libreccm.jpa.utils.UriConverter; import org.libreccm.l10n.LocalizedString; +import org.libreccm.web.Application; import java.io.Serializable; import java.net.URI; @@ -48,21 +52,26 @@ import javax.validation.constraints.Pattern; import org.omg.CORBA.DomainManager; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + /** * A domain is collection of categories designed a specific purpose. This entity * replaces the {@code Domain} entity from the old {@code ccm-ldn-terms} module * as well as the {@code CategoryPurpose} entity from the old * {@code ccm-core module}. * - * A {@code Domain} can be mapped to multiple {@link CcmObject}s. Normally this - * is used to make a {@code Domain} available in a application. The - * {@link CcmObject}s to which a {@code Domain} is mapped are called + * A {@code Domain} can be mapped to multiple {@link Application}s. Normally + * This is used to make a {@code Domain} available in the application. The + * {@link Application}s to which a {@code Domain} is mapped are called * owners of the domain. * * @author Jens Pelzetter */ @Entity @Table(name = "category_domains") +@XmlRootElement(name = "domain", namespace = CAT_XML_NS) public class Domain extends CcmObject implements Serializable { private static final long serialVersionUID = 4012590760598188732L; @@ -75,6 +84,7 @@ public class Domain extends CcmObject implements Serializable { @Column(name = "domain_key", nullable = false, unique = true, length = 255) @NotBlank @Pattern(regexp = "[\\w-.]*") + @XmlElement(name = "domain-key", namespace = CAT_XML_NS) private String domainKey; /** @@ -89,10 +99,11 @@ public class Domain extends CcmObject implements Serializable { * http://example.org/domains/example-nav * */ - @Column(name = "uri", nullable = false, length = 2048) + @Column(name = "uri", nullable = false, unique = true, length = 2048) @Convert(converter = UriConverter.class) @NotBlank @URL + @XmlElement(name = "uri", namespace = CAT_XML_NS) private URI uri; /** @@ -105,6 +116,7 @@ public class Domain extends CcmObject implements Serializable { joinTable = @JoinTable(name = "domain_titles", joinColumns = { @JoinColumn(name = "object_id")})) + @XmlElement(name = "title", namespace = CAT_XML_NS) private LocalizedString title; /** @@ -116,6 +128,7 @@ public class Domain extends CcmObject implements Serializable { joinTable = @JoinTable(name = "domain_descriptions", joinColumns = { @JoinColumn(name = "object_id")})) + @XmlElement(name = "description", namespace = CAT_XML_NS) private LocalizedString description; /** @@ -123,6 +136,7 @@ public class Domain extends CcmObject implements Serializable { */ @Column(name = "version", nullable = false) @NotBlank + @XmlElement(name = "version", namespace = CAT_XML_NS) private String version; /** @@ -130,6 +144,7 @@ public class Domain extends CcmObject implements Serializable { */ @Column(name = "released") @Temporal(TemporalType.TIMESTAMP) + @XmlElement(name = "released", namespace = CAT_XML_NS) private Date released; /** @@ -137,12 +152,14 @@ public class Domain extends CcmObject implements Serializable { */ @ManyToOne @JoinColumn(name = "root_category_id") + @XmlElement(name = "root", namespace = CAT_XML_NS) private Category root; /** * The owners of the domain. */ @OneToMany(mappedBy = "domain") + @XmlElementWrapper(name = "owners", namespace = CAT_XML_NS) private List owners; public Domain() { diff --git a/ccm-core/src/main/java/org/libreccm/categorization/DomainManager.java b/ccm-core/src/main/java/org/libreccm/categorization/DomainManager.java new file mode 100644 index 000000000..c1de518f8 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/categorization/DomainManager.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 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.categorization; + +import org.libreccm.web.Application; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; + +/** + * Provides several methods when managing the relations between {@link Domain}s + * and their owning {@link Application}s. + * + * @author Jens Pelzetter + */ +@RequestScoped +public class DomainManager { + + @Inject + private transient DomainRepository domainRepo; + + /** + * Adds a {@code Application} to the owners of a {@link Domain}. If the + * provided {@code Application} is already an owner of the provided + * {@code Domain} the method does nothing. + * + * @param application The {@code Application} to add to the owners of the + * {@code Domain}. + * @param domain The {@code Domain} to which owners the + * {@code Application is added}. + */ + public void addDomainOwner(final Application application, + final Domain domain) { + throw new UnsupportedOperationException(); + } + + /** + * Removes a {@code Application} from the owners of a {@code Domain}. If the + * provided {@code Application} is not an owner of the provided + * {@code Domain} the method does nothing. + * + * @param application The {@code Application} to remove from the owners of + * the provided {@code Domain}. + * @param domain The {@code Domain} from which owners the provided + * {@code Application} should be removed. + */ + public void removeDomainOwner(final Application application, + final Domain domain) { + throw new UnsupportedOperationException(); + } + + /** + * Determines if a {@link Application} is an owner of {@link Domain}. + * + * @param application The {@code Application} to test. + * @param domain The {@code Domain} to test. + * @return {@code true} if the provided {@code Application} is an owner + * of the provided {@code Domain}, {@code false} otherwise. + */ + public boolean isDomainOwner(final Application application, + final Domain domain) { + throw new UnsupportedOperationException(); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/categorization/DomainOwnership.java b/ccm-core/src/main/java/org/libreccm/categorization/DomainOwnership.java index ca57a2fa7..625d9463c 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/DomainOwnership.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/DomainOwnership.java @@ -20,6 +20,7 @@ package org.libreccm.categorization; import java.io.Serializable; import java.util.Objects; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -27,7 +28,9 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; + import org.libreccm.core.CcmObject; +import org.libreccm.web.Application; /** * Association class for the association between a {@link Domain} and a @@ -55,7 +58,7 @@ public class DomainOwnership implements Serializable { * The {@link CcmObject} owning the {@link Domain}. */ @ManyToOne(optional = false) - private CcmObject owner; + private Application owner; /** * The {@link Domain} owned by the {@link CcmObject}. @@ -91,11 +94,11 @@ public class DomainOwnership implements Serializable { this.ownershipId = ownershipId; } - public CcmObject getOwner() { + public Application getOwner() { return owner; } - protected void setOwner(final CcmObject owner) { + protected void setOwner(final Application owner) { this.owner = owner; } diff --git a/ccm-core/src/main/java/org/libreccm/categorization/DomainRepository.java b/ccm-core/src/main/java/org/libreccm/categorization/DomainRepository.java new file mode 100644 index 000000000..520082383 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/categorization/DomainRepository.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 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.categorization; + +import org.libreccm.core.AbstractEntityRepository; + +import java.net.URI; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.persistence.EntityManager; + +/** + * A repository for executing CRUD operations on {@link Domain} objects. + * + * @author Jens Pelzetter + */ +@RequestScoped +public class DomainRepository extends AbstractEntityRepository { + + @Inject + private transient EntityManager entityManager; + + @Override + public Class getEntityClass() { + return Domain.class; + } + + @Override + public boolean isNew(final Domain entity) { + return entity.getObjectId() == 0; + } + + /** + * Find the {@link Domain} identified by the provided {@code domainKey}. + * + * @param domainKey The domain key of the {@code Domain} to find. + * + * @return The {@code Domain} identified by {@code domainKey} or + * {@code null} if there is no such {@code Domain}. + */ + public Domain findByDomainKey(final String domainKey) { + throw new UnsupportedOperationException(); + } + + /** + * Find the {@link Domain} identified the provided {@code uri}. + * + * @param uri The URI of the domain to find. + * + * @return The {@code Domain} identified by the provided URI or {@code null} + * if there is so such {@code Domain}. + */ + public Domain findByUri(final URI uri) { + throw new UnsupportedOperationException(); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/categorization/package-info.java b/ccm-core/src/main/java/org/libreccm/categorization/package-info.java new file mode 100644 index 000000000..399a83c4e --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/categorization/package-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 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 + */ +@XmlSchema(xmlns = {@XmlNs(prefix = "cat", namespaceURI = CAT_XML_NS)}) +@XmlAccessorType(XmlAccessType.NONE) +package org.libreccm.categorization; + +import static org.libreccm.categorization.CategorizationConstants.*; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlNs; +import javax.xml.bind.annotation.XmlSchema; diff --git a/ccm-core/src/main/java/org/libreccm/core/CcmObject.java b/ccm-core/src/main/java/org/libreccm/core/CcmObject.java index b6a363ac9..5ee7a937c 100644 --- a/ccm-core/src/main/java/org/libreccm/core/CcmObject.java +++ b/ccm-core/src/main/java/org/libreccm/core/CcmObject.java @@ -22,9 +22,7 @@ import static org.libreccm.core.CoreConstants.*; import org.libreccm.categorization.Categorization; import org.libreccm.categorization.Category; -import org.libreccm.categorization.Domain; -import org.libreccm.categorization.DomainOwnership; -import org.omg.CORBA.DomainManager; +import org.libreccm.categorization.CategoryManager; import java.io.Serializable; import java.util.ArrayList; @@ -46,21 +44,21 @@ import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; /** - * Root class of all entities in LibreCCM which need categorisation and - * permission services. - * - * This class defines several basic properties including associations - * to {@link Category} (via the {@link Categorization} class and permissions. - * + * Root class of all entities in LibreCCM which need categorisation and + * permission services. + * + * This class defines several basic properties including associations to + * {@link Category} (via the {@link Categorization} class and permissions. + * * In the old hierarchy the equivalent of this class was the {@code ACSObject} * entity. - * + * * We are using the {@code JOINED} inheritance strategy for the inheritance - * hierarchy of this class to achieve modularity and to minimise duplicate data + * hierarchy of this class to achieve modularity and to minimise duplicate data * in the database. - * + * * @author Jens Pelzetter - * + * */ @Entity @Table(name = "ccm_objects") @@ -75,9 +73,8 @@ public class CcmObject implements Serializable { private static final long serialVersionUID = 201504261329L; /** - * The ID/primary key for the {@code CcmObject}. Please note that it is - * not necessary to define an additional ID on classes which extend this - * class. + * The ID/primary key for the {@code CcmObject}. Please note that it is not + * necessary to define an additional ID on classes which extend this class. */ @Id @Column(name = "object_id") @@ -96,15 +93,7 @@ public class CcmObject implements Serializable { @XmlElementWrapper(name = "permissions", namespace = CORE_XML_NS) @XmlElement(name = "permission", namespace = CORE_XML_NS) private List permissions; - - /** - * Category Domains owned by this {@code CcmObject}. - */ - @OneToMany(mappedBy = "owner") - @XmlElementWrapper(name = "domains", namespace = CORE_XML_NS) - @XmlElement(name = "domain", namespace = CORE_XML_NS) - private List domains; - + /** * Categories which have been assigned to this {@code CcmObject}. */ @@ -112,15 +101,14 @@ public class CcmObject implements Serializable { @XmlElementWrapper(name = "categories", namespace = CORE_XML_NS) @XmlElement(name = "category", namespace = CORE_XML_NS) private List categories; - + public CcmObject() { super(); - + permissions = new ArrayList<>(); - domains = new ArrayList<>(); categories = new ArrayList<>(); } - + public long getObjectId() { return objectId; } @@ -138,10 +126,11 @@ public class CcmObject implements Serializable { } /** - * + * * @return Returns all permissions for this {@code CcmObject}. Please note - * that the returned {@link List} can't be modified. For adding and removing - * permissions use the methods provided by the {@link CcmObjectManager}. + * that the returned {@link List} can't be modified. For adding and + * removing permissions use the methods provided by the + * {@link CcmObjectManager}. */ public List getPermissions() { return Collections.unmodifiableList(permissions); @@ -154,92 +143,49 @@ public class CcmObject implements Serializable { protected void addPermission(final Permission permission) { permissions.add(permission); } - + protected void removePermission(final Permission permission) { permissions.remove(permission); } - - /** - * Gets an unmodifiable list of the domains which are owned - * by the {@code CcmObject}. - * - * @return An unmodifiable list of the domain ownerships of this - * {@code CcmObject}. Might be {@code null} or empty. - */ - public List getDomains() { - return Collections.unmodifiableList(domains); - } /** - * Setter for the list of domain ownerships, only for use by JPA. - * - * @param domains A list of domain ownerships. - */ - protected void setDomains(final List domains) { - this.domains = domains; - } - - /** - * Internal method for adding a domain ownership. - * Users should use the appropriate methods of the {@link DomainManager} - * class to - * manage the {@link Domain}s assigned to {@code CcmObject}. - * - * @param domain The domain ownership to add. - */ - protected void addDomain(final DomainOwnership domain) { - domains.add(domain); - } - - /** - * Internal method for removing a domain ownership. - * Users should use the appropriate methods of the {@link DomainManager} to - * manage the {@link Domain}s assigned to {@code CcmObject}. - * - * @param domain The domain to remove. - */ - protected void removeDomain(final DomainOwnership domain) { - domains.remove(domain); - } - - /** - * Returns a unmodifiable list of the categories this + * Returns a unmodifiable list of the categories this * object is assigned to. To manage the categories of a {@code CcmObject} * use the methods provided by the {@link CategoryManager} class. - * + * * @return An unmodifiable list of the categories of this - * {@code CcmObject}. Might be {@code null} or empty. + * {@code CcmObject}. Might be {@code null} or empty. */ public List getCategories() { return Collections.unmodifiableList(categories); } - /** - * Setter for the list of categories assigned to this {@code CcmObject}, - * only for use by JPA. - * - * @param categories A list of domain ownerships. + /** + * Setter for the list of categories assigned to this {@code CcmObject}, + * only for use by JPA. + * + * @param categories A list of domain ownerships. */ protected void setCategories(final List categories) { this.categories = categories; } - + /** - * Internal method for adding a category. - * Users should use the appropriate methods of the {@link CategoryManager} - * class to manage the categories assigned to a {@code CcmObject}. - * - * @param category The domain ownership to add. + * Internal method for adding a category. Users should use + * the appropriate methods of the {@link CategoryManager} class to manage + * the categories assigned to a {@code CcmObject}. + * + * @param category The domain ownership to add. */ protected void addCategory(final Categorization category) { categories.add(category); } - + /** - * Internal method for removing a assigned category. - * Users should use the appropriate methods of the {@link CategoryManager} - * to manage the categories assigned to a {@code CcmObject}. - * + * Internal method for removing a assigned category. Users + * should use the appropriate methods of the {@link CategoryManager} to + * manage the categories assigned to a {@code CcmObject}. + * * @param category The assigned category to remove. */ protected void removeCategory(final Categorization category) { @@ -255,45 +201,47 @@ public class CcmObject implements Serializable { } /** - * Implementation of the {@code equals(Object)} method for {@code CcmObject}. We are - * using the canEqual approach described at + * Implementation of the {@code equals(Object)} method for + * {@code CcmObject}. We are using the canEqual approach described + * at * http://www.jqno.nl/equalsverifier/2011/01/20/subclass-object-is-not-equal-to-an-instance-of-a-trivial-subclass-with-equal-fields/ * here. Therefore, in addition to overwrite this method subclasses should * also overwrite the {@link #canEqual(java.lang.Object)} method. - * + * * A good pattern for implementing {@code equals(Object)} is the following - * (this is similar to {@code equals(Object)} implemenation created by + * (this is similar to {@code equals(Object)} implemenation created by * Netbeans): - * + * *
      * public boolean equals(final Object obj) {
      *     //Check if obj is null
      *     if (obj == null) {
      *         return false;
      *     }
-     *     
+     *
      *     //Check if obj is an instance of the class implementing equals
      *     if (!(obj instanceof YourClass)) {
      *         return false;
      *     }
-     * 
+     *
      *     //Cast obj to the specific class
      *     final YourClass other = (YourClass) obj;
      *     //Check if other can equal YourClass
      *     if (!other.canEqual(this) {
      *         return false;
      *     }
-     * 
+     *
      *     if(!super.equals(obj) {
      *         return false;
      *     }
-     * 
+     *
      *     //Check properties of YourClass
      *     ...
      * }
      * 
- * + * * @param obj {@inheritDoc} + * * @return {@inheritDoc} */ @Override @@ -316,18 +264,19 @@ public class CcmObject implements Serializable { } /** - * The {@code canEqual(Object} method is a helper method for - * {@link #equals(java.lang.Object)}. Subclasses which overwrite - * {@code #equals(Object)} must override this method also. - * + * The {@code canEqual(Object} method is a helper method for + * {@link #equals(java.lang.Object)}. Subclasses which overwrite + * {@code #equals(Object)} must override this method also. + * * Usually the implementation of this method will be a onliner: *
      * public boolean canEqual(final Object obj) {
      *     return obj instanceof YourClass;
      * }
      * 
- * + * * @param obj The object to check. + * * @return {@code true} if {@link obj} can equal this, false otherwise. */ public boolean canEqual(final Object obj) { @@ -336,11 +285,11 @@ public class CcmObject implements Serializable { /** * Implementation of the {@code toString()} method for {@code CcmObject}. To - * make extension easy {@code toString()} simply calls - * {@link #toString(java.lang.String)} with an empty string as parameter. + * make extension easy {@code toString()} simply calls + * {@link #toString(java.lang.String)} with an empty string as parameter. * Subclasses should not overwrite {@code toString}, instead they should use * {@link #toString(java.lang.String)}. - * + * * @return {@inheritDoc} */ @Override @@ -350,33 +299,34 @@ public class CcmObject implements Serializable { /** * Creates a string representation of this object. Example: - * + * *
-     *   org.libreccm.core.CcmObject@1adafefe4222{ objectId = 42, 
+     *   org.libreccm.core.CcmObject@1adafefe4222{ objectId = 42,
      *   displayName = "example" }
      * 
- * - * Subclasses can simply add their properties by creating a containing the + * + * Subclasses can simply add their properties by creating a containing the * additional properties and call {@code super.toString(String)} with this * data. The string should start with a leading space and comma because the * additional properties are inserted after the {@code displayName} in the * string. Also an overwriting method should insert its own data parameter * and the end of the string it creates. - * + * * Collections should not be included in this string. Associated objects * might be included. In that case their representation should like this: *
      * someObject = { ... }
      * 
- * + * * The content of the curly braces should be the string representation of - * the object. If the object is very complex it might be sufficent to + * the object. If the object is very complex it might be sufficent to * include only a subset of the objects properties. - * - * Likewise, strings would be enclosed by quotes. The value of date + * + * Likewise, strings would be enclosed by quotes. The value of date * properties should be shown in ISO format. - * + * * @param data data from a subclass + * * @return A string representation of this object. */ public String toString(final String data) { @@ -386,7 +336,7 @@ public class CcmObject implements Serializable { + "displayName = \"%s\"" + "%s" + " }", - super.toString(), + super.toString(), objectId, displayName, data); diff --git a/ccm-core/src/main/java/org/libreccm/core/CcmSessionContext.java b/ccm-core/src/main/java/org/libreccm/core/CcmSessionContext.java new file mode 100644 index 000000000..4cc846d27 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/core/CcmSessionContext.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 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.io.Serializable; + +import javax.enterprise.context.SessionScoped; + +/** + * This bean stores several datas about the current session, for example the + * current party. + * + * @author Jens Pelzetter + */ +@SessionScoped +public class CcmSessionContext implements Serializable { + + private static final long serialVersionUID = 6110177865273823685L; + + private Party currentParty; + private Party effectiveParty; + + public Party getCurrentParty() { + return currentParty; + } + + public void setCurrentParty(final Party currentParty) { + this.currentParty = currentParty; + this.effectiveParty = currentParty; + } + + public Party getEffectiveParty() { + return effectiveParty; + } + + protected void setEffectiveParty(final Party effectiveParty) { + this.effectiveParty = effectiveParty; + } + + /** + * Execute code under different privileges. Useful if no current user is + * available, for example in the startup phase. + * + * The there is a current user the method will check if the current user + * has the permission to use the {@code sudo} method. + * + * @param party The party with which permissions the code is executed. + * @param runnable The code to execute. + */ + public void sudo(final Party party, final Runnable runnable) { + //ToDo: Check if current user is permitted to use sudo. + + effectiveParty = party; + runnable.run(); + effectiveParty = currentParty; + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/core/User.java b/ccm-core/src/main/java/org/libreccm/core/User.java index 3362c1cc9..889625de3 100644 --- a/ccm-core/src/main/java/org/libreccm/core/User.java +++ b/ccm-core/src/main/java/org/libreccm/core/User.java @@ -45,7 +45,9 @@ import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; /** - * + * The {@code User} entity stores the name and the password of a user along with + * some other informations. + * * @author Jens Pelzetter */ @Entity @@ -53,7 +55,7 @@ import javax.xml.bind.annotation.XmlTransient; @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... -@SuppressWarnings({"PMD.ShortClassName", +@SuppressWarnings({"PMD.ShortClassName", "PMD.CyclomaticComplexity", "PMD.StdCyclomaticComplexity", "PMD.ModifiedCyclomaticComplexity"}) @@ -61,6 +63,9 @@ public class User extends Party implements Serializable { private static final long serialVersionUID = 892038270064849732L; + /** + * The real name of the user. We are using an {@code Embeddable} here. + */ @Embedded @AssociationOverride( name = "user_names", @@ -70,35 +75,82 @@ public class User extends Party implements Serializable { @XmlElement(name = "person-name", namespace = CORE_XML_NS) private PersonName name; + /** + * A user name of the user. Usually an abbreviation of the users real name. + * For example a the John Doe might have the scree name + * jdoe. The screen name is used as user name for logins (if + * the system if configured so, otherwise the email address of the user is + * used). + */ @Column(name = "screen_name", length = 255, nullable = false) @NotBlank @XmlElement(name = "screen-name", namespace = CORE_XML_NS) private String screenName; + /** + * A user can be banned which means that he or she can't login into the + * system anymore. + */ @Column(name = "banned") @XmlElement(name = "banned", namespace = CORE_XML_NS) private boolean banned; + /** + * An alias for the user used in an another system for SSO, for example LDAP. + */ @Column(name = "sso_login", length = 512) @XmlElement(name = "sso-login", namespace = CORE_XML_NS) private String ssoLogin; + /** + * The hashed password of the user. + */ @Column(name = "password", length = 2048) @XmlTransient private String password; + /** + * The salt used to hash the password. + */ @Column(name = "salt", length = 2048) @XmlTransient private String salt; + /** + * The hash algorithm used to hash the password. This allows us + * the change to another, stronger hash algorithm without invalidating + * existing accounts. The algorithm to use for new passwords can be + * configured by the administrator. + * + */ + @Column(name = "hash_algorithm", length = 64) + @XmlTransient + private String hashAlgorithm; + + /** + * Indicates that the user should be forced to change his or her password + * on the next login. + */ + @Column(name = "password_reset_required") + private boolean passwordResetRequired; + + /** + * Question the recover a forgotten password. + */ @Column(name = "password_question", length = 2048) @XmlElement(name = "password-question", namespace = CORE_XML_NS) private String passwordQuestion; + /** + * Answer the the {@link #passwordQuestion}. + */ @Column(name = "password_answer", length = 2048) @XmlElement(name = "password-answer", namespace = CORE_XML_NS) private String passwordAnswer; + /** + * The groups of which the user is a member. + */ @OneToMany(mappedBy = "user") @XmlElementWrapper(name = "group-memberships") @XmlElement(name = "group-membership", namespace = CORE_XML_NS) @@ -106,10 +158,11 @@ public class User extends Party implements Serializable { public User() { super(); - + + name = new PersonName(); this.groupMemberships = new ArrayList<>(); } - + public PersonName getName() { return name; } @@ -158,6 +211,22 @@ public class User extends Party implements Serializable { this.salt = salt; } + public String getHashAlgorithm() { + return hashAlgorithm; + } + + public void setHashAlgorithm(final String hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; + } + + public boolean isPasswordResetRequired() { + return passwordResetRequired; + } + + public void setPasswordResetRequired(final boolean passwordResetRequired) { + this.passwordResetRequired = passwordResetRequired; + } + public String getPasswordQuestion() { return passwordQuestion; } @@ -195,14 +264,16 @@ public class User extends Party implements Serializable { @Override public int hashCode() { int hash = super.hashCode(); - hash = 59 * hash + Objects.hashCode(this.name); - hash = 59 * hash + Objects.hashCode(this.screenName); - hash = 59 * hash + (this.banned ? 1 : 0); - hash = 59 * hash + Objects.hashCode(this.ssoLogin); - hash = 59 * hash + Objects.hashCode(this.password); - hash = 59 * hash + Objects.hashCode(this.salt); - hash = 59 * hash + Objects.hashCode(this.passwordQuestion); - hash = 59 * hash + Objects.hashCode(this.passwordAnswer); + hash = 59 * hash + Objects.hashCode(name); + hash = 59 * hash + Objects.hashCode(screenName); + hash = 59 * hash + (banned ? 1 : 0); + hash = 59 * hash + Objects.hashCode(ssoLogin); + hash = 59 * hash + Objects.hashCode(password); + hash = 59 * hash + Objects.hashCode(salt); + hash = 59 * hash + Objects.hashCode(hashAlgorithm); + hash = 59 * hash + (passwordResetRequired ? 1 : 0); + hash = 59 * hash + Objects.hashCode(passwordQuestion); + hash = 59 * hash + Objects.hashCode(passwordAnswer); return hash; } @@ -228,28 +299,37 @@ public class User extends Party implements Serializable { return false; } - if (!Objects.equals(this.name, other.getName())) { + if (!Objects.equals(name, other.getName())) { return false; } - if (!Objects.equals(this.screenName, other.getScreenName())) { + if (!Objects.equals(screenName, other.getScreenName())) { return false; } - if (this.banned != other.isBanned()) { + if (banned != other.isBanned()) { return false; } - if (!Objects.equals(this.ssoLogin, other.getSsoLogin())) { + if (!Objects.equals(ssoLogin, other.getSsoLogin())) { return false; } - if (!Objects.equals(this.password, other.getPassword())) { + if (!Objects.equals(password, other.getPassword())) { return false; } - if (!Objects.equals(this.salt, other.getSalt())) { + if (!Objects.equals(salt, other.getSalt())) { return false; } - if (!Objects.equals(this.passwordQuestion, other.getPasswordQuestion())) { + + if (!Objects.equals(hashAlgorithm, other.getHashAlgorithm())) { return false; } - return Objects.equals(this.passwordAnswer, other.getPasswordAnswer()); + + if (passwordResetRequired != other.isPasswordResetRequired()) { + return false; + } + + if (!Objects.equals(passwordQuestion, other.getPasswordQuestion())) { + return false; + } + return Objects.equals(passwordAnswer, other.getPasswordAnswer()); } @Override @@ -262,11 +342,15 @@ public class User extends Party implements Serializable { return super.toString(String.format(", name = %s, " + "screenName = \"%s\", " + "banned = %b, " - + "ssoLogin = \"%s\"%s", + + "ssoLogin = \"%s\"" + + "hashAlgorithm = \"%s\"" + + "passwordResetRequired = %b%s", Objects.toString(name), screenName, banned, ssoLogin, + hashAlgorithm, + passwordResetRequired, data)); } diff --git a/ccm-core/src/main/java/org/libreccm/core/package-info.java b/ccm-core/src/main/java/org/libreccm/core/package-info.java index acfa74b1c..075ab6377 100644 --- a/ccm-core/src/main/java/org/libreccm/core/package-info.java +++ b/ccm-core/src/main/java/org/libreccm/core/package-info.java @@ -21,10 +21,12 @@ * This package provides some base classes for LibreCCM. */ @XmlSchema(xmlns = {@XmlNs(prefix = "ccmcore", - namespaceURI = "http://core.libreccm.org")}) + namespaceURI = CORE_XML_NS)}) @XmlAccessorType(XmlAccessType.NONE) package org.libreccm.core; +import static org.libreccm.core.CoreConstants.*; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlNs; diff --git a/ccm-core/src/main/java/org/libreccm/l10n/L10NConstants.java b/ccm-core/src/main/java/org/libreccm/l10n/L10NConstants.java new file mode 100644 index 000000000..73f3b20a0 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/l10n/L10NConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 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.l10n; + +/** + * + * @author Jens Pelzetter + */ +public final class L10NConstants { + + public static final String L10N_XML_NS = "http://l10n.libreccm.org"; + + private L10NConstants() { + //Nothing + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java b/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java index b7da4f1e3..456dcd6ec 100644 --- a/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java +++ b/ccm-core/src/main/java/org/libreccm/l10n/LocalizedString.java @@ -18,6 +18,8 @@ */ package org.libreccm.l10n; +import static org.libreccm.l10n.L10NConstants.*; + import java.io.Serializable; import java.util.Collections; import java.util.HashMap; @@ -31,8 +33,6 @@ import javax.persistence.ElementCollection; import javax.persistence.Embeddable; import javax.persistence.Lob; import javax.persistence.MapKeyColumn; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; @@ -46,8 +46,7 @@ import javax.xml.bind.annotation.XmlRootElement; * @author Jens Pelzetter */ @Embeddable -@XmlRootElement -@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "localized-string", namespace = L10N_XML_NS) public class LocalizedString implements Serializable { private static final long serialVersionUID = 7378282657084330425L; @@ -59,8 +58,8 @@ public class LocalizedString implements Serializable { @MapKeyColumn(name = "locale") @Column(name = "localized_value") @Lob - @XmlElementWrapper(name = "values") - @XmlElement(name = "value") + @XmlElementWrapper(name = "values", namespace = L10N_XML_NS) + @XmlElement(name = "value", namespace = L10N_XML_NS) private Map values; /** diff --git a/ccm-core/src/main/java/org/libreccm/l10n/package-info.java b/ccm-core/src/main/java/org/libreccm/l10n/package-info.java new file mode 100644 index 000000000..eb5ae79b6 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/l10n/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 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 + */ +@XmlSchema(xmlns = {@XmlNs(prefix = "l10n", namespaceURI = L10N_XML_NS)}) +@XmlAccessorType(XmlAccessType.NONE) +package org.libreccm.l10n; + +import static org.libreccm.l10n.L10NConstants.*; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlNs; +import javax.xml.bind.annotation.XmlSchema; + diff --git a/ccm-core/src/main/java/org/libreccm/web/Application.java b/ccm-core/src/main/java/org/libreccm/web/Application.java index 7626a12f7..d898679a2 100644 --- a/ccm-core/src/main/java/org/libreccm/web/Application.java +++ b/ccm-core/src/main/java/org/libreccm/web/Application.java @@ -18,20 +18,31 @@ */ package org.libreccm.web; +import static org.libreccm.web.WebConstants.*; + +import org.libreccm.categorization.Domain; +import org.libreccm.categorization.DomainOwnership; import org.libreccm.core.Resource; import org.libreccm.core.Group; import org.libreccm.jpa.utils.UriConverter; import java.io.Serializable; import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; import javax.persistence.Column; import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; /** * @@ -39,18 +50,34 @@ import javax.persistence.Table; */ @Entity @Table(name = "applications") +@XmlRootElement(name = "application", namespace = WEB_XML_NS) public class Application extends Resource implements Serializable { private static final long serialVersionUID = 9205226362368890784L; @Column(name = "primary_url", length = 1024, nullable = false) @Convert(converter = UriConverter.class) + @XmlElement(name = "primary-url", namespace = WEB_XML_NS) private URI primaryUrl; @OneToOne @JoinColumn(name = "container_group_id") + @XmlElement(name = "container-group", namespace = WEB_XML_NS) private Group containerGroup; + /** + * Category Domains owned by this {@code CcmObject}. + */ + @OneToMany(mappedBy = "owner") + @XmlElementWrapper(name = "domains", namespace = WEB_XML_NS) + @XmlElement(name = "domain", namespace = WEB_XML_NS) + private List domains; + + public Application() { + super(); + domains = new ArrayList<>(); + } + public URI getPrimaryUrl() { return primaryUrl; } @@ -67,6 +94,48 @@ public class Application extends Resource implements Serializable { this.containerGroup = containerGroup; } + /** + * Gets an unmodifiable list of the domains which are owned + * by the {@code Application}. + * + * @return An unmodifiable list of the domain ownerships of this + * {@code Application}. Might be {@code null} or empty. + */ + public List getDomains() { + return Collections.unmodifiableList(domains); + } + + /** + * Setter for the list of domain ownerships, only for use by JPA. + * + * @param domains A list of domain ownerships. + */ + protected void setDomains(final List domains) { + this.domains = domains; + } + + /** + * Internal method for adding a domain ownership. Users + * should use the appropriate methods of the {@link DomainManager} class to + * manage the {@link Domain}s assigned to {@code CcmObject}. + * + * @param domain The domain ownership to add. + */ + protected void addDomain(final DomainOwnership domain) { + domains.add(domain); + } + + /** + * Internal method for removing a domain ownership. Users + * should use the appropriate methods of the {@link DomainManager} to manage + * the {@link Domain}s assigned to {@code CcmObject}. + * + * @param domain The domain to remove. + */ + protected void removeDomain(final DomainOwnership domain) { + domains.remove(domain); + } + @Override public int hashCode() { int hash = super.hashCode(); @@ -99,7 +168,7 @@ public class Application extends Resource implements Serializable { } return Objects.equals(containerGroup, other.getContainerGroup()); } - + @Override public boolean canEqual(final Object obj) { return obj instanceof Application; diff --git a/ccm-core/src/main/java/org/libreccm/web/WebConstants.java b/ccm-core/src/main/java/org/libreccm/web/WebConstants.java new file mode 100644 index 000000000..8f1901374 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/web/WebConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 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.web; + +/** + * + * @author Jens Pelzetter + */ +public final class WebConstants { + + public static final String WEB_XML_NS = "http://web.libreccm.org"; + + private WebConstants() { + //Nothing + } + +} diff --git a/ccm-core/src/test/java/org/libreccm/categorization/EqualsAndHashCodeTest.java b/ccm-core/src/test/java/org/libreccm/categorization/EqualsAndHashCodeTest.java index ce34a7e72..51734389b 100644 --- a/ccm-core/src/test/java/org/libreccm/categorization/EqualsAndHashCodeTest.java +++ b/ccm-core/src/test/java/org/libreccm/categorization/EqualsAndHashCodeTest.java @@ -24,7 +24,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.libreccm.tests.categories.UnitTest; +import org.libreccm.web.Application; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collection; @@ -52,19 +55,25 @@ public class EqualsAndHashCodeTest { } @Test - public void verifyEqualsAndHashCode() { + public void verifyEqualsAndHashCode() throws URISyntaxException { final Category category1 = new Category(); category1.setName("Category One"); - + final Category category2 = new Category(); category2.setName("Category Two"); - + final Domain domain1 = new Domain(); domain1.setDomainKey("Domain-One"); - + final Domain domain2 = new Domain(); domain2.setDomainKey("Domain Two"); - + + final Application application1 = new Application(); + application1.setPrimaryUrl(new URI("http://application-one.exampl.org")); + + final Application application2 = new Application(); + application2.setPrimaryUrl(new URI("http://application-two.exampl.org")); + EqualsVerifier .forClass(entityClass) .suppress(Warning.STRICT_INHERITANCE) @@ -72,6 +81,7 @@ public class EqualsAndHashCodeTest { .withRedefinedSuperclass() .withPrefabValues(Category.class, category1, category2) .withPrefabValues(Domain.class, domain1, domain2) + .withPrefabValues(Application.class, application1, application2) .verify(); } diff --git a/ccm-core/src/test/java/org/libreccm/core/CcmObjectRepositoryTest.java b/ccm-core/src/test/java/org/libreccm/core/CcmObjectRepositoryTest.java index e3cb9fae6..148b25794 100644 --- a/ccm-core/src/test/java/org/libreccm/core/CcmObjectRepositoryTest.java +++ b/ccm-core/src/test/java/org/libreccm/core/CcmObjectRepositoryTest.java @@ -106,6 +106,7 @@ public class CcmObjectRepositoryTest { .create(WebArchive.class, "LibreCCM-org.libreccm.core.CcmObjectRepositoryTest.war"). addPackage(CcmObject.class.getPackage()) + .addPackage(org.libreccm.web.Application.class.getPackage()) .addPackage(org.libreccm.categorization.Category.class. getPackage()) .addPackage(org.libreccm.l10n.LocalizedString.class.getPackage()). diff --git a/pom.xml b/pom.xml index a146cbb37..bc9077fb0 100644 --- a/pom.xml +++ b/pom.xml @@ -29,9 +29,9 @@ ccm-core - ccm-shortcuts - ccm-testutils - + ccm-shortcuts + ccm-testutils +