/* Index ECM Engine - A system for managing the capture (when created
* or received), classification (cataloguing), storage, retrieval,
* revision, sharing, reuse and disposition of documents.
*
* Copyright (C) 2008 Regione Piemonte
* Copyright (C) 2008 Provincia di Torino
* Copyright (C) 2008 Comune di Torino
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package it.doqui.index.ecmengine.business.job.tenant;
import java.util.List;
import it.doqui.index.ecmengine.business.job.JobBusinessInterface;
import it.doqui.index.ecmengine.business.job.dto.BatchJob;
import it.doqui.index.ecmengine.business.job.dto.BatchJobParam;
import it.doqui.index.ecmengine.business.job.util.EncryptionHelper;
import it.doqui.index.ecmengine.business.job.util.JobStatus;
import it.doqui.index.ecmengine.business.personalization.multirepository.RepositoryManager;
import it.doqui.index.ecmengine.business.personalization.multirepository.Repository;
import it.doqui.index.ecmengine.business.personalization.multirepository.ContentStoreDefinition;
import it.doqui.index.ecmengine.dto.backoffice.Tenant;
import static it.doqui.index.ecmengine.util.EcmEngineConstants.*;
import static it.doqui.index.ecmengine.business.job.tenant.TenantAdminJobConstants.*;
import it.doqui.index.ecmengine.business.personalization.multirepository.bootstrap.MultiTTenantAdminService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.ArrayList;
/**
* Classe che implementa il job per la creazione di tenant. L'esecuzione del job
* avviene in maniera sincronizzata, evitando l'esecuzione in concorrenza nel
* caso di schedulazioni sovrapposte o nel caso in cui l'esecuzione venga
* avviata prima del termine di una esecuzione precedente. Questa classe include
* anche alcuni metodi di utilità per la gestione delle istanze di
* {@code BatchJob} relative a questo tipo di job.
*
* @author DoQui
*
*/
public class TenantAdminJob implements Job {
private static Log logger = LogFactory.getLog(ECMENGINE_JOB_TENANT_LOG_CATEGORY);
private static boolean running = false;
/* (non-Javadoc)
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
*/
public void execute(JobExecutionContext context) throws JobExecutionException {
logger.debug("[TenantAdminJob::execute] BEGIN");
if (!running) {
synchronized (this) {
if (!running) {
running = true;
} else {
logger.debug("[TenantAdminJob::execute] job already running");
logger.debug("[TenantAdminJob::execute] END");
return;
}
}
} else {
logger.debug("[TenantAdminJob::execute] job already running");
logger.debug("[TenantAdminJob::execute] END");
return;
}
JobBusinessInterface jobManager = null;
BatchJob batchJob = null;
String status = null;
String message = null;
try {
jobManager = (JobBusinessInterface)context.getJobDetail().getJobDataMap().get(ECMENGINE_JOB_MANAGER_BEAN);
MultiTTenantAdminService tenantAdminService = (MultiTTenantAdminService)context.getJobDetail().getJobDataMap().get(ECMENGINE_TENANT_ADMIN_SERVICE_BEAN);
List<Repository> repositories = RepositoryManager.getInstance().getRepositories();
for (Repository repository : repositories) {
logger.debug("[TenantAdminJob::execute] creating tenants on repository '"+repository.getId()+"'");
RepositoryManager.setCurrentRepository(repository.getId());
// TODO: MB: verificare se serve impostarsi come utente di sistema e fare un lock in write del repository .. forse utente di sistema si e lock no
batchJob = jobManager.getNextJob(ECMENGINE_TENANT_ADMIN_JOB_REF);
if (batchJob != null) {
while (batchJob != null) {
try {
String domain = batchJob.getParam(PARAM_DOMAIN).getValue();
String adminPassword = EncryptionHelper.decrypt(batchJob.getParam(PARAM_ADMIN_PASSWORD).getValue());
String contentRootLocation = batchJob.getParam(PARAM_CONTENT_ROOT_LOCATION) != null ? batchJob.getParam(PARAM_CONTENT_ROOT_LOCATION).getValue() : null;
// MB: Leggo i contentStore
List<ContentStoreDefinition> lcs = new ArrayList<ContentStoreDefinition>();
int nStore = 0;
while( true ){
BatchJobParam tjp = batchJob.getParam(PARAM_CONTENT_STORE_TYPE +nStore);
if( tjp==null ) break;
BatchJobParam pjp = batchJob.getParam(PARAM_CONTENT_STORE_PROTOCOL+nStore);
if( pjp==null ) break;
BatchJobParam rjp = batchJob.getParam(PARAM_CONTENT_STORE_RESOURCE+nStore);
if( rjp==null ) break;
ContentStoreDefinition cs = new ContentStoreDefinition();
cs.setType( tjp.getValue() );
cs.setProtocol( pjp.getValue() );
cs.setResource( rjp.getValue() );
lcs.add( cs );
logger.debug("[TenantAdminJob::execute] contentStore " +cs.getType() +":" +cs.getProtocol() +"->" +cs.getResource() );
nStore++;
}
//MB: ora prendo il percorso impostato per questo tenant
// e verifico che non sia utilizzato all'interno di un repository diverso quello nel quale e' stato
// chiesto di creare il tenant: il senso e' quello di non usare lo stesso path su reposytory diversi.
//
//TODO: verificare la consistenza anche relativamente alle contentStoreDefinition
// occorre verificare che tutte le csd del tenant da creare, non vadano a sovrapporsi con le csd
// di un qualsiasi altro repository/tenant
// MASTER: EcmEngineBackofficeBean.java
String cRepID = RepositoryManager.getCurrentRepository();
try {
// Creo il path nel quale andranno i dati
String cPath = contentRootLocation;//tenant.getRootContentStoreDir();
// Se e' presente un percorso, provo a vedere se esiste un tenant, in un altro
// repository, con lo stesso path
if( cPath!=null && cPath.length()>0 ) {
//List<it.doqui.index.ecmengine.business.personalization.multirepository.Repository> repositories = RepositoryManager.getInstance().getRepositories();
for (it.doqui.index.ecmengine.business.personalization.multirepository.Repository repositorySub : repositories) {
logger.debug("[TenantAdminJob::createTenant] check tenants on repository '"+repositorySub.getId()+"'");
// Salto il repository corrente
if( !cRepID.equals(repositorySub.getId()) ){
// Imposto il nuovo repository
RepositoryManager.setCurrentRepository(repositorySub.getId());
// Mi loggo come utente di sistema
AuthenticationUtil.setSystemUserAsCurrentUser();
// Prendo i tenant
List<org.alfresco.repo.tenant.Tenant> tenantList = tenantAdminService.getAllTenants();
for (org.alfresco.repo.tenant.Tenant tenantTarget : tenantList) {
// Prendo il path nel quale andranno i dati
String cPathTarget = tenantTarget.getRootContentStoreDir();
if( cPathTarget!=null && cPathTarget.length()>0 ) {
if( cPath.equals(cPathTarget) ){
throw new Exception("Utilizzo illegale del path (" +cPath +") in quanto gia' utilizzato dal tenant (" +tenantTarget.getTenantDomain() +") del repository (" +repositorySub.getId() +")");
}
}
}
}
}
}
//} catch (InvalidParameterException ipe) {
// Rimbalzo l'eccezione
//throw ipe;
} catch (Exception e) {
// Qualsiasi errore genera la creazione di un invalidParameter
throw e; //new InvalidParameterException("Impossibile determinare l'univocita' del path del tenant");
} finally {
RepositoryManager.setCurrentRepository(cRepID);
}
//--------------------------------------------------------------------------------------------------
if(logger.isDebugEnabled()) {
logger.debug("[TenantAdminJob::execute] creating tenant '"+domain+"' on repository '"+RepositoryManager.getCurrentRepository()+"', root location: "+contentRootLocation);
}
tenantAdminService.createTenant(domain, adminPassword.toCharArray(), contentRootLocation, lcs);
logger.debug("[TenantAdminJob::execute] tenant '"+domain+"' created successfully");
status = JobStatus.FINISHED;
message = "";
} catch(Exception e) {
logger.error("[TenantAdminJob::execute] ERROR", e);
status = JobStatus.ERROR;
message = e.getMessage();
} finally {
try {
batchJob.setStatus(status);
batchJob.setMessage(message);
jobManager.updateJob(batchJob);
} catch(Exception e) {
logger.warn("[TenantAdminJob::execute] error updating job status", e);
}
}
batchJob = jobManager.getNextJob(ECMENGINE_TENANT_ADMIN_JOB_REF);
}
} else {
logger.debug("[TenantAdminJob::execute] no tenant jobs found");
}
}
} catch(Exception e) {
logger.error("[TenantAdminJob::execute] ERROR", e);
throw new JobExecutionException(e);
} finally {
running = false;
logger.debug("[TenantAdminJob::execute] END");
}
}
/**
* Metodo statico di utilità per la creazione del job da fornire come
* parametro al job manager.
*
* @param tenant
* L'istanza di {@code Tenant} contenente i dati del tenant.
* @return L'istanza di {@code BatchJob} contenente i dati necessati al job
* di creazione del tenant.
* @throws Exception
* @see {@link it.doqui.index.ecmengine.business.job.JobBusinessInterface}
*/
public static BatchJob createBatchJob(Tenant tenant) throws Exception {
// TODO: controllo di non esistenza del tenant
// TODO: controllo che non ci sia un JOB in coda, per la creazione di questo tenant
BatchJob job = new BatchJob(ECMENGINE_TENANT_ADMIN_JOB_REF);
job.addParam(new BatchJobParam(TenantAdminJobConstants.PARAM_DOMAIN , tenant.getDomain()) );
job.addParam(new BatchJobParam(TenantAdminJobConstants.PARAM_ADMIN_PASSWORD , EncryptionHelper.encrypt(tenant.getAdminPassword())) );
job.addParam(new BatchJobParam(TenantAdminJobConstants.PARAM_CONTENT_ROOT_LOCATION , tenant.getRootContentStoreDir()) );
// MB: aggiungo la lista dei bean di content store
logger.debug("[TenantAdminJob::createBatchJob] tenant.getContentStores");
if( tenant.getContentStores()!=null ){
int nStore = 0;
for( Object cs: tenant.getContentStores() ){
it.doqui.index.ecmengine.dto.backoffice.ContentStoreDefinition tcs = (it.doqui.index.ecmengine.dto.backoffice.ContentStoreDefinition)cs;
logger.debug("[TenantAdminJob::createBatchJob] contentStore (" +nStore +") " +tcs.getType() +":" +tcs.getProtocol() +"->" +tcs.getResource() );
job.addParam(new BatchJobParam(TenantAdminJobConstants.PARAM_CONTENT_STORE_TYPE +nStore, tcs.getType() ) );
job.addParam(new BatchJobParam(TenantAdminJobConstants.PARAM_CONTENT_STORE_PROTOCOL+nStore, tcs.getProtocol() ) );
job.addParam(new BatchJobParam(TenantAdminJobConstants.PARAM_CONTENT_STORE_RESOURCE+nStore, tcs.getResource() ) );
nStore++;
}
}
return job;
}
}