package uk.ac.diamond.scisoft.analysis.processing.actor.actors; import java.io.File; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dawb.passerelle.actors.data.config.IOperationModelInstanceProvider; import org.dawb.passerelle.actors.data.config.OperationModelParameter; import org.dawb.passerelle.common.actors.AbstractDataMessageTransformer; import org.dawb.passerelle.common.message.MessageUtils; import org.eclipse.dawnsci.analysis.api.message.DataMessageComponent; import org.eclipse.dawnsci.analysis.api.processing.IOperation; import org.eclipse.dawnsci.analysis.api.processing.IOperationContext; import org.eclipse.dawnsci.analysis.api.processing.OperationData; import org.eclipse.dawnsci.analysis.api.processing.model.IOperationModel; import org.eclipse.dawnsci.analysis.dataset.slicer.SliceFromSeriesMetadata; import org.eclipse.dawnsci.analysis.dataset.slicer.SourceInformation; import org.eclipse.january.dataset.IDataset; import org.eclipse.january.dataset.Slice; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.NameDuplicationException; import com.isencia.passerelle.actor.ProcessingException; import com.isencia.passerelle.util.ptolemy.IAvailableChoices; import com.isencia.passerelle.util.ptolemy.StringChoiceParameter; /** * Transformer to run an operation. * * @author Matthew Gerring * TODO Move {@link IOperationModelInstanceProvider} out of {@link org.dawb.passerelle.actors.ui} an put in a more common location */ public class OperationTransformer extends AbstractDataMessageTransformer implements IOperationModelInstanceProvider{ private static final Logger logger = LoggerFactory.getLogger(OperationTransformer.class); /** * */ private static final long serialVersionUID = 4261989437774965670L; private IOperation<? extends IOperationModel, ? extends OperationData> operation; private IOperationContext context; // May be null. /** * */ public final StringChoiceParameter operationId; /** * TODO use OSGi instead of having to use directly the implementation */ public final OperationModelParameter model; public OperationTransformer(CompositeEntity container, String name) throws NameDuplicationException, IllegalActionException { super(container, createNonNullName(name)); operationId = new StringChoiceParameter(this, "Operation", new IAvailableChoices() { @Override public String[] getChoices() { try { Collection<String> ops = OperationServiceHolder.getOperationService().getRegisteredOperations(); return ops.toArray(new String[ops.size()]); } catch (Exception ne) { return new String[]{"Please select a Data File"}; } } @Override public Map<String,String> getVisibleChoices() { try { Collection<String> ops = OperationServiceHolder.getOperationService().getRegisteredOperations(); Map<String, String> ret = new HashMap<String, String>(ops.size()); for (String id : ops) ret.put(id, OperationServiceHolder.getOperationService().getName(id)); return ret; } catch (Exception ne) { return null; } } }, 1 << 2); // Single selection bit setDescription(operationId, Requirement.ESSENTIAL, VariableHandling.NONE, "The id of the operation that you would like to use."); registerConfigurableParameter(operationId); model = new OperationModelParameter(this, "Model"); setDescription(model, Requirement.ESSENTIAL, VariableHandling.NONE, "The model for the operation we are running.\n\nThis model will be saved and edited with the same table available in the processing perspective."); registerConfigurableParameter(model); } @Override public Class<? extends IOperationModel> getModelClass() throws Exception { final String opId = operationId.getExpression(); if (opId !=null) return OperationServiceHolder.getOperationService().getModelClass(opId); return null; } private static long nullNameCount = 0; private static String createNonNullName(String name) { if (name!=null) return name; return "OperationTransformer_"+(++nullNameCount); } @Override protected DataMessageComponent getTransformedMessage(List<DataMessageComponent> cache) throws ProcessingException { try { DataMessageComponent msg = MessageUtils.mergeAll(cache); IDataset data = (IDataset)msg.getList().values().iterator().next(); SliceFromSeriesMetadata fullssm = null; try { SourceInformation ssource = data.getMetadata(SliceFromSeriesMetadata.class).get(0).getSourceInfo(); final SliceFromSeriesMetadata ssm = data.getMetadata(SliceFromSeriesMetadata.class).get(0); fullssm = new SliceFromSeriesMetadata(ssource, ssm.getSliceInfo()); data.setMetadata(fullssm); }catch (Exception e) { logger.error("Source not obtainable. Hope this is just a unit test..."); } if (operation==null) operation = createOperation(); OperationData tmp = operation.execute(data, context!=null ? context.getMonitor() : null); if (tmp == null) { //if null after all operations, still need to execute with null //so the visitor knows a pass has finished if (output.getWidth()<1 && context!=null && context.getVisitor()!=null) { context.getVisitor().executed(null, context.getMonitor()); if (context.getMonitor() != null) context.getMonitor().worked(1); logger.debug("null output ran in: " +(System.currentTimeMillis()-msg.getTime())/1000. + " s : Thread" +Thread.currentThread().toString()); } return null; } data = operation.isPassUnmodifiedData() ? data : tmp.getData(); List<SliceFromSeriesMetadata> md = tmp.getData().getMetadata(SliceFromSeriesMetadata.class); if (fullssm!=null && (md == null || md.isEmpty())) tmp.getData().setMetadata(fullssm); if (context!=null && context.getVisitor()!=null) { context.getVisitor().notify(operation, tmp); // Optionally send intermediate result if (output.getWidth()<1) { // We have reached the end. OperationData odata = new OperationData(data); if (!operation.isPassUnmodifiedData()) odata.setAuxData(tmp.getAuxData()); context.getVisitor().executed(odata, context.getMonitor()); // Send result. if (context.getMonitor() != null) { context.getMonitor().worked(1); String update = ""; if (fullssm != null) { try { String filePath = fullssm.getFilePath(); File f = new File(filePath); String name = f.getName(); String slice = Slice.createString(fullssm.getSliceFromInput()); update = name+ " ["+ slice + "] " + operation.getName(); } catch (Exception e) { logger.error("Could not update progress: " + e.getMessage()); } } context.getMonitor().subTask(update); } logger.debug(data.getName()+" ran in: " +(System.currentTimeMillis()-msg.getTime())/1000. + " s : Thread" +Thread.currentThread().toString()); } } // Construct a DataMessageComponent to pass on. msg.clearList(); msg.setList(data); return msg; } catch (Exception ne) { throw createDataMessageException(ne.getMessage(), ne); } } private IOperation<? extends IOperationModel, ? extends OperationData> createOperation() throws Exception { IOperation<IOperationModel, OperationData> op = (IOperation<IOperationModel, OperationData>)OperationServiceHolder.getOperationService().create(operationId.getExpression()); IOperationModel omod = model.getValue(OperationServiceHolder.getOperationService().getModelClass(op.getId())); op.setModel(omod); return op; } @Override protected String getOperationName() { return operation.getName(); } public IOperation<? extends IOperationModel, ? extends OperationData> getOperation() { return operation; } public void setOperation(IOperation<? extends IOperationModel, ? extends OperationData> operation) { this.operation = operation; operationId.setExpression(operation.getId()); model.setValue(operation.getModel()); } public IOperationContext getContext() { return context; } public void setContext(IOperationContext context) { this.context = context; } }