📄 imapstore.java
字号:
p = null;
}
if (p == null)
throw new ConnectionException(
"failed to create new store connection");
p.addResponseHandler(this);
pool.authenticatedConnections.addElement(p);
} else {
// Always use the first element in the Authenticated queue.
if (pool.debug)
out.println("DEBUG: getStoreProtocol() - " +
"connection available -- size: " +
pool.authenticatedConnections.size());
p = (IMAPProtocol)pool.authenticatedConnections.firstElement();
}
if (pool.storeConnectionInUse) {
try {
// someone else is using the connection, give up
// and wait until they're done
p = null;
pool.wait();
} catch (InterruptedException ex) { }
} else {
pool.storeConnectionInUse = true;
if (pool.debug)
out.println("DEBUG: getStoreProtocol() -- " +
"storeConnectionInUse");
}
timeoutConnections();
}
}
return p;
}
/**
* If a SELECT succeeds, but indicates that the folder is
* READ-ONLY, and the user asked to open the folder READ_WRITE,
* do we allow the open to succeed?
*/
boolean allowReadOnlySelect() {
String s = session.getProperty("mail." + name +
".allowreadonlyselect");
return s != null && s.equalsIgnoreCase("true");
}
/**
* Report whether the separateStoreConnection is set.
*/
boolean hasSeparateStoreConnection() {
return pool.separateStoreConnection;
}
/**
* Report whether connection pool debugging is enabled.
*/
boolean getConnectionPoolDebug() {
return pool.debug;
}
/**
* Report whether the connection pool is full.
*/
boolean isConnectionPoolFull() {
synchronized (pool) {
if (pool.debug)
out.println("DEBUG: current size: " +
pool.authenticatedConnections.size() +
" pool size: " + pool.poolSize);
return (pool.authenticatedConnections.size() >= pool.poolSize);
}
}
/**
* Release the protocol object back to the connection pool.
*/
void releaseProtocol(IMAPFolder folder, IMAPProtocol protocol) {
synchronized (pool) {
if (protocol != null) {
// If the pool is not full, add the store as a response handler
// and return the protocol object to the connection pool.
if (!isConnectionPoolFull()) {
protocol.addResponseHandler(this);
pool.authenticatedConnections.addElement(protocol);
if (debug)
out.println("DEBUG: added an " +
"Authenticated connection -- size: " +
pool.authenticatedConnections.size());
} else {
if (debug)
out.println("DEBUG: pool is full, not adding " +
"an Authenticated connection");
try {
protocol.logout();
} catch (ProtocolException pex) {};
}
}
if (pool.folders != null)
pool.folders.removeElement(folder);
timeoutConnections();
}
}
/**
* Release the store connection.
*/
void releaseStoreProtocol(IMAPProtocol protocol) {
if (protocol == null)
return; // nothing to release
synchronized (pool) {
pool.storeConnectionInUse = false;
pool.notifyAll(); // in case anyone waiting
if (pool.debug)
out.println("DEBUG: releaseStoreProtocol()");
timeoutConnections();
}
}
/**
* Empty the connection pool.
*/
private void emptyConnectionPool(boolean force) {
synchronized (pool) {
for (int index = pool.authenticatedConnections.size() - 1;
index >= 0; --index) {
try {
IMAPProtocol p = (IMAPProtocol)
pool.authenticatedConnections.elementAt(index);
p.removeResponseHandler(this);
if (force)
p.disconnect();
else
p.logout();
} catch (ProtocolException pex) {};
}
pool.authenticatedConnections.removeAllElements();
}
if (pool.debug)
out.println("DEBUG: removed all authenticated connections");
}
/**
* Check to see if it's time to shrink the connection pool.
*/
private void timeoutConnections() {
synchronized (pool) {
// If we've exceeded the pruning interval, look for stale
// connections to logout.
if (System.currentTimeMillis() - pool.lastTimePruned >
pool.pruningInterval &&
pool.authenticatedConnections.size() > 1) {
if (pool.debug) {
out.println("DEBUG: checking for connections " +
"to prune: " +
(System.currentTimeMillis() - pool.lastTimePruned));
out.println("DEBUG: clientTimeoutInterval: " +
pool.clientTimeoutInterval);
}
IMAPProtocol p;
// Check the timestamp of the protocol objects in the pool and
// logout if the interval exceeds the client timeout value
// (leave the first connection).
for (int index = pool.authenticatedConnections.size() - 1;
index > 0; index--) {
p = (IMAPProtocol)pool.authenticatedConnections.
elementAt(index);
if (pool.debug) {
out.println("DEBUG: protocol last used: " +
(System.currentTimeMillis() - p.getTimestamp()));
}
if (System.currentTimeMillis() - p.getTimestamp() >
pool.clientTimeoutInterval) {
if (pool.debug) {
out.println("DEBUG: authenticated " +
"connection timed out");
out.println("DEBUG: logging out " +
"the connection");
}
p.removeResponseHandler(this);
pool.authenticatedConnections.removeElementAt(index);
try {
p.logout();
} catch (ProtocolException pex) {}
}
}
pool.lastTimePruned = System.currentTimeMillis();
}
}
}
/**
* Get the block size to use for fetch requests on this Store.
*/
int getFetchBlockSize() {
return blksize;
}
/**
* Get a reference to the session.
*/
Session getSession() {
return session;
}
/**
* Get the number of milliseconds to cache STATUS response.
*/
int getStatusCacheTimeout() {
return statusCacheTimeout;
}
/**
* Get the maximum size of a message to buffer for append.
*/
int getAppendBufferSize() {
return appendBufferSize;
}
/**
* Get the minimum amount of time to delay when returning from idle.
*/
int getMinIdleTime() {
return minIdleTime;
}
/**
* Return true if the specified capability string is in the list
* of capabilities the server announced.
*
* @since JavaMail 1.3.3
*/
public synchronized boolean hasCapability(String capability)
throws MessagingException {
IMAPProtocol p = null;
try {
p = getStoreProtocol();
return p.hasCapability(capability);
} catch (ProtocolException pex) {
if (p == null) { // failed to get a Store connection
// have to force Store to be closed
cleanup();
}
throw new MessagingException(pex.getMessage(), pex);
} finally {
releaseStoreProtocol(p);
}
}
/**
* Check whether this store is connected. Override superclass
* method, to actually ping our server connection.
*/
public synchronized boolean isConnected() {
if (!connected) {
// if we haven't been connected at all, don't bother with
// the NOOP.
super.setConnected(false); // just in case
return false;
}
/*
* The below noop() request can:
* (1) succeed - in which case all is fine.
*
* (2) fail because the server returns NO or BAD, in which
* case we ignore it since we can't really do anything.
* (2) fail because a BYE response is obtained from the
* server
* (3) fail because the socket.write() to the server fails,
* in which case the iap.protocol() code converts the
* IOException into a BYE response.
*
* Thus, our BYE handler will take care of closing the Store
* in case our connection is really gone.
*/
IMAPProtocol p = null;
try {
p = getStoreProtocol();
p.noop();
} catch (ProtocolException pex) {
if (p == null) { // failed to get a Store connection
// have to force Store to be closed
cleanup();
}
// will return false below
} finally {
releaseStoreProtocol(p);
}
return super.isConnected();
}
/**
* Close this Store.
*/
public synchronized void close() throws MessagingException {
if (!super.isConnected()) // Already closed.
return;
IMAPProtocol protocol = null;
try {
boolean isEmpty;
synchronized (pool) {
// If there's no authenticated connections available
// don't create a new one
isEmpty = pool.authenticatedConnections.isEmpty();
}
/*
* Have to drop the lock before calling cleanup.
* Yes, there's a potential race here. The pool could
* become empty after we check, in which case we'll just
* waste time getting a new connection and closing it.
* Or, the pool could be empty now and not empty by the
* time we get into cleanup, but that's ok because cleanup
* will just close the connection.
*/
if (isEmpty) {
if (pool.debug)
out.println("DEBUG: close() - no connections ");
cleanup();
return;
}
protocol = getStoreProtocol();
/*
* We have to remove the protocol from the pool so that,
* when our response handler processes the BYE response
* and calls cleanup, which calls emptyConnection, that
* we don't try to log out this connection twice.
*/
synchronized (pool) {
pool.authenticatedConnections.removeElement(protocol);
}
/*
* LOGOUT.
*
* Note that protocol.logout() closes the server socket
* connection, regardless of what happens ..
*
* Also note that protocol.logout() results in a BYE
* response (As per rfc 2060, BYE is a *required* response
* to LOGOUT). In fact, even if protocol.logout() fails
* with an IOException (if the server connection is dead),
* iap.Protocol.command() converts that exception into a
* BYE response. So, I depend on my BYE handler to do the
* Store cleanup.
*/
protocol.logout();
} catch (ProtocolException pex) {
// Hmm .. will this ever happen ?
cleanup();
throw new MessagingException(pex.getMessage(), pex);
} finally {
releaseStoreProtocol(protocol);
}
}
protected void finalize() throws Throwable {
super.finalize();
close();
}
// Cleanup before dying.
private void cleanup() {
cleanup(false);
}
/**
* Cleanup before dying.
* If force is true, we force the folders to close
* abruptly without waiting for the server. Used when
* the store connection times out.
*
* Not synchronized so that it can be safely called from handleResponse.
*/
private void cleanup(boolean force) {
if (debug)
out.println("DEBUG: IMAPStore cleanup, force " + force);
Vector foldersCopy = null;
boolean done = true;
// To avoid violating the locking hierarchy, there's no lock we
// can hold that prevents another thread from trying to open a
// folder at the same time we're trying to close all the folders.
// Thus, there's an inherent race condition here. We close all
// the folders we know about and then check whether any new folders
// have been opened in the mean time. We keep trying until we're
// successful in closing all the folders.
for (;;) {
// Make a copy of the folders list so we do not violate the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -