/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wps; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.process.ProcessException; import org.geotools.process.ProcessFactory; import org.geotools.process.factory.AnnotatedBeanProcessFactory; import org.geotools.process.factory.DescribeParameter; import org.geotools.process.factory.DescribeProcess; import org.geotools.process.factory.DescribeResult; import org.geotools.util.SimpleInternationalString; import org.opengis.util.ProgressListener; @DescribeProcess(title = "Monkey", description = "Process used to test asynch calls") public class MonkeyProcess { enum CommandType { Exit, SetProgress, Exception, Wait } static Map<String, BlockingQueue<Command>> commands = new ConcurrentHashMap<String, BlockingQueue<MonkeyProcess.Command>>(); private static class Command { CommandType type; Object value; public Command(CommandType type, Object value) { this.type = type; this.value = value; } } public static void exit(String id, SimpleFeatureCollection value, boolean wait) throws InterruptedException { getCommandQueue(id).put(new Command(CommandType.Exit, value)); if (wait) { while (getCommandQueue(id).size() > 0) { Thread.sleep(10); } } } private synchronized static BlockingQueue<Command> getCommandQueue(String id) { BlockingQueue<Command> queue = commands.get(id); if (queue == null) { queue = new LinkedBlockingQueue<MonkeyProcess.Command>(); commands.put(id, queue); } return queue; } public static void progress(String id, float progress, boolean wait) throws InterruptedException { getCommandQueue(id).put(new Command(CommandType.SetProgress, progress)); if (wait) { while (getCommandQueue(id).size() > 0) { Thread.sleep(10); } } } public static void wait(String id, long wait) throws InterruptedException { getCommandQueue(id).put(new Command(CommandType.Wait, wait)); } public static void exception(String id, ProcessException exception, boolean wait) throws InterruptedException { getCommandQueue(id).put(new Command(CommandType.Exception, exception)); if (wait) { while (getCommandQueue(id).size() > 0) { Thread.sleep(10); } } } @DescribeResult(name = "result") public SimpleFeatureCollection execute(@DescribeParameter(name = "id") String id, @DescribeParameter(name = "fc", min = 0) SimpleFeatureCollection fc, @DescribeParameter(name = "extra", min = 0) String extra, ProgressListener listener) throws Exception { BlockingQueue<Command> queue = getCommandQueue(id); while (true) { Command command = queue.take(); if (command.type == CommandType.Exit) { listener.progress(100f); listener.complete(); commands.remove(id); return (SimpleFeatureCollection) command.value; } else if (command.type == CommandType.SetProgress) { float progress = ((Number) command.value).floatValue(); listener.progress(progress); listener.setTask(new SimpleInternationalString("Currently at " + progress)); } else if (command.type == CommandType.Wait) { long wait = ((Number) command.value).longValue(); Thread.sleep(wait); } else { ProcessException exception = (ProcessException) command.value; listener.exceptionOccurred(exception); throw exception; } } } public static final ProcessFactory getFactory() { return new MonkeyProcessFactory(); } public static void clearCommands() { for (Map.Entry<String, BlockingQueue<MonkeyProcess.Command>> entry : commands.entrySet()) { if (entry.getValue().size() > 0) { throw new IllegalStateException("The command queue is not clean, queue " + entry.getKey() + " still has commands in: " + entry.getValue()); } } commands.clear(); } private static class MonkeyProcessFactory extends AnnotatedBeanProcessFactory { public MonkeyProcessFactory() { super(new SimpleInternationalString("Monkey process"), "gs", MonkeyProcess.class); } } }