/**
* Copyright 2014 Ricardo Padilha
*
* 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 net.dsys.snio.impl.handler;
import static net.dsys.snio.impl.handler.ExecutionType.DECOUPLED;
import static net.dsys.snio.impl.handler.ExecutionType.ZERO_COPY;
import java.util.concurrent.atomic.AtomicBoolean;
import net.dsys.commons.api.exception.Bug;
import net.dsys.commons.api.lang.Cleaner;
import net.dsys.commons.api.lang.Copier;
import net.dsys.commons.api.lang.Interruptible;
import net.dsys.snio.api.buffer.InterruptedByClose;
import net.dsys.snio.api.buffer.MessageBufferProducer;
import net.dsys.snio.api.handler.MessageProducer;
/**
* This implementation copies the information produced locally before acquiring
* a new position in the output buffer. This allows a measure of decoupling. The
* down-side is that it requires an additional copy of the data.
*
* @author Ricardo Padilha
*/
final class ProducerThread<T> implements Interruptible {
private final ExecutionType type;
private final MessageBufferProducer<T> out;
private final MessageProducer<T> producer;
private final T holder;
private final Copier<T> copier;
private final Cleaner<T> cleaner;
private final AtomicBoolean interrupted;
ProducerThread(final MessageBufferProducer<T> out, final MessageProducer<T> producer, final T holder,
final Copier<T> copier, final Cleaner<T> cleaner) {
if (out == null) {
throw new NullPointerException("in == null");
}
if (producer == null) {
throw new NullPointerException("producer == null");
}
if (holder == null) {
throw new NullPointerException("holder == null");
}
if (copier == null) {
throw new NullPointerException("copier == null");
}
if (cleaner == null) {
throw new NullPointerException("cleaner == null");
}
this.type = DECOUPLED;
this.out = out;
this.producer = producer;
this.holder = holder;
this.copier = copier;
this.cleaner = cleaner;
this.interrupted = new AtomicBoolean();
}
ProducerThread(final MessageBufferProducer<T> out, final MessageProducer<T> producer) {
if (out == null) {
throw new NullPointerException("in == null");
}
if (producer == null) {
throw new NullPointerException("producer == null");
}
this.type = ZERO_COPY;
this.out = out;
this.producer = producer;
this.holder = null;
this.copier = null;
this.cleaner = null;
this.interrupted = new AtomicBoolean();
}
/**
* {@inheritDoc}
*/
@Override
public void interrupt() {
interrupted.lazySet(true);
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
switch (type) {
case DECOUPLED: {
runDecoupled();
break;
}
case ZERO_COPY: {
runZeroCopy();
break;
}
default: {
throw new Bug("Unsuppported ThreadType: " + type);
}
}
}
private void runDecoupled() {
final T holder = this.holder;
Object attachment;
while (!Thread.interrupted() && !interrupted.get()) {
try {
cleaner.clear(holder);
attachment = producer.produce(holder);
final long sequence = out.acquire();
try {
final T value = out.get(sequence);
copier.copy(holder, value);
out.attach(sequence, attachment);
} finally {
out.release(sequence);
}
} catch (final InterruptedByClose e) {
return;
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
return;
} catch (final Throwable t) {
System.err.println("Uncaught MessageHandler exception: " + t.getLocalizedMessage());
t.printStackTrace();
}
}
}
private void runZeroCopy() {
while (!Thread.interrupted() && !interrupted.get()) {
try {
final long sequence = out.acquire();
try {
final T value = out.get(sequence);
final Object attachment = producer.produce(value);
out.attach(sequence, attachment);
} finally {
out.release(sequence);
}
} catch (final InterruptedByClose e) {
return;
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
return;
} catch (final Throwable t) {
System.err.println("Uncaught MessageHandler exception: " + t.getLocalizedMessage());
t.printStackTrace();
}
}
}
}