How to delete a file after thread is finished in java? - java

I am trying to send a mail with an attachment. I am using javamail api to perform this operation. Since multiple users can send mail at the same time, I created a thread to make it safe. I am able to delete the file using the file.delete() function which happening before the attachment is done in mail. But I am unable to delete the file after attachment/mail sent. Please help me in this issue.
Here is the code I have used to attach and send mail:
public void sendMailWithAttachment(String from, final String to, final String subject, final String msg, final String filePath) {
Thread ty = new Thread(){
public void run(){
MimeMessage message = mailSend.createMimeMessage();
try{
MimeMessageHelper helper = new MimeMessageHelper(message, true);
//helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(msg);
FileSystemResource file = new FileSystemResource(filePath);
helper.addAttachment(file.getFilename(), file);
//I want to write code to delete the file here
}catch (MessagingException e) {
throw new MailParseException(e);
}
mailSend.send(message);
}
};
ty.start();
}

Anyway you're initializing your Thread implementation. You can override the finalize() method for the Thread implementation which gets called when the Thread object is about to get garbage collected.
Code would look like below:
Thread ty = new Thread(){
public void run(){
// do mail sending stuff here.
}
#Override
protected void finalize() throws Throwable {
// delete file here
}
};
ty.start();

You have various ways to do this task, I recommend you the second
1) Instiatate that File, And then if your java environment has the corrects permissions on that folder you can delete that file, like this
try{
File file = new File("filePath");
if(file.delete()){
System.out.println("Deleted file: " + file.getName());
}else{
System.out.println("Delete failed on file ": + file.getName());
}
}catch(Exception e){
e.printStackTrace();
}
2) You can also use The generic Class Files
try {
Files.delete(path);
} catch (NoSuchFileException x) {
System.err.format("%s: no such" + " file or directory%n", path);
} catch (DirectoryNotEmptyException x) {
System.err.format("%s not empty%n", path);
} catch (IOException x) {
// File permission problems are caught here.
System.err.println(x);
}
If you have problems deleting the file maybe is beacuse the object FileSystemResource is pointing that file, Try to finalize that object with
file.finalize()
take a look at this question to finished Threads
How to know if other threads have finished?

Delete the file in a finally block after the send operation.

Related

Is my file saving logic correct?

My java app calls a rest endpoint and in the response body is a 10GB XML file. Before I send the rest quest, I ask the service how many records will be in the file. I then retrieve the file. When I run my app, the file is saved successfully but only roughly 50% of the expected records. There are 2 reasons the file doesn't have all the records:
The file sent from the rest endpoint only has 50% of the expected records
My app is falling over when before it has finished downloading
My question is, if in scenario 2 and my app falls over, would I see an exception stating so? I do not see an exception, in fact, I see my log statement after the save is saved saying 'File successfully saved'.
EDIT: I have downloaded the file outside of my app, via a curl request and the same thing happened - only 50% of the expected population was downloaded. This proves the issue isn't with my file-saving logic.
public void saveFile() {
try {
downloadAndSaveFile();
} catch (Exception e) {
LOGGER.error("A error has occurred processing all content, caused by {}", e.getMessage(), e);
throw new RuntimeException(e);
}
}
private void downloadAndSaveFile() throws Exception {
long recordCount = countRecords();
LOGGER.info("Number of records to process is {}", recordCount);
if (recordCount > 0 ) {
InputStream dataToSave = getAllContent();
saveStream(dataToSave);
LOGGER.info("File successfully saved.");
} else {
LOGGER.error("No content to retrieve");
throw new RuntimeException("There are no records to process");
}
}
public InputStream getAllContent() throws Exception {
return callRestEndpoint(webTarget).readEntity(InputStream.class);
}
private Response callRestEndpoint(WebTarget target) throws InterruptedException {
Response response = null;
for (int numberOfTries = 0; numberOfTries < reconnectRetries; numberOfTries++) {
try {
response = makeGetRequest(target);
if (OK.getStatusCode() == response.getStatus()) {
break;
}
} catch (Exception ex) {
retryRequest(numberOfTries, ex);
}
}
return response;
}
public void saveStream(InputStream inputStream) throws IOException {
File fileToCreate = new File(fileName);
if (!fileToCreate.exists()) {
fileToCreate.mkdirs();
}
Files.copy(
inputStream,
fileToCreate.toPath(),
StandardCopyOption.REPLACE_EXISTING
);
closeQuietly(inputStream);
}
Is my file saving logic correct?
No.
if (!fileToCreate.exists()) {
fileToCreate.mkdirs();
}
Here you are creating every element in fileToCreate as a directory, including the final element. So trying to open it later as a file will fail. And the exists() test is pointless. It should be:
fileToCreate.getParentFile().mkdirs();
if in scenario 2 and my app falls over, would I see an exception stating so
Yes, provided you print or log it somewhere. The method will definitely throw one.

How to check incoming file transfer status in apache commons io monitor

I have implemented a simple file listener using Apache commons io monitor.I have also implemented a selenium script that simply do is download file into the pre hard coded path folder.That is totally working fine.My listener monitoring downloaded files and collect the necessary information.According to my requirement i should be able to stop the file listener once my selenium script is finished execution.To do that i must know that the incoming file transferring status to handle it better way.because i can not stop listener middle of the file transferring.(sometimes download file can be heavy so it will take some time to download).So how can i know that incoming file status in Apache commons io monitor before stop the file listener.If any one knows please let me know.
Sample code snippet
public class SimpleTestMonitor {
// A hardcoded path to a folder you are monitoring .
public static final String FOLDER =
"/home/skywalker/Desktop/simple-test-monitor/watchdir";
public static void main(String[] args) throws Exception {
// The monitor will perform polling on the folder every 5 seconds
final long pollingInterval = 5 * 1000;
File folder = new File(FOLDER);
if (!folder.exists()) {
// Test to see if monitored folder exists
throw new RuntimeException("Directory not found: " + FOLDER);
}
FileAlterationObserver observer = new FileAlterationObserver(folder);
FileAlterationMonitor monitor =
new FileAlterationMonitor(pollingInterval);
FileAlterationListener listener = new FileAlterationListenerAdaptor() {
// Is triggered when a file is created in the monitored folder
#Override
public void onFileCreate(File file) {
try {
// "file" is the reference to the newly created file
System.out.println("File created: "
+ file.getCanonicalPath());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
// Is triggered when a file is deleted from the monitored folder
#Override
public void onFileDelete(File file) {
try {
// "file" is the reference to the removed file
System.out.println("File removed: "
+ file.getCanonicalPath());
// "file" does not exists anymore in the location
System.out.println("File still exists in location: "
+ file.exists());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
observer.addListener(listener);
monitor.addObserver(observer);
monitor.start();
}
}
Reference

Multiple files transfer protocol with "authentication" from Android to Server

I'm a newbie programmer looking for a way to implement a simple file transfer protocol on Android.
Problem:
Several Android phones need to connect to a server to receive/send a series of XML files saved in internal storage. The server needs to know which phone is requesting a connection so that it can save the files in the correct folder.
Possible solution/algorithm:
There are various tutorials/examples on how to send a file to a server, but none of them seem to implement some kind of "authentication".
Ideally I would like to implement the following (I'll use a metaphor):
Phone: Hello.
Server: Hi. Who are you and what do you want? [send/receive]
Phone A: I'm phone A and I would like to send files.
Server: How many files do you want to send, Phone A?
Phone A: 6 files, [+extra data like total size or whatever]
Server: Alright, you can begin the transfer.
Phone A: Transfers...
Server: I've succesfully received 6 files, have a good day. [stores the files in a PhoneA folder]
Phone A: Bye! [closes connection]
I realise this could very likely be made a lot more efficient, but I don't know where to begin...
Is it even possible to initiate a connection with a server and interact multiple times while waiting for responses?
Question :
Could anyone push me in the right direction somehow? Do I write my own protocol or can this be done with standard functionality? What are the best/easiest existing protocols for this kind of implementation?
I've found this article interesting but I don't see how it could be used for multiple files with authentication
Any help would be much appreciated!
This is easier than you think using old-school FTP, which I've used with success in collecting data from apps, and your server will surely support it.
Get a unique ID for each Android device using enter link description here. You get a 64-bit number (as a hex string) that is randomly generated on each device’s first boot. It's supposedly constant for the life of the device.
Import Apache Commons FTP and use the method describe here to create a directory name inside your working directory on the server with a name matching the unique id.
Use the same library to upload the files using FTP. You'll find many example of how to do this. It takes very minimal code.
Unlike your chat scenario, this is a very client-side solution, and phones you might not want to could upload files -- there's no blacklist -- but it's easy to implement.
For those interested in (terrible) code to perform various FTP functions, here's what worked for me.
It requires the apache commons ftp jar file which can be found on the internet.
//Button that starts it all
public void updateWorkordersList(View view) {
if (!CheckNetworkConnection.isOnline()) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(this);
String connectionString = prefs
.getString("connection_string", null);
String userName = prefs.getString("FTPusername", null);
DownloadFilesTask task = new DownloadFilesTask(connectionString,
userName);
task.execute();
Fragment frg = null;
frg = getFragmentManager()
.findFragmentByTag("buttonsContainer");
final FragmentTransaction ft = getFragmentManager()
.beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
}
}
private class DownloadFilesTask extends AsyncTask<Void, Void, Boolean> {
private FTPClient mFtpClient = new FTPClient();
private FTPFile[] mFileArray;
private String _address;
private String _user;
private String _pass;
public DownloadFilesTask(String ip, String user) {
_address = ip;
_user = user;
}
#Override
protected Boolean doInBackground(Void... params) {
try {
mFtpClient.setConnectTimeout(10 * 1000);
mFtpClient.connect(InetAddress.getByName("insert server here"));
boolean status = mFtpClient.login("username", "password");
if (FTPReply.isPositiveCompletion(mFtpClient.getReplyCode())) {
mFtpClient.setFileType(FTP.ASCII_FILE_TYPE);
mFtpClient.enterLocalPassiveMode();
mFileArray = mFtpClient.listFiles();
}
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//Download All Files
if (FTPReply.isPositiveCompletion(mFtpClient.getReplyCode())) {
File directory = null;
directory = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getPath());
for (FTPFile file : mFileArray) {
OutputStream outputStream = null;
try {
outputStream = new BufferedOutputStream(
new FileOutputStream(directory + "/"
+ file.getName()));
mFtpClient.setFileType(FTP.BINARY_FILE_TYPE);
mFtpClient.retrieveFile(file.getName(), outputStream);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//Upload All Files
if (FTPReply.isPositiveCompletion(mFtpClient.getReplyCode())) {
File directory = null;
directory = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getPath() + "/srvReady");
for (File file : directory.listFiles()) {
try {
FileInputStream srcFileStream = new FileInputStream(directory + "/" + file.getName());
boolean status = mFtpClient.storeFile(_user + "/" + file.getName(),
srcFileStream);
srcFileStream.close();
if (status){
file.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
try {
mFtpClient.logout();
mFtpClient.disconnect();
} catch (Exception e) {
// TODO: handle exception
}
return true;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(Boolean result) {
}
}
I figure this could be of some use might someone ever come across a similar problem.

How to watch file for new content and retrieve that content

I have a file with name foo.txt. This file contains some text. I want to achieve following functionality:
I launch program
write something to the file (for example add one row: new string in foo.txt)
I want to get ONLY NEW content of this file.
Can you clarify the best solution of this problem? Also I want resolve related issues: in case if I modify foo.txt I want to see diff.
The closest tool which I found in Java is WatchService but if I understood right this tool can only detect type of event happened on filesystem (create file or delete or modify).
Java Diff Utils is designed for that purpose.
final List<String> originalFileContents = new ArrayList<String>();
final String filePath = "C:/Users/BackSlash/Desktop/asd.txt";
FileListener fileListener = new FileListener() {
#Override
public void fileDeleted(FileChangeEvent paramFileChangeEvent)
throws Exception {
// use this to handle file deletion event
}
#Override
public void fileCreated(FileChangeEvent paramFileChangeEvent)
throws Exception {
// use this to handle file creation event
}
#Override
public void fileChanged(FileChangeEvent paramFileChangeEvent)
throws Exception {
System.out.println("File Changed");
//get new contents
List<String> newFileContents = new ArrayList<String> ();
getFileContents(filePath, newFileContents);
//get the diff between the two files
Patch patch = DiffUtils.diff(originalFileContents, newFileContents);
//get single changes in a list
List<Delta> deltas = patch.getDeltas();
//print the changes
for (Delta delta : deltas) {
System.out.println(delta);
}
}
};
DefaultFileMonitor monitor = new DefaultFileMonitor(fileListener);
try {
FileObject fileObject = VFS.getManager().resolveFile(filePath);
getFileContents(filePath, originalFileContents);
monitor.addFile(fileObject);
monitor.start();
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (FileNotFoundException e) {
//handle
e.printStackTrace();
} catch (IOException e) {
//handle
e.printStackTrace();
}
Where getFileContents is :
void getFileContents(String path, List<String> contents) throws FileNotFoundException, IOException {
contents.clear();
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
String line = null;
while ((line = reader.readLine()) != null) {
contents.add(line);
}
}
What I did:
I loaded the original file contents in a List<String>.
I used Apache Commons VFS to listen for file changes, using FileMonitor. You may ask, why? Because WatchService is only available starting from Java 7, while FileMonitor works with at least Java 5 (personal preference, if you prefer WatchService you can use it). note: Apache Commons VFS depends on Apache Commons Logging, you'll have to add both to your build path in order to make it work.
I created a FileListener, then I implemented the fileChanged method.
That method load new contents form the file, and uses Patch.diff to retrieve all differences, then prints them
I created a DefaultFileMonitor, which basically listens for changes to a file, and I added my file to it.
I started the monitor.
After the monitor is started, it will begin listening for file changes.

Android/Java File.mkdirs() in external storage not working

First off, I want to specify that I do have
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
specified in my manifest, and I do check Environment.MEDIA_MOUNTED.
The really strange thing about this, in my opinion, is that it returns true, but it doesn't actually create the directories.
public static void downloadFiles(ArrayList<FileList> list) {
for (FileList file: list) {
try {
// This will be the download directory
File download = new File(downloadDirPatch.getCanonicalPath(), file.getPath());
// downloadDirPatch is defined as follows in a different class:
//
// private static String updateDir = "CognitionUpdate";
// private static File sdcard = Environment.getExternalStorageDirectory();
// final public static File downloadDir = new File(sdcard, updateDir);
// final public static File downloadDirPatch = new File(downloadDir, "patch");
// final public static File downloadDirFile = new File(downloadDir, "file");
if (DEV_MODE)
Log.i(TAG, "Download file: " + download.getCanonicalPath());
// Check if the directory already exists or not
if (!download.exists())
// The directory doesn't exist, so attempt to create it
if (download.mkdirs()) {
// Directory created successfully
Download.download(new URL(file.getUrl() + file.getPatch()), file.getPath(), file.getName(), true);
} else {
throw new ExternalStorageSetupFailedException("Download sub-directories could not be created");
}
else {
// Directory already exists
Download.download(new URL(file.getUrl() + file.getPatch()), file.getPath(), file.getName(), true);
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ie) {
ie.printStackTrace();
} catch (ExternalStorageSetupFailedException essfe) {
essfe.printStackTrace();
}
}
}
"if (download.mkdirs())" returns true, but when the app goes to actually download the file it throws a
FileNotFoundException: open failed: ENOENT (No such file or directory)
exception, and when I check for the directory afterwards on my phone, it doesn't exist.
Earlier in the program, the app sets up the parent download directory, and that all works fine using File.mkdir(), but File.mkdirs() doesn't seem to be working properly for me.
Your question does not give much detail about the FileNotFoundException. Check the path that triggers this. Forget what you think the path is, log it or run it through the debugger to see what it really is.
As per the directories not created correctly, verify (with your eyes) that the path is really what you think it is. I see you are already logging download.getCanonicalPath, do check in your logs what it really is.
Finally, is Download.download really saving stuff where you think it does? Before you call it you are preparing and verifying a directory using download, but then you are not using download when you call Download.download, so it's impossible to tell.
Btw, don't repeat yourself, you can rewrite without repeating the Download.download line:
if (!download.exists())
if (!download.mkdirs()) {
throw new ExternalStorageSetupFailedException("Download sub-directories could not be created");
}
}
Download.download(new URL(file.getUrl() + file.getPatch()), file.getPath(), file.getName(), true);

Categories

Resources