CCM NG: Workflow and Lifecycle managment

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4216 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-08-10 15:06:05 +00:00
parent 01d3f59f5f
commit 1fb33e6131
39 changed files with 1471 additions and 2730 deletions

View File

@ -321,11 +321,11 @@
</rulesets> </rulesets>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <!--<plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>javancss-maven-plugin</artifactId> <artifactId>javancss-maven-plugin</artifactId>
<version>2.1</version> <version>2.1</version>
</plugin> </plugin>-->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId> <artifactId>maven-project-info-reports-plugin</artifactId>

View File

@ -41,6 +41,8 @@ public class CmsConstants {
public static final String CONTENT_SECTION_DESC_BUNDLE public static final String CONTENT_SECTION_DESC_BUNDLE
= "org.librecms.contentsection.ContentSectionResources"; = "org.librecms.contentsection.ContentSectionResources";
public static final String CATEGORIZATION_TYPE_FOLDER = "folder";
public static final String PRIVILEGE_ADMINISTER_CATEGORIES public static final String PRIVILEGE_ADMINISTER_CATEGORIES
= "administer_categories"; = "administer_categories";
public static final String PRIVILEGE_ADMINISTER_CONTENT_TYPES public static final String PRIVILEGE_ADMINISTER_CONTENT_TYPES

View File

@ -20,15 +20,22 @@ package org.librecms.contentsection;
import org.hibernate.envers.Audited; import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode; import org.hibernate.envers.RelationTargetAuditMode;
import org.libreccm.categorization.Categorization;
import org.libreccm.core.CcmObject; import org.libreccm.core.CcmObject;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
import org.libreccm.security.InheritsPermissions;
import org.libreccm.workflow.Workflow;
import org.librecms.CmsConstants;
import org.librecms.attachments.AttachmentList; import org.librecms.attachments.AttachmentList;
import org.librecms.lifecycle.Lifecycle;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.persistence.AssociationOverride; import javax.persistence.AssociationOverride;
import javax.persistence.Column; import javax.persistence.Column;
@ -62,16 +69,12 @@ import static org.librecms.CmsConstants.*;
query = "SELECT i FROM ContentItem i WHERE TYPE(I) = :type"), query = "SELECT i FROM ContentItem i WHERE TYPE(I) = :type"),
@NamedQuery( @NamedQuery(
name = "ContentItem.findByFolder", name = "ContentItem.findByFolder",
// query = "SELECT i FROM ContentItem i "
// + "WHERE (SELECT c FROM Categorization c "
// + " WHERE c.category = :folder"
// + " AND c.object = i) "
// + "MEMBER OF i.categories"
query = "SELECT c.categorizedObject FROM Categorization c " query = "SELECT c.categorizedObject FROM Categorization c "
+ "WHERE c.category = :folder" + "WHERE c.category = :folder"
) )
}) })
public class ContentItem extends CcmObject implements Serializable { public class ContentItem extends CcmObject implements Serializable,
InheritsPermissions {
private static final long serialVersionUID = 5897287630227129653L; private static final long serialVersionUID = 5897287630227129653L;
@ -154,6 +157,16 @@ public class ContentItem extends CcmObject implements Serializable {
@JoinColumn(name = "CONTENT_ITEM_ID") @JoinColumn(name = "CONTENT_ITEM_ID")
private List<AttachmentList<?>> attachments; private List<AttachmentList<?>> attachments;
@OneToOne
@JoinColumn(name = "LIFECYCLE_ID")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
private Lifecycle lifecycle;
@OneToOne
@JoinColumn(name = "WORKFLOW_ID")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
private Workflow workflow;
public LocalizedString getName() { public LocalizedString getName() {
return name; return name;
} }
@ -226,6 +239,36 @@ public class ContentItem extends CcmObject implements Serializable {
this.attachments = attachments; this.attachments = attachments;
} }
public Lifecycle getLifecycle() {
return lifecycle;
}
public void setLifecycle(final Lifecycle lifecycle) {
this.lifecycle = lifecycle;
}
public Workflow getWorkflow() {
return workflow;
}
public void setWorkflow(final Workflow workflow) {
this.workflow = workflow;
}
@Override
public Optional<CcmObject> getParent() {
final List<Categorization> result = getCategories().stream().filter(
categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.equals(
categorization.getType()))
.collect(Collectors.toList());
if (result.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(result.get(0).getCategorizedObject());
}
}
@Override @Override
public int hashCode() { public int hashCode() {
int hash = super.hashCode(); int hash = super.hashCode();
@ -235,6 +278,8 @@ public class ContentItem extends CcmObject implements Serializable {
hash = 59 * hash + Objects.hashCode(description); hash = 59 * hash + Objects.hashCode(description);
hash = 59 * hash + Objects.hashCode(version); hash = 59 * hash + Objects.hashCode(version);
hash = 59 * hash + Objects.hashCode(launchDate); hash = 59 * hash + Objects.hashCode(launchDate);
hash = 59 * hash + Objects.hashCode(lifecycle);
hash = 59 * hash + Objects.hashCode(workflow);
return hash; return hash;
} }
@ -275,7 +320,10 @@ public class ContentItem extends CcmObject implements Serializable {
if (!Objects.equals(launchDate, other.getLaunchDate())) { if (!Objects.equals(launchDate, other.getLaunchDate())) {
return false; return false;
} }
return true; if (!Objects.equals(lifecycle, other.getLifecycle())) {
return false;
}
return Objects.equals(workflow, other.getWorkflow());
} }
@Override @Override
@ -285,18 +333,23 @@ public class ContentItem extends CcmObject implements Serializable {
@Override @Override
public String toString(final String data) { public String toString(final String data) {
return super.toString(String.format(", name = {}, " return super.toString(String.format(", name = %s, "
+ "contentType = {}, " + "contentType = { %s }, "
+ "title = {}, " + "title = %s, "
+ "description = {}," + "description = %s, "
+ "version = %s," + "version = %s, "
+ "launchDate = %s%s", + "launchDate = %s, "
+ "lifecycle = { %s }, "
+ "workflow = { %s }"
+ "%s",
Objects.toString(name), Objects.toString(name),
Objects.toString(contentType), Objects.toString(contentType),
Objects.toString(title), Objects.toString(title),
Objects.toString(description), Objects.toString(description),
Objects.toString(version), Objects.toString(version),
Objects.toString(launchDate), Objects.toString(launchDate),
Objects.toString(lifecycle),
Objects.toString(workflow),
data)); data));
} }

View File

@ -83,6 +83,8 @@ public class LifecycleDefinition implements Serializable {
private List<PhaseDefinition> phaseDefinitions; private List<PhaseDefinition> phaseDefinitions;
public LifecycleDefinition() { public LifecycleDefinition() {
label = new LocalizedString();
description = new LocalizedString();
phaseDefinitions = new ArrayList<>(); phaseDefinitions = new ArrayList<>();
} }

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class LifecycleDefinitionRepository
extends AbstractEntityRepository<Long, LifecycleDefinition>{
@Override
public Class<LifecycleDefinition> getEntityClass() {
return LifecycleDefinition.class;
}
@Override
public boolean isNew(final LifecycleDefinition lifecycleDefinition) {
return lifecycleDefinition.getDefinitionId() == 0;
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public enum LifecycleEvent {
STARTED,
FINISHED,
RESET
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@FunctionalInterface
public interface LifecycleEventListener {
void update(final Lifecycle lifecycle, final LifecycleEvent event);
}

View File

@ -0,0 +1,188 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege;
import org.librecms.CmsConstants;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class LifecycleManager {
@Inject
private LifecycleDefinitionRepository lifecycleDefinitionRepo;
@Inject
private PhaseDefinititionRepository phaseDefinititionRepo;
@Inject
private LifecycleRepository lifecycleRepo;
@Inject
private PhaseRepository phaseRepo;
@Inject
private BeanManager beanManager;
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
@RequiresPrivilege(CmsConstants.PRIVILEGE_ADMINISTER_LIFECYLES)
public void addPhaseDefinition(
final LifecycleDefinition lifecycleDefinition,
final PhaseDefinition phaseDefinition) {
lifecycleDefinition.addPhaseDefinition(phaseDefinition);
lifecycleDefinitionRepo.save(lifecycleDefinition);
phaseDefinititionRepo.save(phaseDefinition);
}
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
@RequiresPrivilege(CmsConstants.PRIVILEGE_ADMINISTER_LIFECYLES)
public void removePhaseDefinition(
final LifecycleDefinition lifecycleDefinition,
final PhaseDefinition phaseDefinition) {
lifecycleDefinition.removePhaseDefinition(phaseDefinition);
lifecycleDefinitionRepo.save(lifecycleDefinition);
phaseDefinititionRepo.save(phaseDefinition);
}
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
@RequiresPrivilege(CmsConstants.PRIVILEGE_ADMINISTER_LIFECYLES)
public Lifecycle createLifecycle(
final LifecycleDefinition lifecycleDefinition) {
final Lifecycle lifecycle = new Lifecycle();
lifecycle.setDefinition(lifecycleDefinition);
lifecycleDefinition.getPhaseDefinitions().forEach(
phaseDefinition -> createPhase(lifecycle, phaseDefinition));
lifecycleRepo.save(lifecycle);
return lifecycle;
}
private void createPhase(final Lifecycle lifecycle,
final PhaseDefinition phaseDefinition) {
final Phase phase = new Phase();
phase.setDefinition(phaseDefinition);
lifecycle.addPhase(phase);
phase.setLifecycle(lifecycle);
phaseRepo.save(phase);
}
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
@RequiresPrivilege(CmsConstants.PRIVILEGE_ADMINISTER_LIFECYLES)
public void startLifecycle(final Lifecycle lifecycle) {
if (!lifecycle.isStarted()) {
if (lifecycle.isFinished()) {
lifecycle.setFinished(false);
}
lifecycle.getPhases().forEach(phase -> {
phase.setStarted(false);
phase.setFinished(false);
phaseRepo.save(phase);
});
lifecycle.getPhases().get(0).setStarted(true);
phaseRepo.save(lifecycle.getPhases().get(0));
lifecycleRepo.save(lifecycle);
if (lifecycle.getListener() != null
&& !lifecycle.getListener().isEmpty()) {
final List<?> beans = new ArrayList<>(beanManager.getBeans(
lifecycle.getListener()));
if (!beans.isEmpty()) {
((LifecycleEventListener) beans.get(0)).update(
lifecycle, LifecycleEvent.STARTED);
}
}
//ToDo Invoke Listeners
}
}
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
@RequiresPrivilege(CmsConstants.PRIVILEGE_ADMINISTER_LIFECYLES)
public void nextPhase(final Lifecycle lifecycle) {
if (lifecycle.isStarted()) {
int current = -1;
for (int i = 0; i < lifecycle.getPhases().size(); i++) {
if (lifecycle.getPhases().get(i).isStarted()
&& !lifecycle.getPhases().get(i).isFinished()) {
current = i;
break;
}
}
if (current == -1) {
//Lifecycle is already finished, nothing to do.
return;
}
lifecycle.getPhases().get(current).setFinished(true);
//Check for last phase, if not set next phase to started
if (current < lifecycle.getPhases().size() - 1) {
lifecycle.getPhases().get(current + 1).setStarted(true);
}
} else {
startLifecycle(lifecycle);
}
}
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
@RequiresPrivilege(CmsConstants.PRIVILEGE_ADMINISTER_LIFECYLES)
public void reset(final Lifecycle lifecycle) {
lifecycle.setStarted(false);
lifecycle.setFinished(false);
lifecycle.getPhases().forEach(phase -> {
phase.setStarted(false);
phase.setFinished(false);
phaseRepo.save(phase);
});
lifecycleRepo.save(lifecycle);
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class LifecycleRepository extends AbstractEntityRepository<Long, Lifecycle> {
@Override
public Class<Lifecycle> getEntityClass() {
return Lifecycle.class;
}
@Override
public boolean isNew(final Lifecycle lifecycle) {
return lifecycle.getLifecycleId() == 0;
}
}

View File

@ -80,6 +80,11 @@ public class PhaseDefinition implements Serializable {
@Column(name = "DEFAULT_LISTENER", length = 1024) @Column(name = "DEFAULT_LISTENER", length = 1024)
private String defaultListener; private String defaultListener;
public PhaseDefinition() {
label = new LocalizedString();
description = new LocalizedString();
}
public long getDefinitionId() { public long getDefinitionId() {
return definitionId; return definitionId;
} }

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class PhaseDefinititionRepository
extends AbstractEntityRepository<Long, PhaseDefinition> {
@Override
public Class<PhaseDefinition> getEntityClass() {
return PhaseDefinition.class;
}
@Override
public boolean isNew(final PhaseDefinition phaseDefinition) {
return phaseDefinition.getDefinitionId() == 0;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public enum PhaseEvent {
STARTED,
FINISHED
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@FunctionalInterface
public interface PhaseEventListener {
void update(final Lifecycle lifecycle,
final Phase phase,
final PhaseEvent event);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 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.librecms.lifecycle;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class PhaseRepository extends AbstractEntityRepository<Long, Phase>{
@Override
public Class<Phase> getEntityClass() {
return Phase.class;
}
@Override
public boolean isNew(final Phase phase) {
return phase.getPhaseId() == 0;
}
}

View File

@ -0,0 +1,21 @@
ALTER TABLE ccm_cms.content_items
ADD COLUMN lifecycle_id bigint;
ALTER TABLE ccm_cms.content_items
ADD COLUMN workflow_id bigint;
ALTER TABLE ccm_cms.content_items_aud
ADD COLUMN lifecycle_id bigint;
ALTER TABLE ccm_cms.content_items_aud
ADD COLUMN workflow_id bigint;
alter table CCM_CMS.CONTENT_ITEMS
add constraint FKfh1nm46qpw6xcwkmgaqw2iu3h
foreign key (LIFECYCLE_ID)
references CCM_CMS.LIFECYCLES;
alter table CCM_CMS.CONTENT_ITEMS
add constraint FKl00ldjygr6as8gqbt3j14ke7j
foreign key (WORKFLOW_ID)
references CCM_CORE.WORKFLOWS;

View File

@ -0,0 +1,21 @@
ALTER TABLE ccm_cms.content_items
ADD COLUMN lifecycle_id int8;
ALTER TABLE ccm_cms.content_items
ADD COLUMN workflow_id int8;
ALTER TABLE ccm_cms.content_items_aud
ADD COLUMN lifecycle_id int8;
ALTER TABLE ccm_cms.content_items_aud
ADD COLUMN workflow_id int8;
alter table CCM_CMS.CONTENT_ITEMS
add constraint FKfh1nm46qpw6xcwkmgaqw2iu3h
foreign key (LIFECYCLE_ID)
references CCM_CMS.LIFECYCLES;
alter table CCM_CMS.CONTENT_ITEMS
add constraint FKl00ldjygr6as8gqbt3j14ke7j
foreign key (WORKFLOW_ID)
references CCM_CORE.WORKFLOWS;

View File

@ -0,0 +1,122 @@
/*
* Copyright (C) 2016 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.librecms.contentsection;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ContentItemManagerTest {
public ContentItemManagerTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
// TODO add test methods here.
// The methods must be annotated with annotation @Test. For example:
//
// @Test
// public void hello() {}
// Create content item
// Create content item type not in content section
// Create content item name null
// Create content item name empty
// Create content item folder null
// Create content item folder no a folder
// Create content item with lifecycle and workflow
// Create content item with lifecycle and workflow type not in content section
// Create content item with lifecycle and workflow name null
// Create content item with lifecycle and workflow name empty
// Create content item with lifecycle and workflow folder null
// Create content item with lifecycle and workflow folder no a folder
// Move item
// Move item item null
// Move item folder null
// Move item folder not a folder
// copy item
// copy item item null
// copy item folder null
// copy item folder not a folder
// publish item (draft)
// publish item (live)
// publish item null
// unpublish item
// unpublish non live
// unpublish item null
// isLive
// isDraft
// getLiveVersion
// getDraftVersion
// getPendingVersions?
}

View File

@ -48,7 +48,8 @@ public class DatasetsTest extends DatasetsVerifier {
"/datasets/org/librecms/contentsection/ContentSectionManagerTest/after-create.xml", "/datasets/org/librecms/contentsection/ContentSectionManagerTest/after-create.xml",
"/datasets/org/librecms/contentsection/ContentSectionManagerTest/after-remove-role.xml", "/datasets/org/librecms/contentsection/ContentSectionManagerTest/after-remove-role.xml",
"/datasets/org/librecms/contentsection/ContentSectionManagerTest/after-rename.xml", "/datasets/org/librecms/contentsection/ContentSectionManagerTest/after-rename.xml",
"/datasets/org/librecms/contentsection/ContentItemRepositoryTest/data.xml"}); "/datasets/org/librecms/contentsection/ContentItemRepositoryTest/data.xml",
"/datasets/org/librecms/contentsection/ContentItemManagerTest/data.xml"});
} }
public DatasetsTest(final String datasetPath) { public DatasetsTest(final String datasetPath) {

View File

@ -876,6 +876,7 @@ CREATE SCHEMA ccm_cms;
create table CCM_CORE.CATEGORIZATIONS ( create table CCM_CORE.CATEGORIZATIONS (
CATEGORIZATION_ID bigint not null, CATEGORIZATION_ID bigint not null,
TYPE varchar(255),
CATEGORY_ORDER bigint, CATEGORY_ORDER bigint,
CATEGORY_INDEX boolean, CATEGORY_INDEX boolean,
OBJECT_ORDER bigint, OBJECT_ORDER bigint,

View File

@ -876,6 +876,7 @@ CREATE SCHEMA ccm_cms;
create table CCM_CORE.CATEGORIZATIONS ( create table CCM_CORE.CATEGORIZATIONS (
CATEGORIZATION_ID int8 not null, CATEGORIZATION_ID int8 not null,
TYPE varchar(255),
CATEGORY_ORDER int8, CATEGORY_ORDER int8,
CATEGORY_INDEX boolean, CATEGORY_INDEX boolean,
OBJECT_ORDER int8, OBJECT_ORDER int8,

View File

@ -876,6 +876,7 @@ CREATE SCHEMA ccm_cms;
create table CCM_CORE.CATEGORIZATIONS ( create table CCM_CORE.CATEGORIZATIONS (
CATEGORIZATION_ID bigint not null, CATEGORIZATION_ID bigint not null,
TYPE varchar(255),
CATEGORY_ORDER bigint, CATEGORY_ORDER bigint,
CATEGORY_INDEX boolean, CATEGORY_INDEX boolean,
OBJECT_ORDER bigint, OBJECT_ORDER bigint,

View File

@ -0,0 +1,249 @@
<?xml version="1.0" encoding="utf-8"?>
<dataset>
<ccm_core.ccm_objects object_id="-1100"
display_name="info"
uuid="963bcae7-3aeb-4b62-891c-e16c4defa1f2" />
<ccm_core.ccm_objects object_id="-2100"
display_name="info_root"
uuid="82014239-9c06-486d-ae8c-4ae47f52a699" />
<ccm_core.ccm_objects object_id="-2200"
display_name="info_assets"
uuid="b163f73c-9ac2-44d7-a037-de621f5ca828" />
<ccm_core.categories object_id="-2100"
unique_id="82014239-9c06-486d-ae8c-4ae47f52a699"
name="info_root"
enabled="true"
visible="true"
abstract_category="false"
category_order="1" />
<ccm_core.categories object_id="-2200"
unique_id="b163f73c-9ac2-44d7-a037-de621f5ca828"
name="info_assets"
enabled="true"
visible="true"
abstract_category="false"
category_order="1" />
<ccm_core.category_titles object_id="-2100"
locale="en"
localized_value="info_root" />
<ccm_core.category_titles object_id="-2200"
locale="en"
localized_value="info_assets" />
<ccm_core.resources object_id="-1100"
created="2016-07-15" />
<ccm_core.resource_titles object_id="-1100"
locale="en"
localized_value="info" />
<ccm_core.applications object_id="-1100"
application_type="org.librecms.contentsection.ContentSection"
primary_url="info" />
<ccm_cms.content_sections object_id="-1100"
label="info"
root_documents_folder_id="-2100"
root_assets_folder_id="-2200" />
<ccm_core.ccm_roles role_id="-3100"
name="info_alert_recipient" />
<ccm_core.ccm_roles role_id="-3200"
name="info_author" />
<ccm_core.ccm_roles role_id="-3300"
name="info_editor" />
<ccm_core.ccm_roles role_id="-3400"
name="info_manager" />
<ccm_core.ccm_roles role_id="-3500"
name="info_publisher" />
<ccm_core.ccm_roles role_id="-3600"
name="info_content_reader" />
<ccm_cms.content_section_roles role_id="-3100"
section_id="-1100" />
<ccm_cms.content_section_roles role_id="-3200"
section_id="-1100" />
<ccm_cms.content_section_roles role_id="-3300"
section_id="-1100" />
<ccm_cms.content_section_roles role_id="-3400"
section_id="-1100" />
<ccm_cms.content_section_roles role_id="-3500"
section_id="-1100" />
<ccm_cms.content_section_roles role_id="-3600"
section_id="-1100" />
<ccm_core.permissions permission_id="-4110"
granted_privilege="categorize_items"
object_id="-2100"
grantee_id="-3200"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4120"
granted_privilege="create_new_items"
object_id="-2100"
grantee_id="-3200"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4130"
granted_privilege="edit_items"
object_id="-2100"
grantee_id="-3200"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4140"
granted_privilege="view_published_items"
object_id="-2100"
grantee_id="-3200"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4150"
granted_privilege="preview_items"
object_id="-2100"
grantee_id="-3200"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4210"
granted_privilege="categorize_items"
object_id="-2100"
grantee_id="-3300"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4220"
granted_privilege="create_new_items"
object_id="-2100"
grantee_id="-3300"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4230"
granted_privilege="edit_items"
object_id="-2100"
grantee_id="-3300"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4240"
granted_privilege="approve_items"
object_id="-2100"
grantee_id="-3300"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4250"
granted_privilege="delete_items"
object_id="-2100"
grantee_id="-3300"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4260"
granted_privilege="view_published_items"
object_id="-2100"
grantee_id="-3300"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4270"
granted_privilege="preview_items"
object_id="-2100"
grantee_id="-3300"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4310"
granted_privilege="administer_roles"
object_id="-1100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4320"
granted_privilege="administer_workflow"
object_id="-1100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4330"
granted_privilege="administer_lifecyles"
object_id="-1100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4340"
granted_privilege="administer_categories"
object_id="-1100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4350"
granted_privilege="administer_content_types"
object_id="-1100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4360"
granted_privilege="categorize_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4370"
granted_privilege="create_new_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4380"
granted_privilege="edit_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4390"
granted_privilege="approve_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4400"
granted_privilege="publish_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4410"
granted_privilege="delete_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4420"
granted_privilege="view_published_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4430"
granted_privilege="preview_items"
object_id="-2100"
grantee_id="-3400"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4510"
granted_privilege="categorize_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4520"
granted_privilege="create_new_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4530"
granted_privilege="edit_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4540"
granted_privilege="approve_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4550"
granted_privilege="publish_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4560"
granted_privilege="delete_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4570"
granted_privilege="view_published_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4580"
granted_privilege="preview_items"
object_id="-2100"
grantee_id="-3500"
creation_date="2016-07-15"/>
<ccm_core.permissions permission_id="-4610"
granted_privilege="view_published_items"
object_id="-2100"
grantee_id="-3600"
creation_date="2016-07-15"/>
</dataset>

View File

@ -50,8 +50,8 @@ import javax.persistence.Table;
@NamedQueries({ @NamedQueries({
@NamedQuery(name = "Categorization.find", @NamedQuery(name = "Categorization.find",
query = "SELECT c FROM Categorization c " query = "SELECT c FROM Categorization c "
+ "WHERE c.category = :category " + "WHERE c.category = :category "
+ "AND c.categorizedObject = :object") + "AND c.categorizedObject = :object")
}) })
public class Categorization implements Serializable { public class Categorization implements Serializable {
@ -100,6 +100,13 @@ public class Categorization implements Serializable {
@Column(name = "OBJECT_ORDER") @Column(name = "OBJECT_ORDER")
private long objectOrder; private long objectOrder;
/**
* Used to distinguish between different kinds of categorisations. Used for
* example by in the ccm-cms module to distinguish folders from categories.
*/
@Column(name = "TYPE", length = 255, nullable = true)
private String type;
public Categorization() { public Categorization() {
index = false; index = false;
categoryOrder = 0; categoryOrder = 0;
@ -154,16 +161,25 @@ public class Categorization implements Serializable {
this.objectOrder = objectOrder; this.objectOrder = objectOrder;
} }
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
@Override @Override
public int hashCode() { public int hashCode() {
int hash = 7; int hash = 7;
hash hash
= 89 * hash + (int) (categorizationId ^ (categorizationId >>> 32)); = 89 * hash + (int) (categorizationId ^ (categorizationId >>> 32));
hash = 89 * hash + Objects.hashCode(category); hash = 89 * hash + Objects.hashCode(category);
hash = 89 * hash + Objects.hashCode(categorizedObject); hash = 89 * hash + Objects.hashCode(categorizedObject);
hash = 89 * hash + (index ? 1 : 0); hash = 89 * hash + (index ? 1 : 0);
hash = 89 * hash + (int) (categoryOrder ^ (categoryOrder >>> 32)); hash = 89 * hash + (int) (categoryOrder ^ (categoryOrder >>> 32));
hash = 89 * hash + (int) (objectOrder ^ (objectOrder >>> 32)); hash = 89 * hash + (int) (objectOrder ^ (objectOrder >>> 32));
hash = 89 * hash + Objects.hashCode(type);
return hash; return hash;
} }
@ -199,7 +215,12 @@ public class Categorization implements Serializable {
if (categoryOrder != other.getCategoryOrder()) { if (categoryOrder != other.getCategoryOrder()) {
return false; return false;
} }
return objectOrder == other.getObjectOrder();
if (objectOrder != other.getObjectOrder()) {
return false;
}
return Objects.equals(type, other.getType());
} }
public boolean canEqual(final Object obj) { public boolean canEqual(final Object obj) {
@ -213,13 +234,14 @@ public class Categorization implements Serializable {
public String toString(final String data) { public String toString(final String data) {
return String.format("%s{ " return String.format("%s{ "
+ "categorizationId = %d, " + "categorizationId = %d, "
+ "category = %s, " + "category = %s, "
+ "categorizedObject = %s, " + "categorizedObject = %s, "
+ "index = %b," + "index = %b,"
+ "categoryOrder = %d, " + "categoryOrder = %d, "
+ "objectOrder = %d" + "objectOrder = %d"
+ "%s }", + "type = %s"
+ "%s }",
super.toString(), super.toString(),
categorizationId, categorizationId,
Objects.toString(category), Objects.toString(category),
@ -227,6 +249,7 @@ public class Categorization implements Serializable {
index, index,
categoryOrder, categoryOrder,
objectOrder, objectOrder,
type,
data); data);
} }

View File

@ -32,6 +32,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import javax.persistence.AssociationOverride; import javax.persistence.AssociationOverride;
import javax.persistence.Column; import javax.persistence.Column;
@ -338,8 +339,8 @@ public class Category extends CcmObject implements InheritsPermissions,
@Override @Override
public CcmObject getParent() { public Optional<CcmObject> getParent() {
return getParentCategory(); return Optional.ofNullable(getParentCategory());
} }
@Override @Override

View File

@ -20,6 +20,8 @@ package org.libreccm.security;
import org.libreccm.core.CcmObject; import org.libreccm.core.CcmObject;
import java.util.Optional;
/** /**
* Subclasses of {@link CcmObject} can implement this interface to inherit * Subclasses of {@link CcmObject} can implement this interface to inherit
* the permissions of their parent object. This interface is processed by the * the permissions of their parent object. This interface is processed by the
@ -42,6 +44,6 @@ public interface InheritsPermissions {
* object in addition to the permissions granted on the object itself to * object in addition to the permissions granted on the object itself to
* determine if a user is granted a specific privilege on the object. * determine if a user is granted a specific privilege on the object.
*/ */
CcmObject getParent(); Optional<CcmObject> getParent();
} }

View File

@ -86,11 +86,12 @@ public class PermissionChecker {
if (result) { if (result) {
return result; return result;
} else if (object instanceof InheritsPermissions) { } else if (object instanceof InheritsPermissions) {
if (((InheritsPermissions) object).getParent() == null) { if (((InheritsPermissions) object).getParent().isPresent()) {
return result; return result;
} else { } else {
return isPermitted(privilege, return isPermitted(
((InheritsPermissions) object).getParent()); privilege,
((InheritsPermissions) object).getParent().get());
} }
} else { } else {
return result; return result;
@ -139,7 +140,7 @@ public class PermissionChecker {
final boolean result = isPermitted(privilege, object); final boolean result = isPermitted(privilege, object);
if (!result) { if (!result) {
if (((InheritsPermissions) object).getParent() == null) { if (((InheritsPermissions) object).getParent().isPresent()) {
if (subject.isAuthenticated()) { if (subject.isAuthenticated()) {
subject.checkPermission(generatePermissionString( subject.checkPermission(generatePermissionString(
privilege, object)); privilege, object));
@ -148,8 +149,9 @@ public class PermissionChecker {
generatePermissionString(privilege, object)); generatePermissionString(privilege, object));
} }
} else { } else {
checkPermission(privilege, checkPermission(
((InheritsPermissions) object).getParent()); privilege,
((InheritsPermissions) object).getParent().get());
} }
} }
} else if (subject.isAuthenticated()) { } else if (subject.isAuthenticated()) {

View File

@ -217,11 +217,11 @@ public class Role implements Serializable {
this.assignedTasks = assignedTasks; this.assignedTasks = assignedTasks;
} }
protected void addAssignedTask(final TaskAssignment taskAssignment) { public void addAssignedTask(final TaskAssignment taskAssignment) {
assignedTasks.add(taskAssignment); assignedTasks.add(taskAssignment);
} }
protected void removeAssignedTask(final TaskAssignment taskAssignment) { public void removeAssignedTask(final TaskAssignment taskAssignment) {
assignedTasks.remove(taskAssignment); assignedTasks.remove(taskAssignment);
} }

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 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.workflow;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class TaskRepository extends AbstractEntityRepository<Long, Task> {
@Override
public Class<Task> getEntityClass() {
return Task.class;
}
@Override
public boolean isNew(final Task task) {
return task.getTaskId() == 0;
}
}

View File

@ -32,6 +32,8 @@ import java.util.Objects;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
@ -44,6 +46,11 @@ import javax.persistence.TemporalType;
*/ */
@Entity @Entity
@Table(name = "WORKFLOW_USER_TASKS", schema = DB_SCHEMA) @Table(name = "WORKFLOW_USER_TASKS", schema = DB_SCHEMA)
@NamedQueries(
@NamedQuery(
name = "UserTask.findLockedBy",
query = "SELECT t FROM UserTask t WHERE t.lockingUser = :user")
)
//Can't reduce complexity yet //Can't reduce complexity yet
@SuppressWarnings({"PMD.CyclomaticComplexity", @SuppressWarnings({"PMD.CyclomaticComplexity",
"PMD.StdCyclomaticComplexity", "PMD.StdCyclomaticComplexity",

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2016 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.workflow;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class UserTaskRepository extends AbstractEntityRepository<Long, UserTask>{
@Override
public Class<UserTask> getEntityClass() {
return UserTask.class;
}
@Override
public boolean isNew(final UserTask task) {
return task.getTaskId() == 0;
}
}

View File

@ -0,0 +1,250 @@
/*
* Copyright (C) 2016 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.workflow;
import org.libreccm.core.CoreConstants;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege;
import org.libreccm.security.Role;
import org.libreccm.security.RoleRepository;
import org.libreccm.security.Shiro;
import org.libreccm.security.User;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class WorkflowManager {
@Inject
private EntityManager entityManager;
@Inject
private WorkflowRepository workflowRepo;
@Inject
private TaskRepository taskRepo;
@Inject
private RoleRepository roleRepo;
@Inject
private Shiro shiro;
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public Workflow createWorkflow(final WorkflowTemplate template) {
final Workflow workflow = new Workflow();
final Map<Long, Task> tasks = new HashMap<>();
template.getTasks().forEach(taskTemplate -> createTask(taskTemplate,
tasks));
template.getTasks().forEach(taskTemplate -> fixTaskDependencies(
taskTemplate, tasks.get(taskTemplate.getTaskId()), tasks));
tasks.values().forEach(task -> taskRepo.save(task));
workflowRepo.save(workflow);
return workflow;
}
private void createTask(final Task template, final Map<Long, Task> tasks) {
final Class<? extends Task> templateClass = template.getClass();
final Task task;
try {
task = templateClass.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
final BeanInfo templateBeanInfo;
try {
templateBeanInfo = Introspector.getBeanInfo(templateClass);
} catch (IntrospectionException ex) {
throw new RuntimeException(ex);
}
for (PropertyDescriptor propertyDesc : templateBeanInfo
.getPropertyDescriptors()) {
try {
if ("taskId".equals(propertyDesc.getName())
|| "workflow".equals(propertyDesc.getName())
|| "dependentTasks".equals(propertyDesc.getName())
|| "dependsOn".equals(propertyDesc.getName())) {
continue;
}
final Method readMethod = propertyDesc.getReadMethod();
final Method writeMethod = propertyDesc.getWriteMethod();
final Object value = readMethod.invoke(template);
writeMethod.invoke(task, value);
} catch (IllegalAccessException |
IllegalArgumentException |
InvocationTargetException ex) {
throw new RuntimeException();
}
tasks.put(template.getTaskId(), task);
}
}
private void fixTaskDependencies(final Task template,
final Task task,
final Map<Long, Task> tasks) {
if (template.getDependentTasks() != null
&& !template.getDependentTasks().isEmpty()) {
template.getDependentTasks().forEach(dependent
-> task.addDependentTask(tasks.get(dependent.getTaskId())));
}
if (template.getDependsOn() != null
&& !template.getDependsOn().isEmpty()) {
template.getDependsOn().forEach(dependsOn
-> task.addDependsOn(tasks.get(dependsOn.getTaskId())));
}
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void addTask(final Workflow workflow, final Task task) {
workflow.addTask(task);
task.setWorkflow(workflow);
workflowRepo.save(workflow);
taskRepo.save(task);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void removeTask(final Workflow workflow, final Task task) {
workflow.removeTask(task);
task.setWorkflow(null);
workflowRepo.save(workflow);
taskRepo.save(task);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void assignTask(final UserTask task, final Role role) {
final TaskAssignment assignment = new TaskAssignment();
assignment.setTask(task);
assignment.setRole(role);
task.addAssignment(assignment);
role.addAssignedTask(assignment);
entityManager.persist(assignment);
taskRepo.save(task);
roleRepo.save(role);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void retractTask(final UserTask task, final Role role) {
final List<TaskAssignment> result = task.getAssignments().stream()
.filter(assigned -> role.equals(assigned.getRole()))
.collect(Collectors.toList());
if (!result.isEmpty()) {
final TaskAssignment assignment = result.get(0);
task.removeAssignment(assignment);
role.removeAssignedTask(assignment);
entityManager.remove(assignment);
}
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void addDependentTask(final Task parent, final Task task) {
parent.addDependentTask(task);
task.addDependsOn(parent);
taskRepo.save(task);
taskRepo.save(parent);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void removeDependentTask(final Task parent, final Task task) {
parent.removeDependentTask(task);
task.removeDependsOn(parent);
taskRepo.save(task);
taskRepo.save(parent);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void lockTask(final UserTask task) {
task.setLocked(true);
task.setLockingUser(shiro.getUser());
taskRepo.save(task);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void unlockTask(final UserTask task) {
task.setLocked(false);
task.setLockingUser(null);
taskRepo.save(task);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public List<UserTask> lockedBy(final User user) {
final TypedQuery<UserTask> query = entityManager.createNamedQuery(
"UserTask.findLockedBy", UserTask.class);
query.setParameter("user", user);
return query.getResultList();
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 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.workflow;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class WorkflowRepository extends AbstractEntityRepository<Long, Workflow> {
@Override
public Class<Workflow> getEntityClass() {
return Workflow.class;
}
@Override
public boolean isNew(final Workflow workflow) {
return workflow.getWorkflowId() == 0;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2016 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.workflow;
import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class WorkflowTemplateRepository
extends AbstractEntityRepository<Long, WorkflowTemplate> {
@Override
public Class<WorkflowTemplate> getEntityClass() {
return WorkflowTemplate.class;
}
@Override
public boolean isNew(final WorkflowTemplate template) {
return template.getWorkflowId() == 0;
}
}

View File

@ -0,0 +1,2 @@
alter table CCM_CORE.CATEGORIZATIONS
add column TYPE varchar(255);

View File

@ -0,0 +1,2 @@
alter table CCM_CORE.CATEGORIZATIONS
add column TYPE varchar(255);

View File

@ -41,6 +41,7 @@ CREATE SCHEMA ccm_core;
create table ccm_core.categorizations ( create table ccm_core.categorizations (
categorization_id bigint not null, categorization_id bigint not null,
type varchar(255),
category_order bigint, category_order bigint,
category_index boolean, category_index boolean,
object_order bigint, object_order bigint,

View File

@ -35,6 +35,7 @@ CREATE SCHEMA ccm_core;
create table CCM_CORE.CATEGORIZATIONS ( create table CCM_CORE.CATEGORIZATIONS (
CATEGORIZATION_ID int8 not null, CATEGORIZATION_ID int8 not null,
type varchar(255),
CATEGORY_ORDER int8, CATEGORY_ORDER int8,
CATEGORY_INDEX boolean, CATEGORY_INDEX boolean,
OBJECT_ORDER int8, OBJECT_ORDER int8,

View File

@ -329,11 +329,11 @@
</rulesets> </rulesets>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <!--<plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>javancss-maven-plugin</artifactId> <artifactId>javancss-maven-plugin</artifactId>
<version>2.1</version> <version>2.1</version>
</plugin> </plugin>-->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId> <artifactId>maven-project-info-reports-plugin</artifactId>