How to displaly progress bar for downloading attachment - java

I display the progress bar for downloading attachments and it works fine … but when I am downloading some attachments I get the exception message:
Exception in thread "main" com.sun.mail.util.DecodingException:
BASE64Decoder: Error in encoded stream: needed 4 valid base64
characters but only got 1 before EOF, the 10 most recent characters
were: "Q3w5ilxj2P"
I found the explanation:
Certain IMAP servers do not implement the IMAP Partial FETCH
functionality properly. This problem typically manifests as corrupt
email attachments when downloading large messages from the IMAP
server. To workaround this server bug, set the
"mail.imap.partialfetch" property to false. You'll have to set this
property in the Properties object that you provide to your Session.
http://java.sun.com/products/javamail/NOTES113.txt
So I turned off partial fetch:
Properties props = System.getProperties();
props.setProperty("mail.store.protocol", "imaps");
props.setProperty("mail.imaps.partialfetch", "false");
Session session = Session.getDefaultInstance(props, null);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com", "<username>","<password>");
this solved the problem ….however the method getInputStream() from the Part class blocks the thread until the attachment is completely downloaded and it is impossible to get the information about the number of bytes which have been already downloaded from mailbox.
Without this information it is impossible to display the progress bar. So is there a way to obtain this information and display the progress bar?

It's difficult.
The only approach I know of is to create your own socket factory that produces a special kind of socket (of your own design) that returns an InputStream that wraps the real socket InputStream and allows you to monitor the amount of data read through the stream. This will allow you to measure the IMAP protocol data that is being returned from the server to the client. It won't be able to tell you what percentage of the data has been returned (because the data you're measuring includes all the IMAP protocol overhead and encoding overhead), but it should allow you to see that progress is being made.
If you create something like this, I'm sure others would be very interested in it!

Related

Spring boot app and what approach to use to download bulk data

I have spring boot application with basic REST API.
My question is what shall we use to download some bulk data? What is preferable way how to download bulk data without memory leak? Let's suppose we have 10 million records.
Here are some approaches but not sure:
download with PipedInputStream when data are written with PipedOutputStream in separated thread. Is it fine or it is not good choice?
download with ByteArrayOutputStream when data are written into temp file in separated thread and after finish it is ready to download. We can mark this operation with some flags for end user eg. DOWNLOAD_ACTIVE, DOWNLOAD_DONE. The user is just initiating download with result flag DOWNLOAD_ACTIVE and trying to ping server for response flag DOWNLOAD_DONE. When it is done then the user is going to send request to download data.
Summary 2)
1. initiate request to download data - ACTIVE state
2. ping server and server returns current state - ACTIVE or DONE
3. if final state is DONE then user initiate final request to download data
Thanks
You can use the second approach. Which can prepare data in the background and once it's ready you can download it.
Send a request to prepare data. The server responds with a UUID.
Server starts preparing files in the background. The server has a Map that has the key with a new UUID and value as status ACTIVE.
Client saved UUID and checks the server after a certain interval by passing the UUID.
Once the server finishes the task it will update the Map for the given UUID value as status DONE.
As the status is DONE next request will provide the status DONE and UI and send another request to download the file.
The above approach will only work if you don't refresh the page. As page refresh will clear the UUID and you have to proceed again.
To achieve this after refresh/cross-logins then you need to use a database table instead of Map. Store the username along with other information and inform the user once it's ready.

How to continuously read an online/web file in java?

I am making a simple text-only instant messenger in java. The way that it currently works is that all the messages are put into an online text file by sending a php file a request (I know this is bad for security, but this is just to learn how to do web-connected apps in java.)
Currently, I am continually fetching the entire contents of the messages.txt file and placing them into my JTextPane like this:
while(true) {
URL url = new URL("{path to text file}");
InputStream in = url.openStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String conversation = s.hasNext() ? s.next() : "";
textPane.setText(conversation);
}
But when the conversation becomes long enough, it lags as it is fetching 100kb+ files constantly from a web server.
What I want to happen is to only read the changes to the file so that it doesn't lag and max out my internet connection by requesting enourmous amounts of plain text files. I don't want to just make it run every 2 seconds because it's an instant messenger, no delays.
How would I go around only fetching the changes to the file and adding them to the text pane?
Can you push the file contents to another file once it crosses a certain threshold. This will ensure that you operate upon a smaller file.
Instead of contacting url directly you could place some server side script that would call the file
You could (as a client) provide the server script the last line / message identifier and the server could respond with new messages that have been added after the message id that the client has provided. In addition it could send the new last message id
With this approach the server side script doesnt even need to read itself the whole file and instead can immediately skip to the required line if message id contains the information about the line in the log file
Of course this approach is really far from real scenarios but its ok for learning IMO

Reading emails from IMAP - how to flag them as SEEN when processed?

I'm reading and processing emails received from IMAP using JODD mail library. API is very nice but I struggle with one logical issue. I'm using code as following:
EmailFilter filter= new EmailFilter();
filter.flag(Flags.Flag.SEEN, false);
session.receiveEmailAndMarkSeen(filter);
By calling session.receiveEmailAndMarkSeen I receive all unread emails and these are marked as read immediately. Now when processing fails in my code for any reason, and I try to receive emails again all these unprocessed emails are marked as read already and not downloaded anymore. I would rather download emails and mark them as read individualy as beeing processed successfully.
So I tried to receive them with session.receiveEmail but not sure how to mark them as read when processed? Any hint how to do it? I can see that email object has 'flag' property I can set but not sure how to send this information back to server.
To summarize possible solutions:
Re-fetch email with Seen flag. The downside is that email is fetched again.
What you wrote - using a Session and a Folder.
Finally - starting from the next version of Jodd, you will have the method updateEmailFlags that would give you options to just call it:
mymail.flags(newFlags);
ReceiveMailSession.updateEmailFlags(mymail);
The result would be the same.
SOLVED: I'm creating connection manualy using common JAVA mail classes - Session and Store.
Session sess = Session.getDefaultInstance(props, null);
Store store = sess.getStore("imaps");
store.connect("imapServerHost", "username","password");
... then I create folder object (points to Inbox)
Folder folder = store.getFolder(this.imapFolder);
folder.open(Folder.READ_WRITE);
... then I receive emails using session and store
ReceiveMailSession session=new ReceiveMailSession(sess, store);
... after email processed, I send back SEEN=true message using folder object.
Flags f=new Flags();
f.add(Flags.Flag.SEEN);
folder.setFlags(new int[] {email.getMessageNumber()}, f,true);

Java Mail API: Callbacks

Context:
I am working on a piece of Java code where I am reading mails from an array (which works fine). I was wondering if someone can help me with the callback in order to show a fancy message like Your email was sent.
Questions:
How do I implement this?
Is there any way to get any Boolean type return value from javax.mail to check if the message was sent or not?
Maybe I should create a pool? If yes, how do I do that? Is there any signal to kill the pool?
Code:
// addressTo is the array.
Transport t = sesion.getTransport(this.beanMail.getProtocolo());
t.connect(this.beanMail.getUsuario(), this.beanMail.getPassword());
t.sendMessage(mensaje, addressTo);
t.close();
Quoting from the JavaMail API FAQ (in the context of tracking bounced messages):
While there is an Internet standard for reporting such errors (the multipart/report MIME type, see RFC1892), it is not widely implemented yet. RFC1211 discusses this problem in depth, including numerous examples.In Internet email, the existence of a particular mailbox or user name can only be determined by the ultimate server that would deliver the message. The message may pass through several relay servers (that are not able to detect the error) before reaching the end server. Typically, when the end server detects such an error, it will return a message indicating the reason for the failure to the sender of the original message. There are many Internet standards covering such Delivery Status Notifications but a large number of servers don't support these new standards, instead using ad hoc techniques for returning such failure messages. This makes it very difficult to correlate a "bounced" message with the original message that caused the problem. (Note that this problem is completely independent of JavaMail.)
Source

How to mark messages that are received by an java application using javax Mail Api?

I want to create an application that gets all e-mails from an e-mail account using imap.
When I first run the application I get all mails, than if I run it again I want to mark the messages that was read before so I can receive only new messages.
I found that Message Object contains Flags(System Flags and User defined flags), but I can't manage to set one user defined flag.
It is possible to mark the messages received by my application on the e-mail account, or I have to retain all message ids and every time when I get messages from imap I have to compare their id with retained ids and get only the messages that has different ids?
Some IMAP servers don't permit you to set user-defined flags. Most do, however. Via JavaMail, you'd do the following:
Flags flags = new Flags("fetched");
message.setFlags(flags, true);
Those flags aren't permanent, however -- another IMAP client could clear them just as easily as you set them. (Though they probably won't.)
Another option is to track the UIDs of the messages you've seen. You can get them via ImapFolder.getUID(Message). It's more straightforward than tracking Message-ID headers, which are much more costly to fetch and, since they're strings, occupy more memory in your app.
Yet another option is to use POP and track UIDLs.
Yes it is possible to mark the messages as read, and when the next time you want to read the messages you can only read the new messages.
Use the following code:
Folder emailFolder = emailStore.getFolder("INBOX");
Message messages[] = emailFolder.search(new FlagTerm(new Flags(Flag.SEEN), false));
System.out.println("no of messages=" + messages.length);
for (int i = 0; i < messages.length; i++) {
Message message = messages[i];
//here write your code to read the message and whatever you wanna do//
//now at the end of the message(remember at the end of the message u read using code) write the following code//
message.setFlag(Flag.SEEN, true);
}//end of for loop

Categories