I'm using java mail to connect with gmail and I'm keeping one store for the all actions. (Store is set to static.).
And the IMAPFolder instances are attached with imap listeners. So the folders are kept always open. (Folder close is not called any time) But while running after few minutes I'm getting FolderClosedException. After that exception, though the folder can be reopened but the idle() command cannot be issued again, which will result in NullPointerException.
Is there any wrong with keeping folders open always?
Thanks in advance.
===================================================================
[Edit]
Here I'm pasting the actual code i'm doing POC with. The NullPointerException comes when I check .isConnected() after reconnecting the store. Below is the run method of Thread which sends idle() command to the store.
public void run() {
while (true) {
try {
System.out.println("Checking connectivity...");
if (store.isConnected()) {
store.idle();
System.out.println("IDLE send...");
} else {
Thread.sleep(5000);
System.out.println("Tring to connect...");
//Trying to reconnect to the store.
store.connect();
System.out.println("Previous store connected again");
}
} catch (InterruptedException ex) {
System.out.println("InterruptedException...");
} catch (StoreClosedException ex) {
System.out.println("StoreClosedException...");
} catch (MessagingException ex) {
System.out.println("MessagingException...");
}
}
}
Here is the stack trace:
Exception in thread "Thread-1" java.lang.NullPointerException
at com.sun.mail.imap.IMAPStore.waitIfIdle(IMAPStore.java:1881)
at com.sun.mail.imap.IMAPStore.getStoreProtocol(IMAPStore.java:946)
at com.sun.mail.imap.IMAPStore.isConnected(IMAPStore.java:1347)
at pocworks.POCWorks1$IDLEThread.run(POCWorks1.java:125)
Generally, mail servers don't like you to keep connections open when you're not using them. Typical IMAP servers will give you 30 minutes before they time out an unused connection; Gmail may be more aggressive.
Related
I'm wondering how to log information when a server has successfully started. I cannot do this as simple as that:
createServer().start(Exit.NEVER);
System.out.println("Server is running...");
because the instruction createServer().start(Exit.NEVER) doesn't return back. This is a call to external library that uses a method with a loop similar to while(true).
I cannot also run the server in a new thread and then log information about successful start because the server may throw exception and hence there was a failure.
public void start () {
new Thread("Server") {
#Override
public void run() {
try {
createServer().start(Exit.NEVER);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
}
}.start();
System.out.println("Server is running...");
}
Last solution I can think of is to wait a couple of second after createServer().start(Exit.NEVER) and then log the successful start as there was no exception thrown. This is not a perfect solution as we can wait for example 5 seconds and the log the successful start but one second later the server may throw exception.
How do I then can tell whether the server has started successfully and hence log this information?
EDIT
The server I'm using is Takes https://github.com/yegor256/takes.
The below program acts as TCP client and uses NIO to open socket to a remote server, as below
private Selector itsSelector;
private SocketChannel itsChannel;
public boolean getConnection(Selector selector, String host, int port)
{
try
{
itsSelector = selector;
itsChannel = SocketChannel.open();
itsChannel.configureBlocking(false);
itsChannel.register(itsSelector, SelectionKey.OP_CONNECT);
itsChannel.connect(new InetSocketAddress(host, port));
if (itsChannel.isConnectionPending())
{
while (!itsChannel.finishConnect())
{
// waiting until connection is finished
}
}
itsChannel.register(itsSelector, SelectionKey.OP_WRITE);
return (itsChannel != null);
}
catch (IOException ex)
{
close();
if(ex instanceof ConnectException)
{
LOGGER.log(Level.WARNING, "The remoteserver cannot be reached");
}
}
}
public void close()
{
try
{
if (itsChannel != null)
{
itsChannel.close();
itsChannel.socket().close();
itsSelector.selectNow();
}
}
catch (IOException e)
{
LOGGER.log(Level.WARNING, "Connection cannot be closed");
}
}
This program runs on Red Hat Enterprise Linux Server release 6.2 (Santiago)
When number of concurrent sockets are in establishment phase, file descriptor limit reaches a max value and I see below exception while trying to establish more socket connections.
java.net.SocketException: Too many open files
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
This happens only when the remote Node is down, and while it is up, all is fine.
When the remote TCP server is down, below exception is thrown as is handled as IOException in the above code
java.net.ConnectException: Connection refused: no further information
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source)
Is there any way to forcefully close the underlying file descriptor in this case.
Thanks in advance for all the help.
private Selector itsSelector;
I cannot see the point of this declaration. You can always get the selector the channel is registered with, if you need it, which you never do. Possibly you are leaking Selectors?
itsChannel.configureBlocking(false);
itsChannel.register(itsSelector, SelectionKey.OP_CONNECT);
Here you are registering for OP_CONNECT but never making the slightest use of the facility.
itsChannel.connect(new InetSocketAddress(host, port));
Here you are starting a pending connection.
if (itsChannel.isConnectionPending())
It is. You just started it. The test is pointless.
{
while (!itsChannel.finishConnect())
{
// waiting until connection is finished
}
}
This is just a complete waste of time and space. If you don't want to use the selector to detect when OP_CONNECT fires, you should call connect() before setting the channel to non-blocking, and get rid of this pointless test and loop.
itsChannel.register(itsSelector, SelectionKey.OP_WRITE);
return (itsChannel != null);
itsChannel cannot possibly be null at this point. The test is pointless. You would be better off allowing the IOExceptions that can arise to propagate out of this method, so that the caller can get some idea of the failure mode. That also places the onus on the caller to close on any exception, not just the ones you're catching here.
catch (IOException ex)
{
close();
if(ex instanceof ConnectException)
{
LOGGER.log(Level.WARNING, "The remoteserver cannot be reached");
}
}
See above. Remove all this. If you want to distinguish ConnectException from the other IOExceptions, catch it, separately. And you are forgetting to log anything that isn't a ConnectException.
public void close()
{
try
{
if (itsChannel != null)
{
itsChannel.close();
itsChannel.socket().close();
itsSelector.selectNow();
The second close() call is pointless, as the channel is already closed.
catch (IOException e)
{
LOGGER.log(Level.WARNING, "Connection cannot be closed");
}
I'm glad to see you finally logged an IOException, but you're not likely to get any here.
Don't write code like this.
Occasionally when my Java program gets an internal error and terminates, the connection to the MQ channel remains established.
Strangely the java code is not running on my machine, but in MQ explorer, it is shown as connected .
Is there is any process/service running in my machine which I can terminate manually to close the connection ?
Can you tell me what is the likely reason for this ( i am using connection.close / channel.close and queue.close) and what could be the likely
Regards
Abhinav
Is there is any process/service running in my machine which I can
terminate manually to close the connection ?
You need to include try/catch logic in your code and when you have an issue, then in the catch clause, have your code call its cleanup logic (i.e. close queues and disconnect from the queue manager).
Can you tell me what is the likely reason for this ( i am using
connection.close / channel.close and queue.close) and what could be
the likely
Obviously, you are not and it conflicts with your earlier statement of:
when my Java program gets an internal error and terminates,
Therefore, add the appropriate try/catch logic and properly close queues and disconnect from the queue manager even when bad things go wrong in your program.
You can add below method in finally:
private void cleanUp() {
if (producer != null) {
try {
producer.close();
} catch (JMSException jmsex) {
logger.error("WebSphereMQMessageSender. cleanUp: Producer could not be closed.");
recordFailure(jmsex);
}
}
if (session != null) {
try {
session.close();
} catch (JMSException jmsex) {
logger.error("WebSphereMQMessageSender. cleanUp: Session could not be closed.");
recordFailure(jmsex);
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException jmsex) {
logger.error("WebSphereMQMessageSender. cleanUp: Connection could not be closed.");
recordFailure(jmsex);
}
}
}
for more information see this.
I'm having issues dealing with a server which would close my FTP control connection in spite of me sending keep alive requests with ftpClient.setControlKeepAliveTimeout(CONTROL_CONNECTION_KEEP_ALIVE_INTERVAL_SECONDS);
Also sometimes it just dies out of SocketException and not the normal FTPConnectionClosedException. All in all, FTP is a very dodgy protocol I'm using a lot and each server I connect requires a bit of tweaking, however this one is giving a very hard time.
I know there's a million things I could be doing wrong, my question is, is there some solution with retries already implemented on FTP in case you lose the control connection, since is not something that should be shocking (proxies / firewalls sometimes just randomly lose your connection). Or is there some more elegant way of solving this problem.
I have something like this.
public void store(File fileToUpload) throws IOException, InterruptedException {
String filename = fileToUpload.getName();
int retries = 0;
while (true) {
try {
ftpClient.storeFile(filename, inputStreamFactory.getInputStream(fileToUpload));
} catch (FTPConnectionClosedException | SocketException exception) {
LOGGER.debug("Control connection lost uploading {}, continuing.", filename);
}
// This sleep is because there's an anti-malware in the servers which makes the file not to appear
// available immediately after an upload
LOGGER.debug("Waiting {} milliseconds for anti-malware protection to process file", WAIT_AFTER_UPLOAD_MILLISECONDS);
threadWrapper.sleep(WAIT_AFTER_UPLOAD_MILLISECONDS);
if (!ftpClient.isConnected()) {
connect();
}
LOGGER.debug("Checking if {} is already uploaded", filename);
if (ftpFileChecker.isFileCompleted(listFiles(null), filename, fileToUpload.length())) {
// Note this is likely to happen every time since their server will close the control
// connection quite fast and FTPClient uses it at the end of storeFile
LOGGER.debug("File {} was uploaded correctly", filename);
break;
} else {
if (++retries > MAX_RETRIES) {
throw new RemoteTimeoutException("Could not upload file, max retries exceeded");
} else {
LOGGER.info("File {} was not uploaded, retrying", filename);
}
}
}
}
public void connect() throws IOException, InterruptedException {
int retries = 0;
while (true) {
try {
ftpClient = ftpClientFactory.createFtpClient();
ftpClient.connect(server, FTP_PORT);
if (!ftpClient.login(username, password)) {
LOGGER.error("Login to FTP failed");
throw new ConfigurationException("Login to FTP failed");
}
ftpClient.enterLocalPassiveMode();
ftpClient.setControlKeepAliveTimeout(CONTROL_CONNECTION_KEEP_ALIVE_INTERVAL_SECONDS);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(uploadDir);
break;
} catch (FTPConnectionClosedException | SocketException exception) {
if (++retries > MAX_RETRIES) {
throw new RemoteTimeoutException("Could not upload file, max retries exceeded", exception);
} else {
LOGGER.info("Could not login, retrying");
}
}
LOGGER.debug("Sleeping {} milliseconds before trying to reconnect", WAIT_BETWEEN_CONNECT_RETRIES_MILLISECONDS);
threadWrapper.sleep(WAIT_BETWEEN_CONNECT_RETRIES_MILLISECONDS);
}
}
public FTPFile[] listFiles(String directory) throws IOException, InterruptedException {
int retries = 0;
while (true) {
try {
return ftpClient.listFiles(directory);
} catch (FTPConnectionClosedException exception) {
LOGGER.debug("Control connection lost when listing files, continuing");
} catch (SocketException exception) {
LOGGER.debug("Socket exception when listing files, continuing");
}
if (!ftpClient.isConnected()) {
connect();
}
if (++retries > MAX_RETRIES) {
throw new RemoteTimeoutException("Could not list files, max retries exceeded");
} else {
LOGGER.info("Could not list files, retrying");
}
}
}
Now I'm getting SocketException Broken Pipe on listFiles, and I can't figure it out anymore since in my local server it works perfect, but in this particular one (hint it runs on Windows NT - :( - it runs some malware protection which prevents the files to appear on the server immediately and is apparently behind some very strange firewalls, and it drops idle connections after about 5 seconds, and they won't change the configuration cause they are a big company and claim it works for everyone else).
I tried VFS and investigated over other FTP clients but none I found seem to solve the problem, even more unhelpful, most of them (like ftp4j) are not in maven central which really puts me off trying them unless there's a guarantee it will solve my problems.
Any help is welcome.
Edit: Code given reflects the starting complexity of this, my current solution is more stable with quite a lot more complexity, but it's not elegant at all, so I leave the question open in case someone cares to contribute a nice solution.
If using Spring, then consider Spring Retry. I believe the latest Maven version is:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.1.2.RELEASE</version>
</dependency>
I'm using a variation of the example at http://svn.apache.org/repos/asf/activemq/trunk/assembly/src/release/example/src/StompExample.java to receive message from a queue. What I'm trying to do is to keep listening to a queue and perform some action upon reception of a new message. The problem is that I couldn't find a way to register a listener to any of the related objects. I've tried something like:
public static void main(String args[]) throws Exception {
StompConnection connection = null;
try {
connection = new StompConnection();
connection.open("localhost", 61613);
connection.connect("admin", "activemq");
connection.subscribe("/queue/worker", Subscribe.AckModeValues.AUTO);
while (true) {
StompFrame message = connection.receive();
System.out.println(message.getBody());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
but this doesn't work as a time out occurs after a few seconds (java.net.SocketTimeoutException: Read timed out). Is there anything I can do to indefinitely listen to this queue?
ActiveMQ's StompConnection class is a relatively primitive STOMP client. Its not capable of async callbacks on Message or for indefinite waits. You can pass a timeout to receive but depending on whether you are using STOMP v1.1 it could still timeout early if a heart-beat isn't received in time. You can of course always catch the timeout exception and try again.
For STOMP via Java you're better off using StompJMS or the like which behaves like a real JMS client and allows for async Message receipt.
#Tim Bish: I tried StompJMS, but couldn't find any example that I could use (maybe you can provide a link). I 'fixed' the problem by setting the timeout to 0 which seems to be blocking.
even i was facing the same issue.. you can fix this by adding time out to your receive() method.
Declare a long type variable.
long waitTimeOut = 5000; //this is 5 seconds
now modify your receive function like below.
StompFrame message = connection.receive(waitTimeOut);
This will definitely work.