Java tutorial
/******************************************************************************* * Copyright (c) 2013 * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Lautaro Matas (lmatas@gmail.com) - Desarrollo e implementacin * Emiliano Marmonti(emarmonti@gmail.com) - Coordinacin del componente III * * Este software fue desarrollado en el marco de la consultora "Desarrollo e implementacin de las soluciones - Prueba piloto del Componente III -Desarrollador para las herramientas de back-end" del proyecto Estrategia Regional y Marco de Interoperabilidad y Gestin para una Red Federada Latinoamericana de Repositorios Institucionales de Documentacin Cientfica? financiado por Banco Interamericano de Desarrollo (BID) y ejecutado por la Cooperacin Latino Americana de Redes Avanzadas, CLARA. ******************************************************************************/ package org.lareferencia.backend.tasks; import java.util.Date; import java.util.List; import java.util.Map; import javax.xml.crypto.Data; import lombok.Getter; import lombok.Setter; import org.lareferencia.backend.domain.Network; import org.lareferencia.backend.domain.NetworkSnapshot; import org.lareferencia.backend.domain.NetworkSnapshotLog; import org.lareferencia.backend.domain.NetworkSnapshotMetadataStat; import org.lareferencia.backend.domain.OAIOrigin; import org.lareferencia.backend.domain.OAIRecord; import org.lareferencia.backend.domain.OAIRecordValidationResult; import org.lareferencia.backend.domain.OAISet; import org.lareferencia.backend.domain.RecordStatus; import org.lareferencia.backend.domain.SnapshotStatus; import org.lareferencia.backend.harvester.HarvestingEvent; import org.lareferencia.backend.harvester.IHarvester; import org.lareferencia.backend.harvester.IHarvestingEventListener; import org.lareferencia.backend.harvester.OAIRecordMetadata; import org.lareferencia.backend.indexer.IIndexer; import org.lareferencia.backend.repositories.NetworkRepository; import org.lareferencia.backend.repositories.NetworkSnapshotLogRepository; import org.lareferencia.backend.repositories.NetworkSnapshotRepository; import org.lareferencia.backend.repositories.NetworkSnapshotMetadataStatRepository; import org.lareferencia.backend.repositories.OAIRecordRepository; import org.lareferencia.backend.repositories.OAIRecordValidationRepository; import org.lareferencia.backend.stats.IMetadataStatProcessor; import org.lareferencia.backend.stats.IMetadataStatsManager; import org.lareferencia.backend.transformer.ITransformer; import org.lareferencia.backend.util.RepositoryNameHelper; import org.lareferencia.backend.util.datatable.DataTable; import org.lareferencia.backend.util.datatable.JsonRenderer; import org.lareferencia.backend.validator.IValidator; import org.lareferencia.backend.validator.ValidationResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component @Scope(value = "prototype") public class SnapshotWorker implements ISnapshotWorker, IHarvestingEventListener { @Value("${harvester.max.retries}") private int MAX_RETRIES; ////// Variables de deteccin de repositorios tomadas desde la configuracin private RepositoryNameHelper repositoryNameHelper; @Value("${reponame.detection}") private Boolean runRepoNameDetection; @Value("${reponame.pattern}") private String repoNameDetectionPatternString; @Value("${reponame.append}") private Boolean doRepoNameAppend; @Value("${reponame.field}") private String repoNameField; @Value("${reponame.prefix}") private String repoNamePrefix; @Value("${instname.append}") private Boolean doInstNameAppend; @Value("${instname.field}") private String instNameField; @Value("${instname.prefix}") private String instNamePrefix; //// fin de variables de deteccin de nombres de repositorios @Autowired private ApplicationContext applicationContext; @Autowired private NetworkRepository networkRepository; @Autowired private NetworkSnapshotRepository snapshotRepository; @Autowired private NetworkSnapshotLogRepository snapshotLogRepository; @Autowired private NetworkSnapshotMetadataStatRepository snapshotStatRepository; @Autowired private NetworkSnapshotMetadataStatRepository statRepository; @Autowired private OAIRecordRepository recordRepository; @Autowired private IMetadataStatsManager originalMetadataStatsManager; @Autowired private IMetadataStatsManager transformedMetadataStatsManager; @Autowired private OAIRecordValidationRepository recordValidationRepository; private IHarvester harvester; @Autowired public void setHarvester(IHarvester harvester) { this.harvester = harvester; // los eventos de harvesting sern manejados por el worker harvester.addEventListener(this); } // No son autowired, se cargan en cada ejecucin de acuerdo a la conf de cada red private IValidator validator; private ITransformer transformer; @Autowired private IIndexer indexer; @Setter private Long networkID; @Setter private Long snapshotID; private Network network; private NetworkSnapshot snapshot; @Getter @Setter private boolean harvestBySet = false; @Getter @Setter private SnapshotManager manager; public SnapshotWorker() { }; public NetworkSnapshot getSnapshot() { return snapshot; } @Override public void stop() { System.out.print("Seal de stopHarvesting recibida por el worker: "); harvester.stop(); } /** * TODO: Podra ser Async, pero no tiene sentido empezar un nuevo proceso de harvesting para una misma red si el anterior * no termin. Hay que cuidar los bloqueos!!! TODO: Podra implemetarse la limpieza de procesos inactivos para evitar problemas * @throws Exception */ @Override public void run() { boolean newSnapshotCreated = true; if (snapshotID != null) { // Este es el caso en que se retorma un snapshot bloqueado snapshot = snapshotRepository.findOne(snapshotID); if (snapshot != null && snapshot.getStatus().equals(SnapshotStatus.HARVESTING_STOPPED)) { // tiene que estar detenido network = snapshot.getNetwork(); newSnapshotCreated = false; // cambia el status setSnapshotStatus(SnapshotStatus.HARVESTING); } else { System.err.println( "El snapshot no existe o est ya est siendo procesado. El worker no puede continuar"); return; } } else { // este es el caso donde se inicia un nuevo snapshot network = networkRepository.findOne(networkID); if (network != null) { snapshot = new NetworkSnapshot(); snapshot.setNetwork(network); snapshotRepository.save(snapshot); } else { System.err.println("La Red no existe!! El worker no puede continuar"); return; } } // Se cargan el validador y el transformador de acuerdo a la configuracin de la red try { logMessage("Cargando validador y transformador ..."); validator = applicationContext.getBean(network.getValidatorName(), IValidator.class); transformer = applicationContext.getBean(network.getTransformerName(), ITransformer.class); } catch (Exception e) { logMessage("Error en la carga del validador o transformador, vea el log para ms detalles."); setSnapshotStatus(SnapshotStatus.HARVESTING_FINISHED_ERROR); return; } // Se carga el helper para la resolucin de nombre de repositorios repositoryNameHelper = new RepositoryNameHelper(); repositoryNameHelper.setDetectREPattern(repoNameDetectionPatternString); // Se registra el incicio de tareas en el manager manager.registerWorkerBeginSnapshot(snapshot.getId(), this); logMessage("Comenzando cosecha ..."); setSnapshotStatus(SnapshotStatus.HARVESTING); // harvest de la red // inicializacin del harvester harvester.reset(); if (newSnapshotCreated) // caso de harvesting desde cero if (harvestBySet) harvestEntireNetworkBySet(); else harvestEntireNetwork(); else // caso de retomar desde un rt anterior harvestNetworkFromRT(snapshot.getResumptionToken()); // Luego del harvesting el snapshot puede presentar estados diversos // si no fue detenido if (snapshot.getStatus() != SnapshotStatus.HARVESTING_STOPPED) { // Si no gener errores, entonces termin exitosa la cosecha if (snapshot.getStatus() != SnapshotStatus.HARVESTING_FINISHED_ERROR) { logMessage("Cosecha terminada en forma exitosa"); logMessage("Comenzando indexacin ..."); // Graba el status snapshot.setEndTime(new Date()); setSnapshotStatus(SnapshotStatus.INDEXING); // Si est publicada la red y es una red que se indexa if (network.isRunIndexing() && network.isPublished()) { // Indexa boolean isSuccesfullyIndexed = indexer.index(snapshot); // Si el indexado es exitoso marca el snap vlido if (isSuccesfullyIndexed) { // Graba el status setSnapshotStatus(SnapshotStatus.VALID); logMessage("Indexacin terminada con xito."); } else { // Graba el status setSnapshotStatus(SnapshotStatus.INDEXING_FINISHED_ERROR); logMessage("Error en proceso de indexacin."); } } else { // si no est publicada o no se indexa la marca como vlida sin indexar // Graba el status setSnapshotStatus(SnapshotStatus.VALID); // Almacena los resultados de las statsticas de metadatatos if (network.isRunStats()) { saveSnapshotMetadataStats(originalMetadataStatsManager.getStats()); saveSnapshotMetadataStats(transformedMetadataStatsManager.getStats()); } } } else { logMessage("Cosecha finalizada con errores"); } } snapshot.setEndTime(new Date()); snapshotRepository.save(snapshot); // Flush y llamados al GC snapshotRepository.flush(); // Se registra el fin de tareas en el manager manager.registerWorkerEndSnapshot(snapshot.getId()); System.gc(); } /*************************************************************/ private void harvestNetworkFromRT(String resumptionToken) { // Se recorren los orgenes evaluando de cual era el rt TODO: Hay que guardar el origen corriente en el snapshot for (OAIOrigin origin : network.getOrigins()) { harvester.harvest(origin.getUri(), null, null, null, origin.getMetadataPrefix(), resumptionToken, MAX_RETRIES); } } private void harvestEntireNetwork() { // Ciclo principal de procesamiento, dado por la estructura de la red nacional // Se recorren los orgenes for (OAIOrigin origin : network.getOrigins()) { // si tiene sets declarados solo va a cosechar if (origin.getSets().size() > 0) { for (OAISet set : origin.getSets()) { harvester.harvest(origin.getUri(), null, null, set.getSpec(), origin.getMetadataPrefix(), null, MAX_RETRIES); } } // si no hay set declarado cosecha todo else { harvester.harvest(origin.getUri(), null, null, null, origin.getMetadataPrefix(), null, MAX_RETRIES); } } } private void harvestEntireNetworkBySet() { // Ciclo principal de procesamiento, dado por la estructura de la red nacional // Se recorren los orgenes for (OAIOrigin origin : network.getOrigins()) { List<String> setList = harvester.listSets(origin.getUri()); for (String setName : setList) { System.out.println("Cosechando: " + origin.getName() + " set: " + setName); harvester.harvest(origin.getUri(), null, null, setName, origin.getMetadataPrefix(), null, MAX_RETRIES); } } } @Override @Transactional public void harvestingEventOccurred(HarvestingEvent event) { System.out.println(network.getName() + " HarvestingEvent recibido: " + event.getStatus()); switch (event.getStatus()) { case OK: //List<OAIRecord> records = new ArrayList<OAIRecord>(100); // Agrega los records al snapshot actual for (OAIRecordMetadata metadata : event.getRecords()) { try { OAIRecord record = new OAIRecord(metadata.getIdentifier()); // registra el snapshot al que pertenece record.setSnapshot(snapshot); snapshot.incrementSize(); if (network.isRunValidation()) { // prevalidacin ValidationResult validationResult = validator.validate(metadata); // Con el registro original prevalidado se registran las estadsticas previas a las transformacin if (network.isRunStats()) originalMetadataStatsManager.addMetadataObservation(metadata, validationResult); // si corresponde lo transforma if (network.isRunTransformation()) { // transforma Boolean wasTransformed = transformer.transform(metadata, validationResult); // marca si el registro fue transformado record.setWasTransformed(wasTransformed); // lo vuelve a validar validationResult = validator.validate(metadata); // Con el registro transformado y validado se registran las estadsticas posteriores a la transformacin if (network.isRunStats()) transformedMetadataStatsManager.addMetadataObservation(metadata, validationResult); // Si es vlido y hubo transformacin incrementa la cuenta de vlidos transformados if (wasTransformed && validationResult.isValid()) snapshot.incrementTransformedSize(); } // registra si result vlido o es irrecuperable (invlido) if (validationResult.isValid()) { record.setStatus(RecordStatus.VALID); snapshot.incrementValidSize(); } else { record.setStatus(RecordStatus.INVALID); } // En esta etapa se intenta obtener el nombre del repositorio y el de la institucin String repoName = repositoryNameHelper.extractNameFromMetadata(metadata, repoNameField, repoNamePrefix); // Si no existe el repoName en la metadata se intenta recuperarlo usando una expresin regular if (runRepoNameDetection && repoName.equals(RepositoryNameHelper.UNKNOWN)) repoName = repositoryNameHelper.detectRepositoryDomain(metadata.getIdentifier()); // Se establece el nombre del repositorio en el registro record.setRepositoryDomain(repoName); // Si est configurado agrega a la metadata el reponame y el instname if (doRepoNameAppend) repositoryNameHelper.appendNameToMetadata(metadata, repoNameField, repoNamePrefix, network.getName()); if (doInstNameAppend) repositoryNameHelper.appendNameToMetadata(metadata, instNameField, instNamePrefix, network.getInstitutionName()); // Se almacena la metadata transformada //if ( validationResult.isValid() ) record.setPublishedXML(metadata.toString()); //// SE ALMACENA EL REGISTRO recordRepository.save(record); recordRepository.flush(); /////////// TODO: Este cdigo debe esta encapsulado en otro lado /// TODO: Esto debe migrarse a metadata stats /// Almacenamiento de resultados de validacin OAIRecordValidationResult recordValidationResult; for (String field : validationResult.getFieldResults().keySet()) { Boolean isFieldValid = validationResult.getFieldResults().get(field).isValid(); Boolean isFieldMandatory = validationResult.getFieldResults().get(field).isMandatory(); if (!isFieldValid && isFieldMandatory) { recordValidationResult = new OAIRecordValidationResult(field); recordValidationResult.setSnapshot(snapshot); recordValidationResult.setRecord(record); recordValidationRepository.save(recordValidationResult); } } } else { // Si no se valida entonces todo puesto para publicacin // TODO: Chequear esto record.setStatus(RecordStatus.UNTESTED); record.setPublishedXML(metadata.toString()); } } catch (Exception e) { e.printStackTrace(); } } recordRepository.flush(); recordValidationRepository.flush(); snapshot.setEndTime(new Date()); snapshot.setResumptionToken(event.getResumptionToken()); // Graba el status setSnapshotStatus(SnapshotStatus.HARVESTING); break; case ERROR_RETRY: logMessage("Retry:" + event.getMessage()); System.out.println(event.getMessage()); snapshot.setEndTime(new Date()); // Graba el status setSnapshotStatus(SnapshotStatus.RETRYING); break; case ERROR_FATAL: logMessage("Fatal:" + event.getMessage()); System.out.println(event.getMessage()); snapshot.setEndTime(new Date()); // Graba el status setSnapshotStatus(SnapshotStatus.HARVESTING_FINISHED_ERROR); break; case STOP_SIGNAL_RECEIVED: logMessage("Detencin:" + event.getMessage()); System.out.println(event.getMessage()); // Graba el status setSnapshotStatus(SnapshotStatus.HARVESTING_STOPPED); break; default: /** * TODO: Definir que se hace en caso de eventos sin status conocido */ break; } } private void setSnapshotStatus(SnapshotStatus status) { // metodo auxiliar para centralizar la forma de actualizar status snapshot.setStatus(status); snapshotRepository.save(snapshot); snapshotRepository.flush(); } private void logMessage(String message) { snapshotLogRepository.save(new NetworkSnapshotLog(message, this.snapshot)); snapshotLogRepository.flush(); } private void saveSnapshotMetadataStats(Map<String, DataTable> statMap) { for (Map.Entry<String, DataTable> entry : statMap.entrySet()) { String JSONTableString = JsonRenderer.renderDataTable(entry.getValue(), true, true, true).toString(); NetworkSnapshotMetadataStat metadataStat = new NetworkSnapshotMetadataStat(entry.getKey(), JSONTableString); metadataStat.setSnapshot(snapshot); snapshotStatRepository.save(metadataStat); } } @Override public SnapshotStatus getStatus() { if (snapshot != null) return snapshot.getStatus(); else return SnapshotStatus.UNKNOWN; } }