diff --git a/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java b/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java
new file mode 100644
index 000000000..5721858a2
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java
@@ -0,0 +1,285 @@
+/*
+ * 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.CcmObject;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+
+/**
+ * The {@code CategoryManager} provides several helper methods for managing
+ * categories, their sub categories and the objects assigned to a categories.
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+public class CategoryManager {
+
+ /**
+ * A {@link CategoryRepository} instance used to interact with the database.
+ */
+ @Inject
+ private transient CategoryRepository categoryRepo;
+
+ /**
+ * Assigns an category to an object. The object is added at the position
+ * specified by the {@code order} parameter. If that position is already
+ * occupied the object currently assigned to that position and the objects
+ * after that object are moved one position down (the value of their
+ * {@code order} property is increased by one).
+ *
+ * If the position provided by the {@code order} parameter is larger than
+ * the value of the {@code order} property of the last object plus 1 the
+ * order property is set the the value of the {@code order} property of the
+ * last object plus one.
+ *
+ * If the order property is less than 0, the object is inserted at first
+ * position and the value of the {@code order} property is set to {@code 0}.
+ * The value of the {@code order} property of all other objects is increased
+ * by one.
+ *
+ * If the object is already assigned to the category and the value of the
+ * {@code order} property is different than the provided value the
+ * {@code order} property is set the provided value. No further action will
+ * executed.
+ *
+ * Please note: Because the association between {@link Category} and {@code
+ * CcmObject} is a many-to-many association we use an association object to
+ * store the additional attributes of the association. The
+ * {@link Categorization} entity is completely managed by this class.
+ *
+ * If either {@code object} or the {@code category} parameter are
+ * {@code null} an {@link IllegalArgumentException} is thrown because
+ * passing {@code null} to this method indicates a programming error.
+ *
+ * @param object The object to assign to the category. Can never be
+ * {@code null}.
+ * @param category The category to which the object should be assigned. Can
+ * never be {@code null}.
+ * @param order Order value specifying the sort order of the objects
+ * assigned to category.
+ */
+ public void addObjectToCategory(final CcmObject object,
+ final Category category,
+ final long order) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Removes a object from a category. Additionally to removing the object
+ * from the category this method also upgrades the order of all objects
+ * sorted in after the removed object so that the values are consistent
+ * without gaps (which may cause trouble).
+ *
+ * If either the {@code object} or the {@code category} parameter are
+ * {@code null} an {@link IllegalArgumentException} exception is thrown
+ * because passing {@code null} to either parameter indicates a programming
+ * error.
+ *
+ * @param object The object to remove from the category. Can never be
+ * {@code null}.
+ * @param category The category from which the object should be removed. Can
+ * never be {@code null}.
+ *
+ * @throws ObjectNotAssignedToCategoryException Thrown is the provided
+ * object is not
+ * assigned to the provided category.
+ */
+ public void removeObjectFromCategory(final CcmObject object,
+ final Category category)
+ throws ObjectNotAssignedToCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Increases the value of the {@code order} property of the provided object.
+ * The value of the {@code order} property of the object after the provided
+ * is decreased by one. Effectively the two objects are swapped.
+ *
+ * @param object The object which {@code order} property is decreased.
+ * Can't be {@code null}.
+ * @param category The category to which the object is assigned. Can't be
+ * {@code null}.
+ *
+ * @throws ObjectNotAssignedToCategoryException Throws if the provided
+ * object is not assigned to
+ * the provided category.
+ */
+ public void increaseObjectOrder(final CcmObject object,
+ final Category category)
+ throws ObjectNotAssignedToCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Decreases the value of the {@code order} property of the provided object.
+ * The value of the {@code order} property of the object before the provided
+ * is increased by one. Effectively the two objects are swapped.
+ *
+ * @param object The object which {@code order} property is decreased.
+ * Can't be {@code null}.
+ * @param category The category to which the object is assigned. Can't be
+ * {@code null}.
+ *
+ * @throws ObjectNotAssignedToCategoryException Throws if the provided
+ * object is not assigned to
+ * the provided category.
+ */
+ public void decreaseObjectOrder(final CcmObject object,
+ final Category category)
+ throws ObjectNotAssignedToCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Swaps two objects assigned to the same category. More exactly the values
+ * of the {@code order} property of the {@link Categorization} of the
+ * provided objects are swapped.
+ *
+ * @param objectA Th first object. Can't be {@code null}.
+ * @param objectB The second object. Can't be {@code null}.
+ * @param category Can't be {@code null}. The category to which both objects
+ * are assigned. Can't be {@code null}.
+ *
+ * @throws ObjectNotAssignedToCategoryException Thrown if one or both of the
+ * provided objects are not
+ * assigned to the provided
+ * category.
+ */
+ public void swapObjects(final CcmObject objectA,
+ final CcmObject objectB,
+ final Category category)
+ throws ObjectNotAssignedToCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Adds a category as an subcategory to another category. If the category is
+ * assigned to another category that association is removed.
+ *
+ * The method will ensure that values of the {@code order} properties of all
+ * subcategories will remain consistent. If the provided position is already
+ * occupied a the values of the {@code order} properties of the object
+ * occupying the provided positions and of all following objects are
+ * increased by one.
+ *
+ * If the provided value is larger than the value of the {@code order}
+ * property of the last object the value of the {@code property} is set the
+ * value of the of the {@code order} property of the last object plus one.
+ *
+ * The provided value is less than {@code 0} the object will be the first
+ * one and the value of the {@code order} property will be set to {@code 0}.
+ *
+ * If the provided category is already assigned to the provided parent
+ * category only the value of the {@code order} property is updated.
+ *
+ * @param subCategory The category to add as subcategory. Can't be
+ * {@code null}.
+ * @param parentCategory The category to which the category is added as
+ * subcategory. Can't be {@code null}.
+ * @param order The value for the {@code order} property of the
+ * association.
+ */
+ public void addSubCategoryToCategory(final Category subCategory,
+ final Category parentCategory,
+ final long order) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Removes a sub category from its parent category. If the category is not
+ * assigned to another parent category (or as root category to a
+ * {@link Domain} the category becomes orphaned.
+ *
+ * @param subCategory The subcategory to remove from the parent category.
+ * Can't be {@code null}.
+ * @param parentCategory The parent category. Can't be {@code null}.
+ *
+ * @throws NotASubCategoryException If the provided subcategory is not
+ * assigned to the provided parent
+ * category.
+ */
+ public void removeSubCategoryFromCategory(final Category subCategory,
+ final Category parentCategory)
+ throws NotASubCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Increases the value of the {@code order} property of the provided
+ * category by one. The value of the {@code order} property of the following
+ * objects is decreased by one. If the object is the last one this method
+ * has not effect.
+ *
+ * @param subCategory The category which order property is increased.
+ * Can't be {@code null}.
+ * @param parentCategory The parent category of the category. Can't be
+ * {@code null}.
+ *
+ * @throws NotASubCategoryException If the provided subcategory is not a
+ * subcategory of the provided parent
+ * category.
+ */
+ public void increaseCategoryOrder(final Category subCategory,
+ final Category parentCategory)
+ throws NotASubCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Decreases the value of the {@code order} property of the provided
+ * category by one. The value of the {@code order} property of the
+ * preceeding objects is increased by one. If the object is the last one
+ * this method has not effect.
+ *
+ * @param subCategory The category which order property is increased.
+ * Can't be {@code null}.
+ * @param parentCategory The parent category of the category. Can't be
+ * {@code null}.
+ *
+ * @throws NotASubCategoryException If the provided subcategory is not a
+ * subcategory of the provided parent
+ * category.
+ */
+ public void decreaseCategoryOrder(final Category subCategory,
+ final Category parentCategory)
+ throws NotASubCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Swaps the values of the {@code order} properties of two categories.
+ *
+ * @param subCategoryA The first category. Can't be {@code null}.
+ * @param subCategoryB The second category. Can't be {@code null}.
+ * @param parentCategory The parent category of both subcategories. Can't be
+ * {@code null}.
+ *
+ * @throws NotASubCategoryException If one or both categories are not
+ * subcategories of the provided parent category.
+ */
+ public void swapCategories(final Category subCategoryA,
+ final Category subCategoryB,
+ final Category parentCategory)
+ throws NotASubCategoryException {
+ throw new UnsupportedOperationException();
+ }
+
+}
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 45e434cc6..59330d80a 100644
--- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java
@@ -54,5 +54,16 @@ public class CategoryRepository extends AbstractEntityRepository
return query.getResultList();
}
+
+ /**
+ * Retrieves all categories which are not assigned to another category as
+ * subcategory or the an {@link Domain} as root category.
+ *
+ * @return A list of all orphaned categories. Normally this list should be
+ * empty.
+ */
+ public List getOrphanedCategories() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/ccm-core/src/main/java/org/libreccm/categorization/NotASubCategoryException.java b/ccm-core/src/main/java/org/libreccm/categorization/NotASubCategoryException.java
new file mode 100644
index 000000000..3e24b1f35
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/categorization/NotASubCategoryException.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+/**
+ * Indicates that a category passed to a method is not a sub category of another
+ * category also passed to the method.
+ *
+ * @author Jens Pelzetter
+ */
+public class NotASubCategoryException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of NotASubCategoryException without detail message.
+ */
+ public NotASubCategoryException() {
+ super();
+ }
+
+
+ /**
+ * Constructs an instance of NotASubCategoryException with the specified detail message.
+ *
+ * @param msg The detail message.
+ */
+ public NotASubCategoryException(final String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs an instance of NotASubCategoryException which wraps the
+ * specified exception.
+ *
+ * @param exception The exception to wrap.
+ */
+ public NotASubCategoryException(final Exception exception) {
+ super(exception);
+ }
+
+ /**
+ * Constructs an instance of NotASubCategoryException with the specified message which also wraps the
+ * specified exception.
+ *
+ * @param msg The detail message.
+ * @param exception The exception to wrap.
+ */
+ public NotASubCategoryException(final String msg, final Exception exception) {
+ super(msg, exception);
+ }
+}
diff --git a/ccm-core/src/main/java/org/libreccm/categorization/ObjectNotAssignedToCategoryException.java b/ccm-core/src/main/java/org/libreccm/categorization/ObjectNotAssignedToCategoryException.java
new file mode 100644
index 000000000..1577ccd26
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/categorization/ObjectNotAssignedToCategoryException.java
@@ -0,0 +1,72 @@
+/*
+ * 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.CcmObject;
+
+/**
+ * This exception indicates that an {@link CcmObject} passed to a method is not
+ * assigned to an {@link Category} which is also passed to the method.
+ *
+ *
+ * @author Jens Pelzetter
+ */
+public class ObjectNotAssignedToCategoryException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of ObjectNotAssignedToCategoryException without detail message.
+ */
+ public ObjectNotAssignedToCategoryException() {
+ super();
+ }
+
+
+ /**
+ * Constructs an instance of ObjectNotAssignedToCategoryException with the specified detail message.
+ *
+ * @param msg The detail message.
+ */
+ public ObjectNotAssignedToCategoryException(final String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs an instance of ObjectNotAssignedToCategoryException which wraps the
+ * specified exception.
+ *
+ * @param exception The exception to wrap.
+ */
+ public ObjectNotAssignedToCategoryException(final Exception exception) {
+ super(exception);
+ }
+
+ /**
+ * Constructs an instance of ObjectNotAssignedToCategoryException with the specified message which also wraps the
+ * specified exception.
+ *
+ * @param msg The detail message.
+ * @param exception The exception to wrap.
+ */
+ public ObjectNotAssignedToCategoryException(final String msg, final Exception exception) {
+ super(msg, exception);
+ }
+}