- Abstract base class for repositories for audited entities (using Envers)
- First part for the reworked load (or better install) and init part for LibreCCM NG. Needs to be tested and is not finished.


git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3566 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2015-08-11 18:20:21 +00:00
parent 7bb3c52c6c
commit 5580d94608
34 changed files with 1453 additions and 0 deletions

View File

@ -43,6 +43,11 @@
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <K> Primary key of the entity.
* @param <T> Type of the entity
*/
public abstract class AbstractAuditedEntityRepository<K, T>
extends AbstractEntityRepository<K, T> {
@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())
);
}
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class AuditQueryException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of <code>AuditQueryException</code> without detail message.
*/
public AuditQueryException() {
super();
}
/**
* Constructs an instance of <code>AuditQueryException</code> with the specified detail message.
*
* @param msg The detail message.
*/
public AuditQueryException(final String msg) {
super(msg);
}
/**
* Constructs an instance of <code>AuditQueryException</code> which wraps the
* specified exception.
*
* @param exception The exception to wrap.
*/
public AuditQueryException(final Exception exception) {
super(exception);
}
/**
* Constructs an instance of <code>AuditQueryException</code> 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);
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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;
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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());
}
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -63,6 +63,7 @@ public class CategoryRepository extends AbstractEntityRepository<Long, Category>
* empty.
*/
public List<Category> getOrphanedCategories() {
// TODO implement method
throw new UnsupportedOperationException();
}

View File

@ -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();
}

View File

@ -56,6 +56,7 @@ public class DomainRepository extends AbstractEntityRepository<Long, Domain> {
* {@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<Long, Domain> {
* if there is so such {@code Domain}.
*/
public Domain findByUri(final URI uri) {
// TODO implement method
throw new UnsupportedOperationException();
}

View File

@ -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);
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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.
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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.
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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.
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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();
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ApplicationScoped
public class ModuleManager {
@Inject
private transient Instance<Module> modules;
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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();
}
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Target({METHOD, FIELD, PARAMETER, TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Module {
@Nonbinding String name() default "";
@Nonbinding String version() default "";
@Nonbinding RequiredModule[] requiredModules() default {};
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public @interface RequiredModule {
Class<? extends org.libreccm.modules.Module> module();
String version() default "";
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class DependencyException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of <code>DependencyException</code> without detail message.
*/
public DependencyException() {
super();
}
/**
* Constructs an instance of <code>DependencyException</code> with the specified detail message.
*
* @param msg The detail message.
*/
public DependencyException(final String msg) {
super(msg);
}
/**
* Constructs an instance of <code>DependencyException</code> which wraps the
* specified exception.
*
* @param exception The exception to wrap.
*/
public DependencyException(final Exception exception) {
super(exception);
}
/**
* Constructs an instance of <code>DependencyException</code> 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);
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class DependencyTreeManager {
private static final Logger LOGGER = LogManager.getLogger(
DependencyTreeManager.class);
public List<TreeNode> generateTree(final Instance<Module> modules) throws
DependencyException {
LOGGER.info("Starting to generate dependency tree...");
final Map<String, TreeNode> nodes = new HashMap<>();
for (final Module module : modules) {
createTreeNode(module, nodes);
}
for (final Module module : modules) {
addDependencyRelations(module, nodes);
}
final List<TreeNode> nodeList = new ArrayList<>();
for (Map.Entry<String, TreeNode> entry : nodes.entrySet()) {
nodeList.add(entry.getValue());
}
LOGGER.info("Dependency tree generated.");
return nodeList;
}
public List<TreeNode> orderModules(final List<TreeNode> dependencyTree)
throws DependencyException {
LOGGER.info("Creating an ordered list from the dependency tree...");
final List<TreeNode> orderedModules = new ArrayList<>();
final List<TreeNode> 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<String, TreeNode> 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<String, TreeNode> 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);
}
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public final class TreeNode {
private Module module;
private List<TreeNode> dependentModules;
private List<TreeNode> 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<TreeNode> getDependentModules() {
return Collections.unmodifiableList(dependentModules);
}
protected void setDependentModules(final List<TreeNode> dependentModules) {
this.dependentModules = dependentModules;
}
protected void addDependentModule(final TreeNode node) {
dependentModules.add(node);
}
protected void removeDependentModule(final TreeNode node) {
dependentModules.remove(node);
}
public List<TreeNode> getDependsOn() {
return Collections.unmodifiableList(dependsOn);
}
protected void setDependsOn(final List<TreeNode> 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);
}
}

View File

@ -24,9 +24,18 @@
</jta-data-source>
<properties>
<!-- Properties for Hibernate -->
<property name="hibernate.hbm2ddl.auto" value="verify"/>
<property name="hibernate.connection.autocommit" value="false" />
<property name="hibernate.id.new_generator_mappings" value="true"/>
<!--
Properties for Hibernate Envers
We are using the ValidityAuditStrategy here because it is faster
when querying data than the DefaultStrategy
-->
<property name="org.hibernate.envers.audit_strategy"
value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Category(IntegrationTest.class)
@RunWith(Arquillian.class)
public class DependencyTreeManagerTest {
@Inject
@org.libreccm.modules.annotations.Module
private transient Instance<Module> 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<Class<Module>> moduleList = new ArrayList<>();
for (final Module module : modules) {
moduleList.add((Class<Module>) module.getClass());
}
assertThat(moduleList.size(), is(4));
assertThat(moduleList, containsInAnyOrder(TestModuleRoot.class,
TestModuleA.class,
TestModuleB.class,
TestModuleC.class));
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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
}
}

View File

@ -25,6 +25,14 @@
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.connection.autocommit" value="false" />
<!--
Properties for Hibernate Envers
We are using the ValidityAuditStrategy here because it is faster
when querying data than the DefaultStrategy
-->
<property name="org.hibernate.envers.audit_strategy"
value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>

View File

@ -26,6 +26,14 @@
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.connection.autocommit" value="false" />
<!--
Properties for Hibernate Envers
We are using the ValidityAuditStrategy here because it is faster
when querying data than the DefaultStrategy
-->
<property name="org.hibernate.envers.audit_strategy"
value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>

View File

@ -26,6 +26,14 @@
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.connection.autocommit" value="false" />
<!--
Properties for Hibernate Envers
We are using the ValidityAuditStrategy here because it is faster
when querying data than the DefaultStrategy
-->
<property name="org.hibernate.envers.audit_strategy"
value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>

View File

@ -26,6 +26,14 @@
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.connection.autocommit" value="false" />
<!--
Properties for Hibernate Envers
We are using the ValidityAuditStrategy here because it is faster
when querying data than the DefaultStrategy
-->
<property name="org.hibernate.envers.audit_strategy"
value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>

View File

@ -26,6 +26,14 @@
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.connection.autocommit" value="false" />
<!--
Properties for Hibernate Envers
We are using the ValidityAuditStrategy here because it is faster
when querying data than the DefaultStrategy
-->
<property name="org.hibernate.envers.audit_strategy"
value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>

View File

@ -26,6 +26,14 @@
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.connection.autocommit" value="false" />
<!--
Properties for Hibernate Envers
We are using the ValidityAuditStrategy here because it is faster
when querying data than the DefaultStrategy
-->
<property name="org.hibernate.envers.audit_strategy"
value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>