Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.sun.grizzly.async;
import com.sun.grizzly.Controller;
import com.sun.grizzly.SelectorHandler;
import com.sun.grizzly.async.AsyncQueue.AsyncQueueEntry;
import com.sun.grizzly.util.ByteBufferFactory;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.WritableByteChannel;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
/**
*
* @author oleksiys
*/
public abstract class AbstractAsyncQueueWriter implements AsyncQueueWriter {
private SelectorHandler selectorHandler;
private AsyncQueue writeQueue;
private ConcurrentLinkedQueue recordQueue;
public AbstractAsyncQueueWriter(SelectorHandler selectorHandler) {
this.selectorHandler = selectorHandler;
writeQueue = new AsyncQueue();
recordQueue = new ConcurrentLinkedQueue();
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, ByteBuffer buffer) throws IOException {
write(key, null, buffer, null);
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, ByteBuffer buffer,
AsyncWriteCallbackHandler callbackHandler) throws IOException {
write(key, null, buffer, callbackHandler, null);
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, ByteBuffer buffer,
AsyncWriteCallbackHandler callbackHandler,
AsyncQueueDataProcessor writePreProcessor) throws IOException {
write(key, null, buffer, callbackHandler, writePreProcessor, false);
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, ByteBuffer buffer,
AsyncWriteCallbackHandler callbackHandler,
AsyncQueueDataProcessor writePreProcessor, boolean isCloneByteBuffer)
throws IOException {
write(key, null, buffer, callbackHandler, writePreProcessor, isCloneByteBuffer);
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, SocketAddress dstAddress,
ByteBuffer buffer) throws IOException {
write(key, dstAddress, buffer, null);
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, SocketAddress dstAddress,
ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler)
throws IOException {
write(key, dstAddress, buffer, callbackHandler, null);
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, SocketAddress dstAddress,
ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler,
AsyncQueueDataProcessor writePreProcessor) throws IOException {
write(key, dstAddress, buffer, callbackHandler, writePreProcessor, false);
}
/**
* {@inheritDoc}
*/
public void write(SelectionKey key, SocketAddress dstAddress,
ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler,
AsyncQueueDataProcessor writePreProcessor, boolean isCloneByteBuffer)
throws IOException {
if (key == null) {
throw new IOException("SelectionKey is null! " +
"Probably key was cancelled or connection was closed?");
}
SelectableChannel channel = key.channel();
AsyncQueueEntry channelEntry =
writeQueue.obtainAsyncQueueEntry(channel);
ConcurrentLinkedQueue queue = channelEntry.queue;
AtomicReference currentElement = channelEntry.currentElement;
ReentrantLock lock = channelEntry.queuedActionLock;
// If AsyncQueue is empty - try to write ByteBuffer here
try {
AsyncWriteQueueRecord record = null;
if (currentElement.get() == null && // Weak comparison for null
lock.tryLock()) {
record = obtainRecord();
// Strong comparison for null, because we're in locked region
if (currentElement.compareAndSet(null, record)) {
doWrite((WritableByteChannel) channel, dstAddress, buffer,
writePreProcessor);
} else {
lock.unlock();
}
}
if (buffer.hasRemaining() ||
(lock.isHeldByCurrentThread() && writePreProcessor != null &&
writePreProcessor.getInternalByteBuffer().hasRemaining())) {
if (record == null) {
record = obtainRecord();
}
// clone ByteBuffer if required
if (isCloneByteBuffer) {
int size = buffer.remaining();
ByteBuffer newBuffer = ByteBufferFactory.allocateView(
size, buffer.isDirect());
newBuffer.put(buffer);
newBuffer.position(0);
buffer = newBuffer;
}
record.set(buffer, callbackHandler, writePreProcessor, dstAddress);
boolean isRegisterForWriting = false;
// add new element to the queue, if it's not current
if (currentElement.get() != record) {
queue.offer(record); // add to queue
if (!lock.isLocked()) {
isRegisterForWriting = true;
}
} else { // if element was written direct (not fully written)
isRegisterForWriting = true;
lock.unlock();
}
if (isRegisterForWriting) {
registerForWriting(key);
}
} else { // If there are no bytes available for writing
// Notify callback handler
if (callbackHandler != null) {
callbackHandler.onWriteCompleted(key, buffer);
}
// If buffer was written directly - set next queue element as current
if (lock.isHeldByCurrentThread()) {
AsyncWriteQueueRecord nextRecord = queue.poll();
if (nextRecord != null) { // if there is something in queue
currentElement.set(nextRecord);
lock.unlock();
registerForWriting(key);
} else { // if nothing in queue
currentElement.set(null);
lock.unlock(); // unlock
if (queue.peek() != null) { // check one more time
registerForWriting(key);
}
}
}
// Release record element
if (record != null) {
recordQueue.offer(record);
}
}
} catch(IOException e) {
onClose(channel);
throw e;
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
/**
* {@inheritDoc}
*/
public boolean hasReadyAsyncWriteData(SelectionKey key) {
AsyncQueueEntry channelEntry =
writeQueue.getAsyncQueueEntry(key.channel());
return channelEntry != null && (channelEntry.currentElement.get() != null ||
(channelEntry.queue != null && !channelEntry.queue.isEmpty()));
}
/**
* {@inheritDoc}
*/
public void onWrite(SelectionKey key) throws IOException {
SelectableChannel channel = key.channel();
AsyncQueueEntry channelEntry =
writeQueue.obtainAsyncQueueEntry(channel);
ConcurrentLinkedQueue queue = channelEntry.queue;
AtomicReference currentElement = channelEntry.currentElement;
ReentrantLock lock = channelEntry.queuedActionLock;
if (currentElement.get() == null) {
AsyncWriteQueueRecord nextRecord = queue.peek();
if (nextRecord != null && lock.tryLock()) {
if (!queue.isEmpty() &&
currentElement.compareAndSet(null, nextRecord)) {
queue.remove();
}
} else {
return;
}
} else if (!lock.tryLock()) {
return;
}
try {
while (currentElement.get() != null) {
AsyncWriteQueueRecord queueRecord = currentElement.get();
ByteBuffer byteBuffer = queueRecord.byteBuffer;
AsyncQueueDataProcessor writePreProcessor = queueRecord.writePreProcessor;
try {
doWrite((WritableByteChannel) channel,
queueRecord.dstAddress, byteBuffer, writePreProcessor);
} catch (IOException e) {
if (queueRecord.callbackHandler != null) {
queueRecord.callbackHandler.onIOException(e, key,
byteBuffer, queue);
} else {
Controller.logger().log(Level.SEVERE,
"Exception occured when executing " +
"asynchronous queue writing", e);
}
onClose(channel);
}
// check if buffer was completely written
if (!byteBuffer.hasRemaining() &&
(writePreProcessor == null ||
!writePreProcessor.getInternalByteBuffer().hasRemaining())) {
if (queueRecord.callbackHandler != null) {
queueRecord.callbackHandler.onWriteCompleted(key, byteBuffer);
}
currentElement.set(queue.poll());
recordQueue.offer(queueRecord);
// If last element in queue is null - we have to be careful
if (currentElement.get() == null) {
lock.unlock();
AsyncWriteQueueRecord nextRecord = queue.peek();
if (nextRecord != null && lock.tryLock()) {
if (!queue.isEmpty() &&
currentElement.compareAndSet(null, nextRecord)) {
queue.remove();
}
continue;
} else {
break;
}
}
} else { // if there is still some data in current buffer
lock.unlock();
registerForWriting(key);
break;
}
}
} finally {
if (lock.isHeldByCurrentThread()) {
channelEntry.queuedActionLock.unlock();
}
}
}
/**
* {@inheritDoc}
*/
public void onClose(SelectableChannel channel) {
writeQueue.removeEntry(channel);
}
/**
* {@inheritDoc}
*/
public void close() {
writeQueue.clear();
}
protected void doWrite(WritableByteChannel channel, SocketAddress dstAddress,
ByteBuffer byteBuffer, AsyncQueueDataProcessor writePreProcessor)
throws IOException {
if (writePreProcessor != null) {
ByteBuffer resultByteBuffer = null;
do {
if (byteBuffer.hasRemaining()) {
writePreProcessor.process(byteBuffer);
}
resultByteBuffer = writePreProcessor.getInternalByteBuffer();
doWrite(channel, dstAddress, resultByteBuffer);
} while(byteBuffer.hasRemaining() &&
!resultByteBuffer.hasRemaining());
} else {
doWrite(channel, dstAddress, byteBuffer);
}
}
protected abstract void doWrite(WritableByteChannel channel, SocketAddress dstAddress,
ByteBuffer byteBuffer) throws IOException;
protected void registerForWriting(SelectionKey key) {
selectorHandler.register(key, SelectionKey.OP_WRITE);
}
private AsyncWriteQueueRecord obtainRecord() {
AsyncWriteQueueRecord record = recordQueue.poll();
if (record == null) {
record = new AsyncWriteQueueRecord();
}
return record;
}
}