/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
*
* 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.apache.streams.local.builders;
import org.apache.streams.config.StreamsConfiguration;
import org.apache.streams.core.DatumStatusCountable;
import org.apache.streams.core.StreamsDatum;
import org.apache.streams.core.StreamsOperation;
import org.apache.streams.core.StreamsPersistWriter;
import org.apache.streams.core.StreamsProcessor;
import org.apache.streams.core.StreamsProvider;
import org.apache.streams.local.tasks.StreamsPersistWriterTask;
import org.apache.streams.local.tasks.StreamsProcessorTask;
import org.apache.streams.local.tasks.StreamsProviderTask;
import org.apache.streams.local.tasks.StreamsTask;
import org.apache.streams.util.SerializationUtil;
import org.joda.time.DateTime;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
/**
* Stores the implementations of {@link org.apache.streams.core.StreamsOperation}, the StreamsOperations it is connected
* to and the necessary metadata to construct a data stream.
*/
public class StreamComponent implements Serializable {
private static final int START = 1;
private static final int END = 2;
private String id;
private Set<StreamComponent> inBound;
private Map<StreamComponent, BlockingQueue<StreamsDatum>> outBound;
private BlockingQueue<StreamsDatum> inQueue;
private StreamsProvider provider;
private StreamsProcessor processor;
private StreamsPersistWriter writer;
private DateTime[] dateRange;
private BigInteger sequence;
private int numTasks = 1;
private boolean perpetual;
private List<StreamsTask> tasks;
private StreamsConfiguration streamConfig;
/**
*
* @param id
* @param provider
*/
public StreamComponent(String id, StreamsProvider provider, boolean perpetual, StreamsConfiguration streamConfig) {
this.id = id;
this.provider = provider;
this.perpetual = perpetual;
this.streamConfig = streamConfig;
initializePrivateVariables();
}
/**
*
* @param id
* @param provider
* @param start
* @param end
*/
public StreamComponent(String id, StreamsProvider provider, DateTime start, DateTime end, StreamsConfiguration streamConfig) {
this.id = id;
this.provider = provider;
this.dateRange = new DateTime[2];
this.dateRange[START] = start;
this.dateRange[END] = end;
this.streamConfig = streamConfig;
initializePrivateVariables();
}
/**
*
* @param id
* @param provider
* @param sequence
*/
public StreamComponent(String id, StreamsProvider provider, BigInteger sequence, StreamsConfiguration streamConfig) {
this.id = id;
this.provider = provider;
this.sequence = sequence;
this.streamConfig = streamConfig;
}
/**
*
* @param id
* @param processor
* @param inQueue
* @param numTasks
*/
public StreamComponent(String id, StreamsProcessor processor, BlockingQueue<StreamsDatum> inQueue, int numTasks, StreamsConfiguration streamConfig) {
this.id = id;
this.processor = processor;
this.inQueue = inQueue;
this.numTasks = numTasks;
this.streamConfig = streamConfig;
initializePrivateVariables();
}
/**
*
* @param id
* @param writer
* @param inQueue
* @param numTasks
*/
public StreamComponent(String id, StreamsPersistWriter writer, BlockingQueue<StreamsDatum> inQueue, int numTasks, StreamsConfiguration streamConfig) {
this.id = id;
this.writer = writer;
this.inQueue = inQueue;
this.numTasks = numTasks;
this.streamConfig = streamConfig;
initializePrivateVariables();
}
private void initializePrivateVariables() {
this.inBound = new HashSet<>();
this.outBound = new HashMap<>();
this.tasks = new ArrayList<>();
}
/**
* Add an outbound queue for this component. The queue should be an inbound queue of a downstream component.
* @param component the component that this supplying their inbound queue
* @param queue the queue to to put post processed/provided datums on
*/
public void addOutBoundQueue(StreamComponent component, BlockingQueue<StreamsDatum> queue) {
this.outBound.put(component, queue);
}
/**
* Add a component that supplies data through the inbound queue.
* @param component that supplies data through the inbound queue
*/
public void addInboundQueue(StreamComponent component) {
this.inBound.add(component);
}
/**
* The components that are immediately downstream of this component (aka child nodes)
* @return Collection of child nodes of this component
*/
public Collection<StreamComponent> getDownStreamComponents() {
return this.outBound.keySet();
}
/**
* The components that are immediately upstream of this component (aka parent nodes)
* @return Collection of parent nodes of this component
*/
public Collection<StreamComponent> getUpStreamComponents() {
return this.inBound;
}
/**
* The inbound queue for this component
* @return inbound queue
*/
public BlockingQueue<StreamsDatum> getInBoundQueue() {
return this.inQueue;
}
/**
* The number of tasks this to run this component
* @return
*/
public int getNumTasks() {
return this.numTasks;
}
/**
* Creates a {@link org.apache.streams.local.tasks.StreamsTask} that is running a clone of this component whose
* inbound and outbound queues are appropriately connected to the parent and child nodes.
*
* @return StreamsTask for this component
* @param timeout The timeout to use in milliseconds for any tasks that support configurable timeout
*/
public StreamsTask createConnectedTask(int timeout) {
StreamsTask task;
if(this.processor != null) {
if(this.numTasks > 1) {
task = new StreamsProcessorTask(SerializationUtil.cloneBySerialization(this.processor), streamConfig);
task.addInputQueue(this.inQueue);
for(BlockingQueue<StreamsDatum> q : this.outBound.values()) {
task.addOutputQueue(q);
}
} else {
task = new StreamsProcessorTask(this.processor, streamConfig);
task.addInputQueue(this.inQueue);
for(BlockingQueue<StreamsDatum> q : this.outBound.values()) {
task.addOutputQueue(q);
}
}
}
else if(this.writer != null) {
if(this.numTasks > 1) {
task = new StreamsPersistWriterTask(SerializationUtil.cloneBySerialization(this.writer), streamConfig);
task.addInputQueue(this.inQueue);
} else {
task = new StreamsPersistWriterTask(this.writer, streamConfig);
task.addInputQueue(this.inQueue);
}
}
else if(this.provider != null) {
StreamsProvider prov;
if(this.numTasks > 1) {
prov = SerializationUtil.cloneBySerialization(this.provider);
} else {
prov = this.provider;
}
if(this.dateRange == null && this.sequence == null)
task = new StreamsProviderTask(prov, this.perpetual, streamConfig);
else if(this.sequence != null)
task = new StreamsProviderTask(prov, this.sequence, streamConfig);
else
task = new StreamsProviderTask(prov, this.dateRange[0], this.dateRange[1], streamConfig);
//Adjust the timeout if necessary
if(timeout != 0) {
((StreamsProviderTask)task).setTimeout(timeout);
}
for(BlockingQueue<StreamsDatum> q : this.outBound.values()) {
task.addOutputQueue(q);
}
}
else {
throw new InvalidStreamException("Underlying StreamComponoent was NULL.");
}
if(task != null) {
tasks.add(task);
}
return task;
}
public List<StreamsTask> getStreamsTasks() {
return this.tasks;
}
/**
* The unique of this component
* @return
*/
public String getId() {
return this.id;
}
@Override
public int hashCode() {
return this.id.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof StreamComponent && this.id.equals(((StreamComponent) o).id);
}
protected StreamsOperation getOperation() {
if(this.processor != null) {
return this.processor;
}
else if(this.writer != null) {
return this.writer;
}
else if(this.provider != null) {
return this.provider;
}
else {
throw new InvalidStreamException("Underlying StreamComponoent was NULL.");
}
}
@Deprecated
protected boolean isOperationCountable() {
return getOperation() instanceof DatumStatusCountable;
}
}