/** * * Copyright * 2009-2015 Jayway Products AB * 2016-2017 Föreningen Sambruk * * Licensed under AGPL, Version 3.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/agpl.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package se.streamsource.streamflow.web.application.organization; import static org.qi4j.api.usecase.UsecaseBuilder.newUsecase; import org.qi4j.api.entity.association.ManyAssociation; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.mixin.Mixins; import org.qi4j.api.query.Query; import org.qi4j.api.service.Activatable; import org.qi4j.api.service.ServiceComposite; import org.qi4j.api.specification.Specifications; import org.qi4j.api.structure.Module; import org.qi4j.api.unitofwork.NoSuchEntityException; import org.qi4j.api.unitofwork.UnitOfWork; import org.qi4j.api.value.ValueBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.streamsource.dci.api.RoleMap; import se.streamsource.streamflow.api.workspace.cases.contact.ContactDTO; import se.streamsource.streamflow.web.domain.entity.casetype.CaseTypeEntity; import se.streamsource.streamflow.web.domain.entity.customer.CustomersEntity; import se.streamsource.streamflow.web.domain.entity.organization.*; import se.streamsource.streamflow.web.domain.entity.project.ProjectEntity; import se.streamsource.streamflow.web.domain.entity.user.UserEntity; import se.streamsource.streamflow.web.domain.entity.user.UsersEntity; import se.streamsource.streamflow.web.domain.interaction.gtd.IdGenerator; import se.streamsource.streamflow.web.domain.interaction.gtd.Ownable; import se.streamsource.streamflow.web.domain.interaction.gtd.Owner; import se.streamsource.streamflow.web.domain.structure.casetype.CaseType; import se.streamsource.streamflow.web.domain.structure.organization.Organization; import se.streamsource.streamflow.web.domain.structure.organization.OrganizationalUnit; import se.streamsource.streamflow.web.domain.structure.organization.Organizations; import se.streamsource.streamflow.web.domain.structure.project.Project; import se.streamsource.streamflow.web.domain.structure.role.PermissionsEnum; import se.streamsource.streamflow.web.domain.structure.role.Role; import java.util.Calendar; import java.util.Date; /** * Ensure that the most basic entities are always created. This includes: * 1) an UsersEntity * 2) an OrganizationsEntity * 3) an Organization * 4) an Administrator role * 5) an Administrator user */ @Mixins(BootstrapDataService.Mixin.class) public interface BootstrapDataService extends ServiceComposite, Activatable { class Mixin implements Activatable { final Logger logger = LoggerFactory.getLogger( getClass().getName() ); @Structure Module module; public void activate() throws Exception { UnitOfWork uow = module.unitOfWorkFactory().newUnitOfWork(newUsecase("Bootstrap data")); RoleMap.newCurrentRoleMap(); try { UsersEntity users; try { // Check if users entity exists users = uow.get( UsersEntity.class, UsersEntity.USERS_ID ); } catch (NoSuchEntityException e) { // Create bootstrap data users = uow.newEntity( UsersEntity.class, UsersEntity.USERS_ID ); } OrganizationsEntity organizations; try { // Check if organizations entity exists organizations = uow.get( OrganizationsEntity.class, OrganizationsEntity.ORGANIZATIONS_ID ); } catch (NoSuchEntityException e) { // Create bootstrap data organizations = uow.newEntity( OrganizationsEntity.class, OrganizationsEntity.ORGANIZATIONS_ID ); } // Check if admin exists UserEntity admin; try { admin = uow.get( UserEntity.class, UserEntity.ADMINISTRATOR_USERNAME ); } catch (NoSuchEntityException e) { // Create admin admin = (UserEntity) users.createUser( UserEntity.ADMINISTRATOR_USERNAME, UserEntity.ADMINISTRATOR_USERNAME ); ValueBuilder<ContactDTO> contactBuilder = module.valueBuilderFactory().newValueBuilder(ContactDTO.class); contactBuilder.prototype().name().set( "Administrator" ); ContactDTO contact = contactBuilder.newInstance(); admin.updateContact( contact ); } try { // Check if customers entity exists uow.get( CustomersEntity.class, CustomersEntity.CUSTOMERS_ID ); } catch (NoSuchEntityException e) { // Create bootstrap data uow.newEntity( CustomersEntity.class, CustomersEntity.CUSTOMERS_ID ); } Query<OrganizationEntity> orgs = organizations.organizations().newQuery( uow ); long orgCount = orgs.count(); if (orgCount == 0) { // Create default organization organizations.createOrganization( "Organization" ); uow.complete(); uow = module.unitOfWorkFactory().newUnitOfWork(newUsecase("Bootstrap data")); orgs = uow.get( organizations ).organizations().newQuery( uow ); admin = uow.get(admin); } else if (orgCount == 1) { // Set association to the one org organizations.organization().set(orgs.find()); } else if (orgCount > 1) { logger.warn("Multiple organizations exist. Removing extra"); OrganizationEntity realOrg = null; for (OrganizationEntity organizationEntity : orgs) { if (!organizationEntity.getDescription().equals("Organization")) { if (realOrg != null) logger.warn("Multiple organizations have changed name. Cannot determine which one to remove!"); realOrg = organizationEntity; } } // Set association to the one org organizations.organization().set(realOrg); // Now remove all extra orgs for (OrganizationEntity org : orgs) { if (!org.equals(realOrg)) { logger.warn("Removing extra organization with id:"+org); org.removeEntity(); } } uow.complete(); uow = module.unitOfWorkFactory().newUnitOfWork(newUsecase("Bootstrap data")); orgs = uow.get(organizations).organizations().newQuery( uow ); admin = uow.get(admin); } for (OrganizationEntity org : orgs) { Role administrator; if (org.roles().count() == 0) { // Administrator role administrator = org.createRole( "Administrator" ); } else { administrator = org.roles().get( 0 ); } administrator.addPermission( PermissionsEnum.administrator.name() ); // Administrator should be member of all organizations if (!admin.organizations().contains( org )) { admin.join( org ); } // Assign admin role to administrator org.grantRole( admin, administrator ); // Check that ownership is correctly set org.visitOrganization( new OrganizationVisitor() { @Override public boolean visitOrganization( Organization org ) { OrganizationEntity organization = (OrganizationEntity) org; fixOwnership(organization, organization.organizationalUnits()); fixOwnership(organization, organization.forms()); fixOwnership(organization, organization.roles()); fixOwnership(organization, organization.caseTypes()); return true; } @Override public boolean visitOrganizationalUnit( OrganizationalUnit ou ) { OrganizationalUnitEntity orgUnit = (OrganizationalUnitEntity) ou; fixOwnership(orgUnit, orgUnit.organizationalUnits()); fixOwnership(orgUnit, orgUnit.forms()); fixOwnership(orgUnit, orgUnit.groups()); fixOwnership(orgUnit, orgUnit.projects()); fixOwnership(orgUnit, orgUnit.caseTypes()); return true; } @Override public boolean visitProject( Project project ) { ProjectEntity proj = (ProjectEntity) project; fixOwnership(proj, proj.forms()); fixOwnership(proj, proj.caseTypes()); return true; } @Override public boolean visitCaseType( CaseType caseType ) { CaseTypeEntity ct = (CaseTypeEntity) caseType; fixOwnership(ct, ct.forms()); return true; } private void fixOwnership( Owner owner, ManyAssociation<? extends Ownable> ownables ) { for (Ownable ownable : ownables) { fixOwner( ownable, owner ); } } private void fixOwner( Ownable ownable, Owner owner ) { if (!ownable.isOwnedBy( owner )) { logger.info( "Changed owner of "+ownable+" to "+owner ); ownable.changeOwner( owner ); } } }, Specifications.<Class>TRUE()); } // check if a global case id generator state entity exists try{ uow.get(GlobalCaseIdStateEntity.class, GlobalCaseIdStateEntity.GLOBALCASEIDSTATE_ID ); } catch( NoSuchEntityException ne ){ //create one and feed it with id generator state from organization entity. OrganizationsEntity orgz = uow.get( OrganizationsEntity.class, OrganizationsEntity.ORGANIZATIONS_ID ); GlobalCaseIdStateEntity caseIdStateEntity = uow.newEntity( GlobalCaseIdStateEntity.class, GlobalCaseIdStateEntity.GLOBALCASEIDSTATE_ID ); caseIdStateEntity.setCounter( ((IdGenerator)orgz.organization().get()).getCounter()); Long date = ((IdGenerator) orgz.organization().get()).getDate(); caseIdStateEntity.changeDate( date != null ? date : Calendar.getInstance().getTimeInMillis() ); } uow.complete(); logger.info( "Bootstrap of domain model complete" ); } catch (Exception e) { logger.warn( "BootstrapDataService failed to start!" ); e.printStackTrace(); uow.discard(); } } public void passivate() throws Exception { } } }