diff --git a/ccm-core/pom.xml b/ccm-core/pom.xml
index 704b666a2..b4f7099aa 100644
--- a/ccm-core/pom.xml
+++ b/ccm-core/pom.xml
@@ -43,6 +43,11 @@
hibernate-entitymanager
+
+ org.hibernate
+ hibernate-envers
+
+
org.hibernate
hibernate-validator
diff --git a/ccm-core/src/main/java/org/libreccm/auditing/AbstractAuditedEntityRepository.java b/ccm-core/src/main/java/org/libreccm/auditing/AbstractAuditedEntityRepository.java
new file mode 100644
index 000000000..5099e75ea
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/auditing/AbstractAuditedEntityRepository.java
@@ -0,0 +1,61 @@
+/*
+ * 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.auditing;
+
+import org.hibernate.envers.AuditReader;
+import org.hibernate.envers.query.AuditEntity;
+import org.hibernate.envers.query.AuditQuery;
+import org.libreccm.core.AbstractEntityRepository;
+
+import javax.inject.Inject;
+
+/**
+ *
+ * @author Jens Pelzetter
+ * @param Primary key of the entity.
+ * @param Type of the entity
+ */
+public abstract class AbstractAuditedEntityRepository
+ extends AbstractEntityRepository {
+
+ @Inject
+ private transient AuditReader auditReader;
+
+ public abstract K getEntityId(final T entity);
+
+ public T retrieveRevisionOfEntity(final T entity, final Number revision) {
+ final AuditQuery query = auditReader.createQuery()
+ .forEntitiesAtRevision(getEntityClass(), revision);
+ query.add(AuditEntity.id().eq(getEntityId(entity)));
+
+ final Object result = query.getSingleResult();
+
+ if (getEntityClass().isInstance(result)) {
+ return (T) result;
+ } else {
+ throw new AuditQueryException(String.format(
+ "The result is not an instance of the entity class. "
+ + "Entity class: \"%s\"; Result class: \"%s\"",
+ getEntityClass().getName(),
+ result.getClass().getName())
+ );
+ }
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/auditing/AuditQueryException.java b/ccm-core/src/main/java/org/libreccm/auditing/AuditQueryException.java
new file mode 100644
index 000000000..4af78718d
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/auditing/AuditQueryException.java
@@ -0,0 +1,67 @@
+/*
+ * 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.auditing;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class AuditQueryException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of AuditQueryException without detail message.
+ */
+ public AuditQueryException() {
+ super();
+ }
+
+
+ /**
+ * Constructs an instance of AuditQueryException with the specified detail message.
+ *
+ * @param msg The detail message.
+ */
+ public AuditQueryException(final String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs an instance of AuditQueryException which wraps the
+ * specified exception.
+ *
+ * @param exception The exception to wrap.
+ */
+ public AuditQueryException(final Exception exception) {
+ super(exception);
+ }
+
+ /**
+ * Constructs an instance of AuditQueryException with the specified message which also wraps the
+ * specified exception.
+ *
+ * @param msg The detail message.
+ * @param exception The exception to wrap.
+ */
+ public AuditQueryException(final String msg, final Exception exception) {
+ super(msg, exception);
+ }
+}
diff --git a/ccm-core/src/main/java/org/libreccm/auditing/CcmRevision.java b/ccm-core/src/main/java/org/libreccm/auditing/CcmRevision.java
new file mode 100644
index 000000000..a7d150fed
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/auditing/CcmRevision.java
@@ -0,0 +1,54 @@
+/*
+ * 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.auditing;
+
+import org.hibernate.envers.DefaultRevisionEntity;
+import org.hibernate.envers.RevisionEntity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Revision entity for Hibernate Envers containing the editing user. We are not
+ * using an association between this class and the user class because the user
+ * may be deleted but the revisions will stay. Therefore we use the value of the
+ * screenname property here.
+ *
+ * @author Jens Pelzetter
+ */
+@Entity
+@Table(name = "ccm_revisions")
+@RevisionEntity()
+public class CcmRevision extends DefaultRevisionEntity {
+
+ private static final long serialVersionUID = -3458682765535922544L;
+
+ @Column(name = "user_name")
+ private String userName;
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(final String userName) {
+ this.userName = userName;
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/auditing/CcmRevisionListener.java b/ccm-core/src/main/java/org/libreccm/auditing/CcmRevisionListener.java
new file mode 100644
index 000000000..c581f39c3
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/auditing/CcmRevisionListener.java
@@ -0,0 +1,54 @@
+/*
+ * 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.auditing;
+
+import org.hibernate.envers.RevisionListener;
+import org.libreccm.core.CcmSessionContext;
+import org.libreccm.core.Subject;
+import org.libreccm.core.User;
+
+import javax.inject.Inject;
+
+/**
+ * {@link RevisionListener} setting the user for the {@link CcmRevision} entity.
+ *
+ * @author Jens Pelzetter
+ */
+public class CcmRevisionListener implements RevisionListener {
+
+ @Inject
+ private transient CcmSessionContext sessionContext;
+
+ @Override
+ public void newRevision(final Object revisionEntity) {
+ if (!(revisionEntity instanceof CcmRevision)) {
+ throw new IllegalArgumentException(String.format(
+ "Provided revision entity is not an instance of class \"%s\".",
+ CcmRevision.class.getName()));
+ }
+
+ final CcmRevision revision = (CcmRevision) revisionEntity;
+ final Subject subject = sessionContext.getCurrentSubject();
+ if (subject instanceof User) {
+ final User user = (User) subject;
+ revision.setUserName(user.getScreenName());
+ }
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/auditing/package-info.java b/ccm-core/src/main/java/org/libreccm/auditing/package-info.java
new file mode 100644
index 000000000..44dd459e2
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/auditing/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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
+ */
+/**
+ * This package contains supplemental classes for auditing entities using
+ * Hibernate Envers.
+ */
+package org.libreccm.auditing;
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 be369c1de..53d6acfb6 100644
--- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java
+++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java
@@ -79,6 +79,7 @@ public class CategoryManager {
public void addObjectToCategory(final CcmObject object,
final Category category,
final long order) {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -105,6 +106,7 @@ public class CategoryManager {
public void removeObjectFromCategory(final CcmObject object,
final Category category)
throws ObjectNotAssignedToCategoryException {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -125,6 +127,7 @@ public class CategoryManager {
public void increaseObjectOrder(final CcmObject object,
final Category category)
throws ObjectNotAssignedToCategoryException {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -145,6 +148,7 @@ public class CategoryManager {
public void decreaseObjectOrder(final CcmObject object,
final Category category)
throws ObjectNotAssignedToCategoryException {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -167,6 +171,7 @@ public class CategoryManager {
final CcmObject objectB,
final Category category)
throws ObjectNotAssignedToCategoryException {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -200,6 +205,7 @@ public class CategoryManager {
public void addSubCategoryToCategory(final Category subCategory,
final Category parentCategory,
final long order) {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -219,6 +225,7 @@ public class CategoryManager {
public void removeSubCategoryFromCategory(final Category subCategory,
final Category parentCategory)
throws NotASubCategoryException {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -240,6 +247,7 @@ public class CategoryManager {
public void increaseCategoryOrder(final Category subCategory,
final Category parentCategory)
throws NotASubCategoryException {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -261,6 +269,7 @@ public class CategoryManager {
public void decreaseCategoryOrder(final Category subCategory,
final Category parentCategory)
throws NotASubCategoryException {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -279,6 +288,7 @@ public class CategoryManager {
final Category subCategoryB,
final Category parentCategory)
throws NotASubCategoryException {
+ // TODO implement method
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 59330d80a..7e4ae67ae 100644
--- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java
@@ -63,6 +63,7 @@ public class CategoryRepository extends AbstractEntityRepository
* empty.
*/
public List getOrphanedCategories() {
+ // TODO implement method
throw new UnsupportedOperationException();
}
diff --git a/ccm-core/src/main/java/org/libreccm/categorization/DomainManager.java b/ccm-core/src/main/java/org/libreccm/categorization/DomainManager.java
index c1de518f8..fb53861cd 100644
--- a/ccm-core/src/main/java/org/libreccm/categorization/DomainManager.java
+++ b/ccm-core/src/main/java/org/libreccm/categorization/DomainManager.java
@@ -47,6 +47,7 @@ public class DomainManager {
*/
public void addDomainOwner(final Application application,
final Domain domain) {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -62,6 +63,7 @@ public class DomainManager {
*/
public void removeDomainOwner(final Application application,
final Domain domain) {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -75,6 +77,7 @@ public class DomainManager {
*/
public boolean isDomainOwner(final Application application,
final Domain domain) {
+ // TODO implement method
throw new UnsupportedOperationException();
}
diff --git a/ccm-core/src/main/java/org/libreccm/categorization/DomainRepository.java b/ccm-core/src/main/java/org/libreccm/categorization/DomainRepository.java
index 520082383..c4dfc7dce 100644
--- a/ccm-core/src/main/java/org/libreccm/categorization/DomainRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/categorization/DomainRepository.java
@@ -56,6 +56,7 @@ public class DomainRepository extends AbstractEntityRepository {
* {@code null} if there is no such {@code Domain}.
*/
public Domain findByDomainKey(final String domainKey) {
+ // TODO implement method
throw new UnsupportedOperationException();
}
@@ -68,6 +69,7 @@ public class DomainRepository extends AbstractEntityRepository {
* if there is so such {@code Domain}.
*/
public Domain findByUri(final URI uri) {
+ // TODO implement method
throw new UnsupportedOperationException();
}
diff --git a/ccm-core/src/main/java/org/libreccm/jpa/EntityManagerProducer.java b/ccm-core/src/main/java/org/libreccm/jpa/EntityManagerProducer.java
index acc13b036..cd2c36572 100644
--- a/ccm-core/src/main/java/org/libreccm/jpa/EntityManagerProducer.java
+++ b/ccm-core/src/main/java/org/libreccm/jpa/EntityManagerProducer.java
@@ -1,5 +1,8 @@
package org.libreccm.jpa;
+import org.hibernate.envers.AuditReader;
+import org.hibernate.envers.AuditReaderFactory;
+
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
@@ -17,4 +20,7 @@ public class EntityManagerProducer {
@PersistenceContext(name = "LibreCCM")
private EntityManager entityManager;
+ @Produces
+ private AuditReader auditReader = AuditReaderFactory.get(entityManager);
+
}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/Bar.java b/ccm-core/src/main/java/org/libreccm/modules/Bar.java
new file mode 100644
index 000000000..93770758c
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/Bar.java
@@ -0,0 +1,47 @@
+/*
+ * 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.modules;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class Bar implements Module {
+
+ @Override
+ public void prepare() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void uninstall() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void init() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void shutdown() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/Example.java b/ccm-core/src/main/java/org/libreccm/modules/Example.java
new file mode 100644
index 000000000..606181e19
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/Example.java
@@ -0,0 +1,47 @@
+/*
+ * 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.modules;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class Example implements Module {
+
+ @Override
+ public void prepare() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void uninstall() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void init() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void shutdown() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/Foo.java b/ccm-core/src/main/java/org/libreccm/modules/Foo.java
new file mode 100644
index 000000000..738a25689
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/Foo.java
@@ -0,0 +1,54 @@
+/*
+ * 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.modules;
+
+import org.libreccm.modules.annotations.RequiredModule;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@org.libreccm.modules.annotations.Module(name = "org.libreccm.foo.Foo",
+ version = "1.0.0-beta.1",
+ requiredModules = {
+ @RequiredModule(module = Bar.class, version = "1.0.0"),
+ @RequiredModule(module= Example.class, version = "6.6.7")})
+public class Foo implements Module {
+
+ @Override
+ public void prepare() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void uninstall() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void init() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void shutdown() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/Module.java b/ccm-core/src/main/java/org/libreccm/modules/Module.java
new file mode 100644
index 000000000..d8cf09005
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/Module.java
@@ -0,0 +1,52 @@
+/*
+ * 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.modules;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public interface Module {
+
+ /**
+ * Called by the {@link ModuleManager} after the database tables for the
+ * module have been created. Use this method to create initial or example
+ * data.
+ */
+ void prepare();
+
+ /**
+ * Called by the {@link ModuleManager} when a module is removed from the
+ * installation. If necessary clean up the data of the module in the
+ * implementation of this method.
+ */
+ void uninstall();
+
+ /**
+ * Called each time the CCM application is started. Use an implementation of
+ * this method for creating static instances or for integrity checking.
+ */
+ void init();
+
+ /**
+ * Called each time the CCM application stops.
+ */
+ void shutdown();
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/ModuleManager.java b/ccm-core/src/main/java/org/libreccm/modules/ModuleManager.java
new file mode 100644
index 000000000..6731765c1
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/ModuleManager.java
@@ -0,0 +1,37 @@
+/*
+ * 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.modules;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@ApplicationScoped
+public class ModuleManager {
+
+ @Inject
+ private transient Instance modules;
+
+
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/ModuleUtil.java b/ccm-core/src/main/java/org/libreccm/modules/ModuleUtil.java
new file mode 100644
index 000000000..3a0807bf6
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/ModuleUtil.java
@@ -0,0 +1,78 @@
+/*
+ * 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.modules;
+
+import org.libreccm.modules.annotations.RequiredModule;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class ModuleUtil {
+
+ private ModuleUtil() {
+ //Nothing
+ }
+
+ private static org.libreccm.modules.annotations.Module getModuleAnnotation(
+ final Module module) {
+ final org.libreccm.modules.annotations.Module annotation = module
+ .getClass().getAnnotation(
+ org.libreccm.modules.annotations.Module.class);
+
+ if (annotation == null) {
+ throw new IllegalArgumentException(String.format(
+ "The provided implementation of the "
+ + "org.libreccm.modules.Module interface, \"%s\", is not"
+ + "annotated with org.libreccm.modules.annotations.Module",
+ module.getClass().getName()));
+ } else {
+ return annotation;
+ }
+ }
+
+ public static String getModuleName(final Module module) {
+ return getModuleAnnotation(module).name();
+ }
+
+ public static String getVersion(final Module module) {
+ return getModuleAnnotation(module).version();
+ }
+
+ public static RequiredModule[] getRequiredModules(final Module module) {
+ return getModuleAnnotation(module).requiredModules();
+ }
+
+ public static String getModuleName(Class extends Module> module) {
+ final org.libreccm.modules.annotations.Module annotation = module
+ .getAnnotation(org.libreccm.modules.annotations.Module.class);
+
+ if (annotation == null) {
+ throw new IllegalArgumentException(String.format(
+ "The provided implementation of the "
+ + "org.libreccm.modules.Module interface, \"%s\", is not"
+ + "annotated with org.libreccm.modules.annotations.Module",
+ module.getClass().getName()));
+ } else {
+ return annotation.name();
+ }
+
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/annotations/Module.java b/ccm-core/src/main/java/org/libreccm/modules/annotations/Module.java
new file mode 100644
index 000000000..6015af003
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/annotations/Module.java
@@ -0,0 +1,49 @@
+/*
+ * 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.modules.annotations;
+
+import org.jboss.as.server.moduleservice.ModuleDefinition;
+
+import static java.lang.annotation.ElementType.*;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.enterprise.util.Nonbinding;
+import javax.inject.Qualifier;
+
+/**
+ * Annotate an implementation of the {@link ModuleDefinition} interface with
+ * this annotation to use it as a module.
+ *
+ * @author Jens Pelzetter
+ */
+@Target({METHOD, FIELD, PARAMETER, TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+public @interface Module {
+
+ @Nonbinding String name() default "";
+
+ @Nonbinding String version() default "";
+
+ @Nonbinding RequiredModule[] requiredModules() default {};
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/annotations/RequiredModule.java b/ccm-core/src/main/java/org/libreccm/modules/annotations/RequiredModule.java
new file mode 100644
index 000000000..edc5c7741
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/annotations/RequiredModule.java
@@ -0,0 +1,31 @@
+/*
+ * 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.modules.annotations;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public @interface RequiredModule {
+
+ Class extends org.libreccm.modules.Module> module();
+
+ String version() default "";
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/dependencytree/DependencyException.java b/ccm-core/src/main/java/org/libreccm/modules/dependencytree/DependencyException.java
new file mode 100644
index 000000000..28bdabc26
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/dependencytree/DependencyException.java
@@ -0,0 +1,67 @@
+/*
+ * 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.modules.dependencytree;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class DependencyException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of DependencyException without detail message.
+ */
+ public DependencyException() {
+ super();
+ }
+
+
+ /**
+ * Constructs an instance of DependencyException with the specified detail message.
+ *
+ * @param msg The detail message.
+ */
+ public DependencyException(final String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs an instance of DependencyException which wraps the
+ * specified exception.
+ *
+ * @param exception The exception to wrap.
+ */
+ public DependencyException(final Exception exception) {
+ super(exception);
+ }
+
+ /**
+ * Constructs an instance of DependencyException with the specified message which also wraps the
+ * specified exception.
+ *
+ * @param msg The detail message.
+ * @param exception The exception to wrap.
+ */
+ public DependencyException(final String msg, final Exception exception) {
+ super(msg, exception);
+ }
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/dependencytree/DependencyTreeManager.java b/ccm-core/src/main/java/org/libreccm/modules/dependencytree/DependencyTreeManager.java
new file mode 100644
index 000000000..648fc0660
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/dependencytree/DependencyTreeManager.java
@@ -0,0 +1,179 @@
+/*
+ * 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.modules.dependencytree;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.libreccm.modules.Module;
+import org.libreccm.modules.ModuleUtil;
+import org.libreccm.modules.annotations.RequiredModule;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.enterprise.inject.Instance;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class DependencyTreeManager {
+
+ private static final Logger LOGGER = LogManager.getLogger(
+ DependencyTreeManager.class);
+
+ public List generateTree(final Instance modules) throws
+ DependencyException {
+
+ LOGGER.info("Starting to generate dependency tree...");
+
+ final Map nodes = new HashMap<>();
+
+ for (final Module module : modules) {
+ createTreeNode(module, nodes);
+ }
+
+ for (final Module module : modules) {
+ addDependencyRelations(module, nodes);
+ }
+
+ final List nodeList = new ArrayList<>();
+ for (Map.Entry entry : nodes.entrySet()) {
+ nodeList.add(entry.getValue());
+ }
+
+ LOGGER.info("Dependency tree generated.");
+
+ return nodeList;
+ }
+
+ public List orderModules(final List dependencyTree)
+ throws DependencyException {
+ LOGGER.info("Creating an ordered list from the dependency tree...");
+
+ final List orderedModules = new ArrayList<>();
+ final List resolvedModules = new ArrayList<>();
+
+ LOGGER.info("Looking for modules which do not depend on any other "
+ + "modules...");
+ for (final TreeNode node : dependencyTree) {
+ if (node.getDependsOn().isEmpty()) {
+ LOGGER.info(
+ "\tModule \"{}\" does not depend on any other module",
+ ModuleUtil.getModuleName(node.getModule()));
+ resolvedModules.add(node);
+ }
+ }
+
+ LOGGER.info("Ordering remaining nodes...");
+ while (!resolvedModules.isEmpty()) {
+
+ final TreeNode current = resolvedModules.remove(0);
+ LOGGER.info("\tProcessing node for module \"{}\"...",
+ ModuleUtil.getModuleName(current.getModule()));
+
+ orderedModules.add(current);
+
+ for (final TreeNode dependent : current.getDependentModules()) {
+ dependent.removeDependsOn(current);
+
+ if (dependent.getDependsOn().isEmpty()) {
+ resolvedModules.add(dependent);
+ }
+ }
+ }
+
+ if (orderedModules.size() == dependencyTree.size()) {
+ LOGGER.info("Dependency graph proceessed successfully. "
+ + "Modules in order:");
+ for (final TreeNode node : orderedModules) {
+ LOGGER.info("\t{}", ModuleUtil.getModuleName(node.getModule()));
+ }
+
+ return orderedModules;
+ } else {
+ LOGGER.fatal("The dependency graph has a least one cycle.");
+ throw new DependencyException(
+ "The dependency graph has a least one cycle.");
+ }
+ }
+
+ private void createTreeNode(final Module module,
+ final Map nodes) {
+ final TreeNode node = new TreeNode(module);
+
+ LOGGER.info("Creating node for module \"{}\"...",
+ ModuleUtil.getModuleName(module));
+ nodes.put(ModuleUtil.getModuleName(module), node);
+ }
+
+ private void addDependencyRelations(final Module module,
+ final Map nodes)
+ throws DependencyException {
+
+ LOGGER.info("Adding dependency relations for module \"{}\"...",
+ ModuleUtil.getModuleName(module));
+
+ final String moduleName = ModuleUtil.getModuleName(module);
+
+ if (!nodes.containsKey(moduleName)) {
+ LOGGER.fatal("Modules nodes map does contain an entry for \"{}\". "
+ + "That should not happen.",
+ ModuleUtil.getModuleName(module));
+ throw new IllegalArgumentException(String.format(
+ "The nodes map does not contain a node for module \"%s\". "
+ + "That should not happen.",
+ moduleName));
+ }
+
+ final TreeNode node = nodes.get(moduleName);
+ LOGGER.info("Processing required modules for module \"{}\"...",
+ ModuleUtil.getModuleName(module));
+ for (RequiredModule requiredModule : ModuleUtil.getRequiredModules(
+ module)) {
+
+ LOGGER.info("\tModule \"{}\" requires module \"{}\".",
+ ModuleUtil.getModuleName(module),
+ ModuleUtil.getModuleName(requiredModule.module()));
+
+ if (!nodes.containsKey(ModuleUtil.getModuleName(requiredModule
+ .module()))) {
+
+ LOGGER.fatal("Required module \"{}\" no found.",
+ ModuleUtil.getModuleName(requiredModule.module()));
+
+ throw new DependencyException(String.format(
+ "Module \"%s\" depends on module \"%s\" but the dependency "
+ + "tree does contain an entry for module \"%s\".",
+ ModuleUtil.getModuleName(module),
+ ModuleUtil.getModuleName(requiredModule.module()),
+ ModuleUtil.getModuleName(requiredModule.module())));
+ }
+
+ final TreeNode dependencyNode = nodes.get(ModuleUtil.getModuleName(
+ requiredModule.module()));
+
+ node.addDependsOn(node);
+ dependencyNode.addDependentModule(node);
+ }
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/dependencytree/TreeNode.java b/ccm-core/src/main/java/org/libreccm/modules/dependencytree/TreeNode.java
new file mode 100644
index 000000000..3a5542624
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/modules/dependencytree/TreeNode.java
@@ -0,0 +1,129 @@
+/*
+ * 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.modules.dependencytree;
+
+import org.libreccm.modules.Module;
+import org.libreccm.modules.ModuleUtil;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public final class TreeNode {
+
+ private Module module;
+ private List dependentModules;
+ private List dependsOn;
+
+ public TreeNode() {
+ super();
+
+ dependentModules = new ArrayList<>();
+ dependentModules = new ArrayList<>();
+ }
+
+ public TreeNode(final Module module) {
+ this();
+
+ this.module = module;
+ }
+
+ public Module getModule() {
+ return module;
+ }
+
+ public void setModule(final Module module) {
+ this.module = module;
+ }
+
+ public List getDependentModules() {
+ return Collections.unmodifiableList(dependentModules);
+ }
+
+ protected void setDependentModules(final List dependentModules) {
+ this.dependentModules = dependentModules;
+ }
+
+ protected void addDependentModule(final TreeNode node) {
+ dependentModules.add(node);
+ }
+
+ protected void removeDependentModule(final TreeNode node) {
+ dependentModules.remove(node);
+ }
+
+ public List getDependsOn() {
+ return Collections.unmodifiableList(dependsOn);
+ }
+
+ protected void setDependsOn(final List dependsOn) {
+ this.dependsOn = dependsOn;
+ }
+
+ protected void addDependsOn(final TreeNode node) {
+ dependsOn.add(node);
+ }
+
+ protected void removeDependsOn(final TreeNode node) {
+ dependsOn.remove(node);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+
+ final String moduleName = ModuleUtil.getModuleName(module);
+ final String version = ModuleUtil.getVersion(module);
+
+ hash = 37 * hash + Objects.hashCode(moduleName);
+ hash = 37 * hash + Objects.hashCode(version);
+
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object object) {
+ if (object == null) {
+ return false;
+ }
+
+ if (!(object instanceof TreeNode)) {
+ return false;
+ }
+
+ final TreeNode other = (TreeNode) object;
+ final String name = ModuleUtil.getModuleName(module);
+ final String otherName = ModuleUtil.getModuleName(other.getModule());
+
+ if (!name.equals(otherName)) {
+ return false;
+ }
+
+ final String version = ModuleUtil.getVersion(module);
+ final String otherVersion = ModuleUtil.getVersion(other.getModule());
+
+ return version.equals(otherVersion);
+ }
+
+}
diff --git a/ccm-core/src/main/resources/META-INF/persistence.xml b/ccm-core/src/main/resources/META-INF/persistence.xml
index e85eb1f78..dc0ea24b5 100644
--- a/ccm-core/src/main/resources/META-INF/persistence.xml
+++ b/ccm-core/src/main/resources/META-INF/persistence.xml
@@ -24,9 +24,18 @@
+
+
+
+
diff --git a/ccm-core/src/test/java/org/libreccm/modules/dependencytree/DependencyTreeManagerTest.java b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/DependencyTreeManagerTest.java
new file mode 100644
index 000000000..27fb120e8
--- /dev/null
+++ b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/DependencyTreeManagerTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.modules.dependencytree;
+
+import static org.hamcrest.Matchers.*;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.resolver.api.maven.Maven;
+import org.jboss.shrinkwrap.resolver.api.maven.PomEquippedResolveStage;
+import org.junit.After;
+import org.junit.AfterClass;
+
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.libreccm.modules.Module;
+import org.libreccm.tests.categories.IntegrationTest;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@Category(IntegrationTest.class)
+@RunWith(Arquillian.class)
+public class DependencyTreeManagerTest {
+
+ @Inject
+ @org.libreccm.modules.annotations.Module
+ private transient Instance modules;
+
+ public DependencyTreeManagerTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Deployment
+ public static WebArchive createDeployment() {
+ final PomEquippedResolveStage pom = Maven
+ .resolver()
+ .loadPomFromFile("pom.xml");
+ final PomEquippedResolveStage dependencies = pom
+ .importCompileAndRuntimeDependencies();
+ final File[] libs = dependencies.resolve().withTransitivity().asFile();
+
+ for (File lib : libs) {
+ System.err.printf("Adding file '%s' to test archive...%n",
+ lib.getName());
+ }
+
+ return ShrinkWrap
+ .create(WebArchive.class,
+ "LibreCCM-org.libreccm.modules.dependencytree.DependencyTreeManager.war")
+ .addPackage(DependencyTreeManager.class.getPackage())
+ .addPackage(org.libreccm.modules.annotations.Module.class
+ .getPackage())
+ .addPackage(org.libreccm.tests.categories.IntegrationTest.class
+ .getPackage())
+ .addClass(org.libreccm.modules.Module.class)
+ .addClass(org.libreccm.modules.ModuleUtil.class)
+ .addAsWebInfResource("test-web.xml", "web.xml")
+ .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void allModulesInjected() {
+
+ final List> moduleList = new ArrayList<>();
+ for (final Module module : modules) {
+ moduleList.add((Class) module.getClass());
+ }
+
+ assertThat(moduleList.size(), is(4));
+ assertThat(moduleList, containsInAnyOrder(TestModuleRoot.class,
+ TestModuleA.class,
+ TestModuleB.class,
+ TestModuleC.class));
+
+ }
+
+}
diff --git a/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleA.java b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleA.java
new file mode 100644
index 000000000..09a007910
--- /dev/null
+++ b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleA.java
@@ -0,0 +1,54 @@
+/*
+ * 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.modules.dependencytree;
+
+import org.libreccm.modules.Module;
+import org.libreccm.modules.annotations.RequiredModule;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@org.libreccm.modules.annotations.Module(
+ name = "org.libreccm.core.ccm-testmodule-a", version = "1.0.0",
+ requiredModules = {
+ @RequiredModule(module = TestModuleRoot.class)})
+public class TestModuleA implements Module {
+
+ @Override
+ public void prepare() {
+ //Nothing
+ }
+
+ @Override
+ public void uninstall() {
+ //Nothing
+ }
+
+ @Override
+ public void init() {
+ //Nothing
+ }
+
+ @Override
+ public void shutdown() {
+ //Nothing
+ }
+
+}
diff --git a/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleB.java b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleB.java
new file mode 100644
index 000000000..b2fd15e32
--- /dev/null
+++ b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleB.java
@@ -0,0 +1,54 @@
+/*
+ * 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.modules.dependencytree;
+
+import org.libreccm.modules.Module;
+import org.libreccm.modules.annotations.RequiredModule;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@org.libreccm.modules.annotations.Module(
+ name = "org.libreccm.core.ccm-testmodule-a", version = "1.0.0",
+ requiredModules = {
+ @RequiredModule(module = TestModuleRoot.class)})
+public class TestModuleB implements Module {
+
+ @Override
+ public void prepare() {
+ //Nothing
+ }
+
+ @Override
+ public void uninstall() {
+ //Nothing
+ }
+
+ @Override
+ public void init() {
+ //Nothing
+ }
+
+ @Override
+ public void shutdown() {
+ //Nothing
+ }
+
+}
diff --git a/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleC.java b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleC.java
new file mode 100644
index 000000000..e11ee48b6
--- /dev/null
+++ b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleC.java
@@ -0,0 +1,55 @@
+/*
+ * 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.modules.dependencytree;
+
+import org.libreccm.modules.Module;
+import org.libreccm.modules.annotations.RequiredModule;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@org.libreccm.modules.annotations.Module(
+ name = "org.libreccm.core.ccm-testmodule-a", version = "1.0.0",
+ requiredModules = {
+ @RequiredModule(module = TestModuleRoot.class),
+ @RequiredModule(module = TestModuleA.class)})
+public class TestModuleC implements Module {
+
+ @Override
+ public void prepare() {
+ //Nothing
+ }
+
+ @Override
+ public void uninstall() {
+ //Nothing
+ }
+
+ @Override
+ public void init() {
+ //Nothing
+ }
+
+ @Override
+ public void shutdown() {
+ //Nothing
+ }
+
+}
diff --git a/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleRoot.java b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleRoot.java
new file mode 100644
index 000000000..49e7df808
--- /dev/null
+++ b/ccm-core/src/test/java/org/libreccm/modules/dependencytree/TestModuleRoot.java
@@ -0,0 +1,51 @@
+/*
+ * 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.modules.dependencytree;
+
+import org.libreccm.modules.Module;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@org.libreccm.modules.annotations.Module(
+ name = "org.libreccm.core.ccm-testmodule-a", version = "1.0.0")
+public class TestModuleRoot implements Module {
+
+ @Override
+ public void prepare() {
+ //Nothing
+ }
+
+ @Override
+ public void uninstall() {
+ //Nothing
+ }
+
+ @Override
+ public void init() {
+ //Nothing
+ }
+
+ @Override
+ public void shutdown() {
+ //Nothing
+ }
+
+}
diff --git a/ccm-core/src/test/resources-tomee-embedded/test-persistence.xml b/ccm-core/src/test/resources-tomee-embedded/test-persistence.xml
index df9065f98..5b74c8a71 100644
--- a/ccm-core/src/test/resources-tomee-embedded/test-persistence.xml
+++ b/ccm-core/src/test/resources-tomee-embedded/test-persistence.xml
@@ -25,6 +25,14 @@
+
+
+
diff --git a/ccm-core/src/test/resources-tomee-remote-pgsql/test-persistence.xml b/ccm-core/src/test/resources-tomee-remote-pgsql/test-persistence.xml
index 9a5bee458..5126c7654 100644
--- a/ccm-core/src/test/resources-tomee-remote-pgsql/test-persistence.xml
+++ b/ccm-core/src/test/resources-tomee-remote-pgsql/test-persistence.xml
@@ -26,6 +26,14 @@
+
+
+
diff --git a/ccm-core/src/test/resources-wildfly8-embedded/test-persistence.xml b/ccm-core/src/test/resources-wildfly8-embedded/test-persistence.xml
index b59fd75d3..3912ba83e 100644
--- a/ccm-core/src/test/resources-wildfly8-embedded/test-persistence.xml
+++ b/ccm-core/src/test/resources-wildfly8-embedded/test-persistence.xml
@@ -26,6 +26,14 @@
+
+
+
diff --git a/ccm-core/src/test/resources-wildfly8-remote-h2-mem/test-persistence.xml b/ccm-core/src/test/resources-wildfly8-remote-h2-mem/test-persistence.xml
index 9c65918f0..186fd9255 100644
--- a/ccm-core/src/test/resources-wildfly8-remote-h2-mem/test-persistence.xml
+++ b/ccm-core/src/test/resources-wildfly8-remote-h2-mem/test-persistence.xml
@@ -26,6 +26,14 @@
+
+
+
diff --git a/ccm-core/src/test/resources-wildfly8-remote-mysql/test-persistence.xml b/ccm-core/src/test/resources-wildfly8-remote-mysql/test-persistence.xml
index cc3b2cc77..d7a557597 100644
--- a/ccm-core/src/test/resources-wildfly8-remote-mysql/test-persistence.xml
+++ b/ccm-core/src/test/resources-wildfly8-remote-mysql/test-persistence.xml
@@ -26,6 +26,14 @@
+
+
+
diff --git a/ccm-core/src/test/resources-wildfly8-remote-pgsql/test-persistence.xml b/ccm-core/src/test/resources-wildfly8-remote-pgsql/test-persistence.xml
index 9a5bee458..5126c7654 100644
--- a/ccm-core/src/test/resources-wildfly8-remote-pgsql/test-persistence.xml
+++ b/ccm-core/src/test/resources-wildfly8-remote-pgsql/test-persistence.xml
@@ -26,6 +26,14 @@
+
+
+