public Map<String, Object> process(Map<String, Object> input) { if (!isValid) { validate(true); } Long currentProcessId = processId.incrementAndGet(); Semaphore resultSemaphoreForProcess = new Semaphore(0); resultSemaphores.put(currentProcessId, resultSemaphoreForProcess); // send input to all input pipeline stages for (PipelineStage inputStage : inputStages.keySet()) { Map<String, String> inputPortMapping = inputStages.get(inputStage); for (String inputPort : inputPortMapping.keySet()) { Object inputParam = input.get(inputPort); inputStage.consume(currentProcessId, inputPortMapping.get(inputPort), inputParam); } } // wait for the output to become ready resultSemaphoreForProcess.acquireUninterruptibly(); if (Boolean.FALSE == processingStatus.remove(currentProcessId)) { Throwable t = processingException.remove(currentProcessId); throw new PipelineProcessingException( "Processing failed for id '" + currentProcessId + "'.", t); } // cleanup and return the result return clear(currentProcessId); }
/** * Abort the processing for a given id. * * @param id The processing id. * @param t The exception that was caught during the processing. */ protected void abort(Long id, Throwable t) { processingStatus.put(id, Boolean.FALSE); processingException.put(id, t); for (PipelineStage c : pipelineStages.values()) { // TODO: This will result in a memory leak once we add multi threading. Threads might already // be running and producing new data. c.clear(id); } }
/** * Validate that the pipeline is consistent. * * @param hard If this is set to true, an exception will be thrown if the validation fails. * @return True if the validation succeeded. */ @Override public boolean validate(boolean hard) { // check that all input ports will be populated for (PipelineStage c : pipelineStages.values()) { if (this == c) { continue; } if (!c.validate(hard)) { return false; } } return true; }
/** * Add a target stage for a given out-port. * * @param outPort The outgoing port. * @param target The target stage. * @param targetInPort The ingoing port of the target stage. */ @Override public void addTarget(String outPort, PipelineStage target, String targetInPort) { Map<String, String> parametersForInputStage = this.inputStages.get(target); if (null == parametersForInputStage) { parametersForInputStage = new HashMap<>(); this.inputStages.put(target, parametersForInputStage); } parametersForInputStage.put(outPort, targetInPort); // tell the target who will provide the data target.setInPortSupplier(this, targetInPort); }
/** * Add a pipe between two workers. * * @param sourceWorker The source worker. * @param sourceOutPort The source port. * @param targetWorker The target worker. * @param targetInPort The target port. */ public void addPipe( String sourceWorker, String sourceOutPort, String targetWorker, String targetInPort) { if (null == sourceWorker) { // this is an input pipe PipelineStage targetStage = pipelineStages.get(targetWorker); if (null == targetStage) { throw new ProcessingPipelineInitializationException( "No worker with name '" + targetWorker + "' available in pipeline + '" + name + "'."); } this.addTarget(sourceOutPort, targetStage, targetInPort); } else if (null == targetWorker) { // this is an output pipe PipelineStage sourceStage = pipelineStages.get(sourceWorker); if (!pipelineStages.containsKey(sourceWorker)) { throw new ProcessingPipelineInitializationException( "No worker with name '" + sourceWorker + "' available in pipeline + '" + name + "'."); } if (outputPorts.contains(targetInPort)) { throw new ProcessingPipelineInitializationException( "Output port '" + targetInPort + "' is already defined for pipeline + '" + name + "'."); } sourceStage.addTarget(sourceOutPort, this, targetInPort); this.outputPorts.add(targetInPort); } else { // this is an intermediate pipe PipelineStage sourceStage = pipelineStages.get(sourceWorker); if (null == sourceStage) { throw new ProcessingPipelineInitializationException( "No worker with name '" + sourceWorker + "' available in pipeline + '" + name + "'."); } PipelineStage targetStage = pipelineStages.get(targetWorker); if (null == targetStage) { throw new ProcessingPipelineInitializationException( "No worker with name '" + targetWorker + "' available in pipeline + '" + name + "'."); } sourceStage.addTarget(sourceOutPort, targetStage, targetInPort); } this.isValid = validate(false); }