
org.kaleidofoundry.messaging.AbstractProducer Maven / Gradle / Ivy
/*
* Copyright 2008-2021 the original author or authors
*
* 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 org.kaleidofoundry.messaging;
import static org.kaleidofoundry.messaging.ClientContextBuilder.DEBUG_PROPERTY;
import static org.kaleidofoundry.messaging.ClientContextBuilder.THREAD_POOL_COUNT_PROPERTY;
import static org.kaleidofoundry.messaging.ClientContextBuilder.TRANSPORT_REF;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.kaleidofoundry.core.context.EmptyContextParameterException;
import org.kaleidofoundry.core.context.RuntimeContext;
import org.kaleidofoundry.core.lang.annotation.Task;
import org.kaleidofoundry.core.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author jraduget
*/
public abstract class AbstractProducer implements Producer {
/** Default Logger */
protected static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
// message counters
protected final AtomicInteger ProcessedMessagesOK = new AtomicInteger(0);
protected final AtomicInteger ProcessedMessagesKO = new AtomicInteger(0);
protected final AtomicInteger ProcessedMessagesSKIPPED = new AtomicInteger(0);
/** I18n messaging bundle */
protected final RuntimeContext context;
protected final Transport transport;
/** Executor service used to implements timeout feature when sending message */
@Task(comment = "Lazy creation of the executor service for google application engine, use com.google.appengine.api.taskqueue.Queue ?")
protected final ExecutorService pool;
public AbstractProducer(RuntimeContext context) {
this.context = context;
// transport
String transportRef = this.context.getString(TRANSPORT_REF);
if (!StringHelper.isEmpty(transportRef)) {
this.transport = TransportFactory.provides(transportRef, context);
this.transport.getProducers().put(getName(), this);
} else {
throw new EmptyContextParameterException(TRANSPORT_REF, context);
}
// thread executor service
int threadCount = this.context.getInteger(THREAD_POOL_COUNT_PROPERTY, 1);
LOGGER.info("Creating producer [{}] with a thread pool size of {}", context.getName(), threadCount);
this.pool = Executors.newFixedThreadPool(threadCount);
}
@Override
public void send(final Message message, final long timeout) throws MessagingException {
if (timeout <= 0) {
send(message);
}
FutureTask future = new FutureTask(new Callable() {
public Throwable call() {
try {
send(message);
return null;
} catch (Throwable th) {
return th;
}
}
});
pool.execute(future);
try {
Throwable error = future.get(timeout, TimeUnit.MILLISECONDS);
if (error != null) {
if (error instanceof MessagingException) {
throw (MessagingException) error;
} else {
throw new IllegalStateException("Internal producer error", error);
}
}
} catch (TimeoutException ex) {
throw MessageTimeoutException.buildProducerTimeoutException(getName());
} catch (ExecutionException eex) {
throw new IllegalStateException("Executor service error", eex);
} catch (InterruptedException iex) {
throw new IllegalStateException("Thread have been interrupted", iex);
}
}
@Override
public void send(final Collection messages, final long timeout) throws MessagingException {
if (timeout <= 0) {
send(messages);
}
FutureTask future = new FutureTask(new Callable() {
public Throwable call() {
try {
send(messages);
return null;
} catch (Throwable th) {
return th;
}
}
});
pool.execute(future);
try {
Throwable error = future.get(timeout, TimeUnit.MILLISECONDS);
if (error != null) {
if (error instanceof MessagingException) {
throw (MessagingException) error;
} else {
throw new IllegalStateException("Internal producer error", error);
}
}
} catch (TimeoutException ex) {
throw MessageTimeoutException.buildProducerTimeoutException(getName());
} catch (ExecutionException eex) {
throw new IllegalStateException("Executor service error", eex);
} catch (InterruptedException iex) {
throw new IllegalStateException("Thread have been interrupted", iex);
}
}
/*
* (non-Javadoc)
* @see org.kaleidofoundry.messaging.Client#getTransport()
*/
@Override
public Transport getTransport() throws TransportException {
return transport;
}
/*
* (non-Javadoc)
* @see org.kaleidofoundry.messaging.Producer#getName()
*/
@Override
public String getName() {
return context.getName();
}
@Override
public void stop() throws TransportException {
pool.shutdown();
this.transport.getProducers().remove(getName());
}
/*
* (non-Javadoc)
* @see org.kaleidofoundry.messaging.Client#getStatistics()
*/
@Override
public UsageStatistics getStatistics() {
return new UsageStatistics(ProcessedMessagesOK.get(), ProcessedMessagesKO.get(), 0);
}
protected boolean isDebug() {
return context.getBoolean(DEBUG_PROPERTY, false) || LOGGER.isDebugEnabled();
}
protected void debugMessage(Message message) {
if (isDebug()) {
LOGGER.info(">>> sending message with providerId={} , correlationId={} , parameters={}",
new Object[] { message.getProviderId(), message.getCorrelationId(), String.valueOf(message.getParameters()) });
LOGGER.info("{}", message.toString());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy