/*
* Copyright 2012 AppSatori s.r.o.
*
* 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 eu.appsatori.pipes;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.RetryOptions;
import com.google.appengine.api.taskqueue.TaskOptions;
/**
* Internal implementation of type running particular nodes on Google App Engine.
* @author <a href="mailto:vladimir.orany@appsatori.eu">Vladimir Orany</a>
*/
class AppEngineNodeRunner implements NodeRunner {
private PipeDatastore pipeDatastore;
AppEngineNodeRunner(PipeDatastore datastore){
if(datastore == null){
throw new NullPointerException("Pipes datastore cannot be null");
}
this.pipeDatastore = datastore;
}
AppEngineNodeRunner() {
this(new DatastorePipeDatastore());
}
public PipeDatastore getPipeDatastore() {
return pipeDatastore;
}
public <N extends Node<?, ?>> String run(PipeType type, Class<N> node, Object arg) {
String taskId = Pipes.getUniqueTaskId(node.getName());
int total = type.getParallelTasksCount(arg);
for (int i = 0; i < total; i++) {
run(taskId, type, node, arg);
}
pipeDatastore.logAllTasksStarted(taskId);
return taskId;
}
public <N extends Node<?, ?>> int run(String taskId, PipeType type, Class<N> node, Object arg) {
int index = pipeDatastore.logTaskStarted(taskId);
Queue q = getQueue(node);
startTask(q, type, node, arg, taskId, index);
return index;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void startTask(Queue q, PipeType type, Class node, Object arg, String taskId, int index) {
NodeTask nodeTask = new NodeTask(type, node, taskId, index, arg);
TaskOptions options = TaskOptions.Builder.withTaskName(index + "_" + taskId).payload(nodeTask).retryOptions(RetryOptions.Builder.withTaskRetryLimit(0));
try {
q.add(options);
} catch (IllegalStateException e){
if(!QueueFactory.getDefaultQueue().equals(q)){
startTask(QueueFactory.getDefaultQueue(), type, node, arg, taskId, index);
} else {
throw e;
}
} catch (IllegalArgumentException e){
if(e.getMessage().startsWith("Task size too large") && !(arg instanceof StashedArgument)){
startTask(q, type, node, new StashedArgument(pipeDatastore.stashArgument(arg)), taskId, index);
} else {
throw e;
}
}
}
static <N extends Node<?,?>> Queue getQueue(Class<? extends Node<?,?>> node) {
String name = Pipes.getQueueName(node);
Queue q = QueueFactory.getDefaultQueue();
if(!"".equals(name)){
q = QueueFactory.getQueue(name);
}
return q;
}
public void clearTasks(String queue, String baseTaskId, int tasksCount) {
Queue q;
if("".equals(queue) || queue == null){
q = QueueFactory.getDefaultQueue();
} else {
q = QueueFactory.getQueue(queue);
}
for (int i = 0; i < tasksCount; i++) {
String taskName = "" + i + "_" + baseTaskId;
try {
q.deleteTask(taskName);
} catch (IllegalStateException e){
QueueFactory.getDefaultQueue().deleteTask(taskName);
}
}
}
}