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.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.mina.core.session;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.file.DefaultFileRegion;
import org.apache.mina.core.file.FilenameFileRegion;
import org.apache.mina.core.filterchain.IoFilterChain;
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.DefaultCloseFuture;
import org.apache.mina.core.future.DefaultReadFuture;
import org.apache.mina.core.future.DefaultWriteFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.future.ReadFuture;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.service.AbstractIoService;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.service.IoProcessor;
import org.apache.mina.core.service.IoService;
import org.apache.mina.core.service.TransportMetadata;
import org.apache.mina.core.write.DefaultWriteRequest;
import org.apache.mina.core.write.WriteException;
import org.apache.mina.core.write.WriteRequest;
import org.apache.mina.core.write.WriteRequestQueue;
import org.apache.mina.core.write.WriteTimeoutException;
import org.apache.mina.core.write.WriteToClosedSessionException;
import org.apache.mina.util.ExceptionMonitor;
/**
* Base implementation of {@link IoSession}.
*
* @author Apache MINA Project
*/
public abstract class AbstractIoSession implements IoSession {
/** The associated handler */
private final IoHandler handler;
/** The session config */
protected IoSessionConfig config;
/** The service which will manage this session */
private final IoService service;
private static final AttributeKey READY_READ_FUTURES_KEY = new AttributeKey(AbstractIoSession.class,
"readyReadFutures");
private static final AttributeKey WAITING_READ_FUTURES_KEY = new AttributeKey(AbstractIoSession.class,
"waitingReadFutures");
private static final IoFutureListener SCHEDULED_COUNTER_RESETTER = new IoFutureListener() {
public void operationComplete(CloseFuture future) {
AbstractIoSession session = (AbstractIoSession) future.getSession();
session.scheduledWriteBytes.set(0);
session.scheduledWriteMessages.set(0);
session.readBytesThroughput = 0;
session.readMessagesThroughput = 0;
session.writtenBytesThroughput = 0;
session.writtenMessagesThroughput = 0;
}
};
/**
* An internal write request object that triggers session close.
*/
public static final WriteRequest CLOSE_REQUEST = new DefaultWriteRequest(new Object());
/**
* An internal write request object that triggers message sent events.
*/
public static final WriteRequest MESSAGE_SENT_REQUEST = new DefaultWriteRequest(DefaultWriteRequest.EMPTY_MESSAGE);
private final Object lock = new Object();
private IoSessionAttributeMap attributes;
private WriteRequestQueue writeRequestQueue;
private WriteRequest currentWriteRequest;
/** The Session creation's time */
private final long creationTime;
/** An id generator guaranteed to generate unique IDs for the session */
private static AtomicLong idGenerator = new AtomicLong(0);
/** The session ID */
private long sessionId;
/**
* A future that will be set 'closed' when the connection is closed.
*/
private final CloseFuture closeFuture = new DefaultCloseFuture(this);
private volatile boolean closing;
// traffic control
private boolean readSuspended = false;
private boolean writeSuspended = false;
// Status variables
private final AtomicBoolean scheduledForFlush = new AtomicBoolean();
private final AtomicInteger scheduledWriteBytes = new AtomicInteger();
private final AtomicInteger scheduledWriteMessages = new AtomicInteger();
private long readBytes;
private long writtenBytes;
private long readMessages;
private long writtenMessages;
private long lastReadTime;
private long lastWriteTime;
private long lastThroughputCalculationTime;
private long lastReadBytes;
private long lastWrittenBytes;
private long lastReadMessages;
private long lastWrittenMessages;
private double readBytesThroughput;
private double writtenBytesThroughput;
private double readMessagesThroughput;
private double writtenMessagesThroughput;
private AtomicInteger idleCountForBoth = new AtomicInteger();
private AtomicInteger idleCountForRead = new AtomicInteger();
private AtomicInteger idleCountForWrite = new AtomicInteger();
private long lastIdleTimeForBoth;
private long lastIdleTimeForRead;
private long lastIdleTimeForWrite;
private boolean deferDecreaseReadBuffer = true;
/**
* Create a Session for a service
*
* @param service the Service for this session
*/
protected AbstractIoSession(IoService service) {
this.service = service;
this.handler = service.getHandler();
// Initialize all the Session counters to the current time
long currentTime = System.currentTimeMillis();
creationTime = currentTime;
lastThroughputCalculationTime = currentTime;
lastReadTime = currentTime;
lastWriteTime = currentTime;
lastIdleTimeForBoth = currentTime;
lastIdleTimeForRead = currentTime;
lastIdleTimeForWrite = currentTime;
// TODO add documentation
closeFuture.addListener(SCHEDULED_COUNTER_RESETTER);
// Set a new ID for this session
sessionId = idGenerator.incrementAndGet();
}
/**
* {@inheritDoc}
*
* We use an AtomicLong to guarantee that the session ID are unique.
*/
public final long getId() {
return sessionId;
}
/**
* @return The associated IoProcessor for this session
*/
public abstract IoProcessor getProcessor();
/**
* {@inheritDoc}
*/
public final boolean isConnected() {
return !closeFuture.isClosed();
}
/**
* {@inheritDoc}
*/
public boolean isActive() {
// Return true by default
return true;
}
/**
* {@inheritDoc}
*/
public final boolean isClosing() {
return closing || closeFuture.isClosed();
}
/**
* {@inheritDoc}
*/
public boolean isSecured() {
// Always false...
return false;
}
/**
* {@inheritDoc}
*/
public final CloseFuture getCloseFuture() {
return closeFuture;
}
/**
* Tells if the session is scheduled for flushed
*
* @return true if the session is scheduled for flush
*/
public final boolean isScheduledForFlush() {
return scheduledForFlush.get();
}
/**
* Schedule the session for flushed
*/
public final void scheduledForFlush() {
scheduledForFlush.set(true);
}
/**
* Change the session's status : it's not anymore scheduled for flush
*/
public final void unscheduledForFlush() {
scheduledForFlush.set(false);
}
/**
* Set the scheduledForFLush flag. As we may have concurrent access to this
* flag, we compare and set it in one call.
*
* @param schedule
* the new value to set if not already set.
* @return true if the session flag has been set, and if it wasn't set
* already.
*/
public final boolean setScheduledForFlush(boolean schedule) {
if (schedule) {
// If the current tag is set to false, switch it to true,
// otherwise, we do nothing but return false : the session
// is already scheduled for flush
return scheduledForFlush.compareAndSet(false, schedule);
}
scheduledForFlush.set(schedule);
return true;
}
/**
* {@inheritDoc}
*/
public final CloseFuture close(boolean rightNow) {
if (rightNow) {
return closeNow();
} else {
return closeOnFlush();
}
}
/**
* {@inheritDoc}
*/
public final CloseFuture close() {
return closeNow();
}
/**
* {@inheritDoc}
*/
public final CloseFuture closeOnFlush() {
if (!isClosing()) {
getWriteRequestQueue().offer(this, CLOSE_REQUEST);
getProcessor().flush(this);
}
return closeFuture;
}
/**
* {@inheritDoc}
*/
public final CloseFuture closeNow() {
synchronized (lock) {
if (isClosing()) {
return closeFuture;
}
closing = true;
try {
destroy();
} catch (Exception e) {
IoFilterChain filterChain = getFilterChain();
filterChain.fireExceptionCaught(e);
}
}
getFilterChain().fireFilterClose();
return closeFuture;
}
/**
* Destroy the session
*/
protected void destroy() {
if (writeRequestQueue != null) {
while (!writeRequestQueue.isEmpty(this)) {
WriteRequest writeRequest = writeRequestQueue.poll(this);
if (writeRequest != null) {
WriteFuture writeFuture = writeRequest.getFuture();
// The WriteRequest may not always have a future : The CLOSE_REQUEST
// and MESSAGE_SENT_REQUEST don't.
if (writeFuture != null) {
writeFuture.setWritten();
}
}
}
}
}
/**
* {@inheritDoc}
*/
public IoHandler getHandler() {
return handler;
}
/**
* {@inheritDoc}
*/
public IoSessionConfig getConfig() {
return config;
}
/**
* {@inheritDoc}
*/
public final ReadFuture read() {
if (!getConfig().isUseReadOperation()) {
throw new IllegalStateException("useReadOperation is not enabled.");
}
Queue readyReadFutures = getReadyReadFutures();
ReadFuture future;
synchronized (readyReadFutures) {
future = readyReadFutures.poll();
if (future != null) {
if (future.isClosed()) {
// Let other readers get notified.
readyReadFutures.offer(future);
}
} else {
future = new DefaultReadFuture(this);
getWaitingReadFutures().offer(future);
}
}
return future;
}
/**
* Associates a message to a ReadFuture
*
* @param message the message to associate to the ReadFuture
*
*/
public final void offerReadFuture(Object message) {
newReadFuture().setRead(message);
}
/**
* Associates a failure to a ReadFuture
*
* @param exception the exception to associate to the ReadFuture
*/
public final void offerFailedReadFuture(Throwable exception) {
newReadFuture().setException(exception);
}
/**
* Inform the ReadFuture that the session has been closed
*/
public final void offerClosedReadFuture() {
Queue readyReadFutures = getReadyReadFutures();
synchronized (readyReadFutures) {
newReadFuture().setClosed();
}
}
/**
* @return a readFuture get from the waiting ReadFuture
*/
private ReadFuture newReadFuture() {
Queue readyReadFutures = getReadyReadFutures();
Queue waitingReadFutures = getWaitingReadFutures();
ReadFuture future;
synchronized (readyReadFutures) {
future = waitingReadFutures.poll();
if (future == null) {
future = new DefaultReadFuture(this);
readyReadFutures.offer(future);
}
}
return future;
}
/**
* @return a queue of ReadFuture
*/
private Queue getReadyReadFutures() {
Queue readyReadFutures = (Queue) getAttribute(READY_READ_FUTURES_KEY);
if (readyReadFutures == null) {
readyReadFutures = new ConcurrentLinkedQueue<>();
Queue oldReadyReadFutures = (Queue) setAttributeIfAbsent(READY_READ_FUTURES_KEY,
readyReadFutures);
if (oldReadyReadFutures != null) {
readyReadFutures = oldReadyReadFutures;
}
}
return readyReadFutures;
}
/**
* @return the queue of waiting ReadFuture
*/
private Queue getWaitingReadFutures() {
Queue waitingReadyReadFutures = (Queue) getAttribute(WAITING_READ_FUTURES_KEY);
if (waitingReadyReadFutures == null) {
waitingReadyReadFutures = new ConcurrentLinkedQueue<>();
Queue oldWaitingReadyReadFutures = (Queue) setAttributeIfAbsent(
WAITING_READ_FUTURES_KEY, waitingReadyReadFutures);
if (oldWaitingReadyReadFutures != null) {
waitingReadyReadFutures = oldWaitingReadyReadFutures;
}
}
return waitingReadyReadFutures;
}
/**
* {@inheritDoc}
*/
public WriteFuture write(Object message) {
return write(message, null);
}
/**
* {@inheritDoc}
*/
public WriteFuture write(Object message, SocketAddress remoteAddress) {
if (message == null) {
throw new IllegalArgumentException("Trying to write a null message : not allowed");
}
// We can't send a message to a connected session if we don't have
// the remote address
if (!getTransportMetadata().isConnectionless() && (remoteAddress != null)) {
throw new UnsupportedOperationException();
}
// If the session has been closed or is closing, we can't either
// send a message to the remote side. We generate a future
// containing an exception.
if (isClosing() || !isConnected()) {
WriteFuture future = new DefaultWriteFuture(this);
WriteRequest request = new DefaultWriteRequest(message, future, remoteAddress);
WriteException writeException = new WriteToClosedSessionException(request);
future.setException(writeException);
return future;
}
FileChannel openedFileChannel = null;
// TODO: remove this code as soon as we use InputStream
// instead of Object for the message.
try {
if ((message instanceof IoBuffer) && !((IoBuffer) message).hasRemaining()) {
// Nothing to write : probably an error in the user code
throw new IllegalArgumentException("message is empty. Forgot to call flip()?");
} else if (message instanceof FileChannel) {
FileChannel fileChannel = (FileChannel) message;
message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());
} else if (message instanceof File) {
File file = (File) message;
openedFileChannel = new FileInputStream(file).getChannel();
message = new FilenameFileRegion(file, openedFileChannel, 0, openedFileChannel.size());
}
} catch (IOException e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
return DefaultWriteFuture.newNotWrittenFuture(this, e);
}
// Now, we can write the message. First, create a future
WriteFuture writeFuture = new DefaultWriteFuture(this);
WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);
// Then, get the chain and inject the WriteRequest into it
IoFilterChain filterChain = getFilterChain();
filterChain.fireFilterWrite(writeRequest);
// TODO : This is not our business ! The caller has created a
// FileChannel,
// he has to close it !
if (openedFileChannel != null) {
// If we opened a FileChannel, it needs to be closed when the write
// has completed
final FileChannel finalChannel = openedFileChannel;
writeFuture.addListener(new IoFutureListener() {
public void operationComplete(WriteFuture future) {
try {
finalChannel.close();
} catch (IOException e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
}
}
});
}
// Return the WriteFuture.
return writeFuture;
}
/**
* {@inheritDoc}
*/
public final Object getAttachment() {
return getAttribute("");
}
/**
* {@inheritDoc}
*/
public final Object setAttachment(Object attachment) {
return setAttribute("", attachment);
}
/**
* {@inheritDoc}
*/
public final Object getAttribute(Object key) {
return getAttribute(key, null);
}
/**
* {@inheritDoc}
*/
public final Object getAttribute(Object key, Object defaultValue) {
return attributes.getAttribute(this, key, defaultValue);
}
/**
* {@inheritDoc}
*/
public final Object setAttribute(Object key, Object value) {
return attributes.setAttribute(this, key, value);
}
/**
* {@inheritDoc}
*/
public final Object setAttribute(Object key) {
return setAttribute(key, Boolean.TRUE);
}
/**
* {@inheritDoc}
*/
public final Object setAttributeIfAbsent(Object key, Object value) {
return attributes.setAttributeIfAbsent(this, key, value);
}
/**
* {@inheritDoc}
*/
public final Object setAttributeIfAbsent(Object key) {
return setAttributeIfAbsent(key, Boolean.TRUE);
}
/**
* {@inheritDoc}
*/
public final Object removeAttribute(Object key) {
return attributes.removeAttribute(this, key);
}
/**
* {@inheritDoc}
*/
public final boolean removeAttribute(Object key, Object value) {
return attributes.removeAttribute(this, key, value);
}
/**
* {@inheritDoc}
*/
public final boolean replaceAttribute(Object key, Object oldValue, Object newValue) {
return attributes.replaceAttribute(this, key, oldValue, newValue);
}
/**
* {@inheritDoc}
*/
public final boolean containsAttribute(Object key) {
return attributes.containsAttribute(this, key);
}
/**
* {@inheritDoc}
*/
public final Set