/******************************************************************************* * Copyright 2011 * Ubiquitous Knowledge Processing (UKP) Lab * Technische Universität Darmstadt * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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 org.dkpro.lab.engine.impl; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.dkpro.lab.engine.LifeCycleException; import org.dkpro.lab.engine.LifeCycleManager; import org.dkpro.lab.engine.TaskContext; import org.dkpro.lab.reporting.Report; import org.dkpro.lab.task.ConfigurationAware; import org.dkpro.lab.task.Task; import org.dkpro.lab.task.TaskContextMetadata; import org.dkpro.lab.task.impl.ParameterUtil; import org.springframework.beans.PropertyAccessor; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.dao.DataAccessResourceFailureException; public class DefaultLifeCycleManager implements LifeCycleManager { @Override public void configure(TaskContext aParentContext, Task aTask, Map<String, Object> aConfiguration) { PropertyAccessor paBean = PropertyAccessorFactory.forBeanPropertyAccess(aTask); PropertyAccessor paDirect = PropertyAccessorFactory.forDirectFieldAccess(aTask); for (Entry<String, Object> property : aConfiguration.entrySet()) { String key = property.getKey(); Object value = property.getValue(); // Find all fields that are annotated with a discriminator/property that have // a non-default name and might apply. for (String prop : ParameterUtil.findBeanPropertiesWithName(aTask, key)) { // Try setter - there may be extra logic in the setter if (paBean.isWritableProperty(prop)) { paBean.setPropertyValue(prop, value); } // Otherwise try direct access else if (paDirect.isWritableProperty(prop)) { paDirect.setPropertyValue(prop, value); } } // And try once again for all fields where the name is not explicitly set // Try setter - there may be extra logic in the setter if (paBean.isWritableProperty(key)) { paBean.setPropertyValue(key, value); } // Otherwise try direct access else if (paDirect.isWritableProperty(key)) { paDirect.setPropertyValue(key, value); } } if (aTask instanceof ConfigurationAware) { ((ConfigurationAware) aTask).setConfiguration(aConfiguration); } if (aParentContext != null) { aParentContext.message("Injected parameters into ["+aTask.getType()+"]"); } } @Override public void initialize(TaskContext aContext, Task aConfiguration) throws LifeCycleException { // Preparation hook for batch task in case it wants to do anything to itself // before the subtasks are executed (e.g. adding subtasks or a parameter space) aConfiguration.initialize(aContext); aContext.message("Initialized task ["+aConfiguration.getType()+"]"); aConfiguration.analyze(); aContext.message("Analyzed task configuration ["+aConfiguration.getType()+"]"); try { aConfiguration.persist(aContext); aContext.message("Persisted task configuration ["+aConfiguration.getType()+"]"); } catch (IOException e) { throw new LifeCycleException(e); } } @Override public void begin(TaskContext aContext, Task aConfiguration) { for (int g = 0; g < 3; g++) { System.gc(); } aContext.getMetadata().setStart(System.currentTimeMillis()); aContext.message("Starting task ["+aConfiguration.getType()+"]"); } @Override public void complete(TaskContext aContext, Task aConfiguration) throws LifeCycleException { aContext.getMetadata().setEnd(System.currentTimeMillis()); aContext.message("Completing task ["+aConfiguration.getType()+"]"); aContext.message("Running reports for task ["+aConfiguration.getType()+"]"); List<Class<? extends Report>> reports = new ArrayList<Class<? extends Report>>( aConfiguration.getReports()); int i = 1; for (Class<? extends Report> reportClass : reports) { for (int g = 0; g < 3; g++) { System.gc(); } try { aContext.message("Starting report [" + reportClass.getName() + "] (" + i + "/" + reports.size() + ")"); Report report = reportClass.newInstance(); report.setContext(aContext); report.execute(); aContext.message("Report complete [" + reportClass.getName() + "] (" + i + "/" + reports.size() + ")"); } catch (Exception e) { aContext.error("Report failed [" + reportClass.getName() + "] (" + i + "/" + reports.size() + ")", e); throw new LifeCycleException(e); } finally { i++; } } // This is a critical file as it marks if a task has completed successfully or not. If // this file cannot be created properly, e.g. because the disk is full, then there will be // subsequent and hard to debug errors. Thus, if the file cannot be created properly, any // potentially incomplete version of this file has to be deleted. try { aContext.storeBinary(TaskContextMetadata.METADATA_KEY, aContext.getMetadata()); } catch (Throwable e) { aContext.getStorageService().delete(aContext.getId(), TaskContextMetadata.METADATA_KEY); throw new LifeCycleException("Unable to write [" + TaskContextMetadata.METADATA_KEY + "] to mark context as complete.", e); } aContext.message("Completed task ["+aConfiguration.getType()+"]"); } @Override public void fail(TaskContext aContext, Task aConfiguration, Throwable aCause) throws LifeCycleException { try { aContext.getStorageService().delete(aContext.getId()); } catch (DataAccessResourceFailureException e) { aContext.error("Unable to clean up context after failure. Some data may remain in " + "the context.", e); } aContext.error("Task failed ["+aConfiguration.getType()+"]", aCause); } @Override public void destroy(TaskContext aContext, Task aConfiguration) { aConfiguration.destroy(aContext); if (aConfiguration.isInitialized()) { throw new IllegalStateException( "Task not destroyed. Maybe forgot to call super.destroy(ctx) in [" + getClass().getName() + "]?"); } aContext.destroy(); aContext.message("Shut down task"); } }