Java tutorial
/* * Copyright 2017 ZhangJiupeng * * 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 cc.gospy.core.remote.rabbitmq; import cc.gospy.core.TaskFilter; import cc.gospy.core.entity.Task; import cc.gospy.core.scheduler.queue.LazyTaskQueue; import cc.gospy.core.scheduler.queue.impl.TimingLazyTaskQueue; import cc.gospy.core.scheduler.remover.DuplicateRemover; import cc.gospy.core.scheduler.remover.impl.HashDuplicateRemover; import com.rabbitmq.client.*; import org.apache.commons.lang3.SerializationUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; import static cc.gospy.core.remote.rabbitmq.TaskQueue.*; public class RemoteServiceProvider { private static final Logger logger = LoggerFactory.getLogger(RemoteServiceProvider.class); private ConnectionFactory factory; private Connection connection; private Channel channel; private String[] specialQueues; private TaskDispatcher dispatcher; private LazyTaskQueue lazyTaskQueue; private DuplicateRemover duplicateRemover; private TaskFilter taskFilter; private Map arguments; private boolean withPriority; private RemoteServiceProvider(DuplicateRemover remover, TaskFilter taskFilter, TaskDispatcher dispatcher, String host, int port, String virtualHost, String username, String password, int ttlInSeconds, boolean withPriority, String... specialQueues) { this.lazyTaskQueue = new TimingLazyTaskQueue(wakedTask -> { try { this.publish(wakedTask); } catch (IOException e) { e.printStackTrace(); } }); this.duplicateRemover = remover; this.taskFilter = taskFilter; this.dispatcher = dispatcher; this.factory = new ConnectionFactory(); this.factory.setHost(host); this.factory.setPort(port); this.factory.setVirtualHost(virtualHost); this.factory.setUsername(username); this.factory.setPassword(password); this.specialQueues = specialQueues; this.withPriority = withPriority; this.arguments = new HashMap() { { if (ttlInSeconds != -1) { put("x-message-ttl", ttlInSeconds / 1000); logger.info("Picked up x-message-ttl: {}", ttlInSeconds / 1000); } if (withPriority) { put("x-max-priority", 255); logger.info("Picked up x-max-priority: 255"); } } }; } public static RemoteServiceProvider getDefault() { return new RemoteServiceProvider(new HashDuplicateRemover(), TaskFilter.ALLOW_ALL, TaskDispatcher.DEFAULT, "localhost", -1, "/", "guest", "guest", -1, false); } public static Builder custom() { return new Builder(); } public void start() { try { this.init(factory); this.declareBase(); this.declareSpecialQueues(specialQueues); this.declareNewTaskConsumer(); logger.info("Remote provider has successfully started at {}:{}", factory.getHost(), factory.getPort()); } catch (IOException | TimeoutException e) { e.printStackTrace(); } } private void init(ConnectionFactory factory) throws IOException, TimeoutException { connection = factory.newConnection(); channel = connection.createChannel(); } private void declareBase() throws IOException { channel.exchangeDeclare(EXCHANGE, "direct"); // task queue exchanger channel.queueDeclare(DEFAULT, true, false, false, getArgumentsOrNull()); // default task queue channel.queueBind(DEFAULT, EXCHANGE, DEFAULT); // bind queue to exchanger channel.queueDeclare(NEW_TASK_QUEUE, true, false, false, null); // feedback queue channel.queueDeclare(NEW_LAZY_TASK_QUEUE, true, false, false, null); // feedback queue } private void declareSpecialQueues(String... specialQueues) throws IOException { for (String queueName : specialQueues) { channel.queueDeclare(queueName, true, false, false, getArgumentsOrNull()); channel.queueBind(queueName, EXCHANGE, queueName); } } private void declareNewTaskConsumer() throws IOException { channel.basicConsume(NEW_TASK_QUEUE, true, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { Task newTask = (Task) SerializationUtils.deserialize(body); if (newTask.isCheckSkipping() || taskFilter.test(newTask)) { if (duplicateRemover.exists(newTask)) { duplicateRemover.record(newTask); } else { if (newTask.getExpectedVisitInSeconds() == 0) { publish(newTask); } else { lazyTaskQueue.add(newTask); } } } } }); channel.basicConsume(NEW_LAZY_TASK_QUEUE, true, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { Task newTask = (Task) SerializationUtils.deserialize(body); if (newTask.isCheckSkipping() || taskFilter.test(newTask)) { lazyTaskQueue.add(newTask); } } }); } private Map getArgumentsOrNull() { return arguments.size() > 0 ? arguments : null; } private void publish(Task task) throws IOException { AMQP.BasicProperties properties = !withPriority ? MessageProperties.PERSISTENT_BASIC : new AMQP.BasicProperties.Builder().contentType("application/octet-stream").deliveryMode(2) .priority((int) task.getPriority()).build(); channel.basicPublish(EXCHANGE, dispatcher.getTargetQueue(task), properties, SerializationUtils.serialize(task)); duplicateRemover.record(task); } public static class Builder { private DuplicateRemover remover = new HashDuplicateRemover(); private TaskFilter filter = TaskFilter.ALLOW_ALL; private TaskDispatcher dispatcher = task -> DEFAULT; private String host = "localhost"; private int port = -1; private String virtualHost = "/"; private String username = "guest"; private String password = "guest"; private int ttlInSeconds = -1; private boolean withPriority; private String[] specialQueues = {}; public Builder setRemover(DuplicateRemover remover) { this.remover = remover; return this; } public Builder setTaskFilter(TaskFilter filter) { this.filter = filter; return this; } public Builder setDispatcher(TaskDispatcher dispatcher) { this.dispatcher = dispatcher; return this; } public Builder setHost(String host) { this.host = host; return this; } public Builder setPort(int port) { this.port = port; return this; } public Builder setVirtualHost(String virtualHost) { this.virtualHost = virtualHost; return this; } public Builder setUsername(String username) { this.username = username; return this; } public Builder setPassword(String password) { this.password = password; return this; } public Builder setSpecialQueues(String[] specialQueues) { this.specialQueues = specialQueues; return this; } public Builder setTimeToLive(int ttlInSeconds) { this.ttlInSeconds = ttlInSeconds; return this; } public Builder withPriority() { this.withPriority = true; return this; } public RemoteServiceProvider build() { return new RemoteServiceProvider(remover, filter, dispatcher, host, port, virtualHost, username, password, ttlInSeconds, withPriority, specialQueues); } } }