I'm trying to make a launcher for my Java desktop application (separated applications), which has to look for an updated version of the main application on the server. My idea is to store the app version inside of a text file on each side.
I found (thanks to Google san) the way to read the version from the text file and download the jar directory with all of it's content (both on server side). I'm using the Apache Commons Net FTP library btw.
The problem comes when I try to download the jar directory from the server after beeing reading the text file. I get the text file content correctly, the files download fails though.
If I switch code lines to download the stuff first and then read the text file, both of them works well, but we all know that's not the way an update check should be.
I've been looking and I don't get what I'm doing wrong. It's my first time working with this library.
This is the code I'm working with:
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
class FTPUtil{
private String server = "www.server.host";
private int port = 21;
private String user = "user";
private String pass = "password";
private FTPClient ftpClient = new FTPClient();
public void Connect() throws IOException{
ftpClient.connect(server, port);
ftpClient.login(user, pass);
ftpClient.enterLocalPassiveMode();
System.out.println("Connected");
}
public void Disconnect() throws IOException{
ftpClient.logout();
ftpClient.disconnect();
System.out.println("Disconnected");
}
public double getServerVersion(String remoteDirPath) throws IOException{
InputStream inputStream = ftpClient.retrieveFileStream(remoteDirPath + "/version.txt");
return Double.parseDouble(IOUtils.toString(inputStream, "UTF-8"));
}
public boolean downloadSingleFile(String remoteFilePath, String savePath) throws IOException{
File downloadFile = new File(savePath);
File parentDir = downloadFile.getParentFile();
if(!parentDir.exists())
parentDir.mkdir();
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(downloadFile));
try{
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
return ftpClient.retrieveFile(remoteFilePath, outputStream);
}catch(IOException e){
throw e;
}finally{
if(outputStream != null)
outputStream.close();
}
}
public void downloadDirectory(String parentDir, String currentDir, String saveDir) throws IOException{
String dirToList = parentDir;
if(!currentDir.equals(""))
dirToList += "/" + currentDir;
FTPFile[] subFiles = ftpClient.listFiles(dirToList);
if(subFiles != null && subFiles.length > 0){
for(FTPFile aFile : subFiles){
String currentFileName = aFile.getName();
// skip parent directory and the directory itself
if(currentFileName.equals(".") || currentFileName.equals(".."))
continue;
String filePath = parentDir + "/" + currentDir + "/" + currentFileName;
if(currentDir.equals(""))
filePath = parentDir + "/" + currentFileName;
String newDirPath = saveDir + parentDir + File.separator + currentDir + File.separator + currentFileName;
if(currentDir.equals(""))
newDirPath = saveDir + parentDir + File.separator + currentFileName;
if(aFile.isDirectory()){
// create the directory in saveDir
File newDir = new File(newDirPath);
boolean created = newDir.mkdirs();
if(created)
System.out.println("CREATED the directory: " + newDirPath);
else
System.out.println("COULD NOT create the directory: " + newDirPath);
// download the sub directory
downloadDirectory(dirToList, currentFileName, saveDir);
}else{
// download the file
boolean success = downloadSingleFile(filePath, newDirPath);
if(success)
System.out.println("DOWNLOADED the file: " + filePath);
else
System.out.println("COULD NOT download the file: " + filePath);
}
}
}
}
}
import java.io.IOException;
public class Main{
public static void main(String[] args){
String project = "ServerFolderName";
String remoteDirPath = "/" + project;
String saveDirPath = "C:/Users/username/Desktop";
FTPUtil ob = new FTPUtil();
try{
ob.Connect();
System.out.println(ob.getServerVersion(remoteDirPath));
ob.downloadDirectory(remoteDirPath, "", saveDirPath);
ob.Disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
}
And the console output:
run:
Connected
1.0
Exception in thread "main" org.apache.commons.net.ftp.parser.ParserInitializationException: Unknown parser type: 0.000 seconds (measured here), 37.12 Kbytes per second
at org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory.createFileEntryParser(DefaultFTPFileEntryParserFactory.java:170)
at org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory.createFileEntryParser(DefaultFTPFileEntryParserFactory.java:94)
at org.apache.commons.net.ftp.FTPClient.__createParser(FTPClient.java:3381)
at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:3338)
at org.apache.commons.net.ftp.FTPClient.listFiles(FTPClient.java:3016)
at generateupdateinfo.FTPUtil.downloadDirectory(FTPUtil.java:58)
at generateupdateinfo.Main.main(Main.java:13)
C:\Users\username\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)
Maybe I'm going the wrong way doing this launcher/updater, I'm open to suggestions and new ideas to achieve it.
Edit:
I noticed that it works if I renew the server connection with Disconnect()
and Connect()
after reading the text file and before downloading the files. I still feel should be another way, doesn't look quite good.
ob.Connect();
System.out.println(ob.getServerVersion(remoteDirPath));
ob.Disconnect();
ob.Connect();
ob.downloadDirectory(remoteDirPath, "", saveDirPath);
ob.Disconnect();
I found the problem. Apparently I just have to flush the server replies with ftpClient.completePendingCommand()
after reading the version from the text file. I still do not get why happens just with one of both processes though, I would like to understand.
Thanks!:)