Issue while downloading a file from a WEB FTP using Java? - java

I have been having an issue while downloading a file from a Web Ftp through a Java program using Apache Commons Net.
Let's say I want to download this file : webftp.vancouver.ca/opendata/bike_rack/BikeRackData.csv
This is not a file you will be able to download via an HTTP request. I can do it with my browser because I'm using a FTP plugin.
It appears that the traditionnal way to retrieve files from a FTP server doesn't work with that particuliar type (Web FTP). I can establish the connection, but the file retrieval doesn't work as the file is empty.
The code I used (classic way to retrieve a file using Apache Commons) is the following :
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory;
public class FTPDownload {
final private FTPClient ftp = new FTPClient();
private String input;
private String server;
private String path;
private String destination;
private String fileName;
public FTPDownload(String input, String destination) {
this.input = input;
this.destination = destination;
if (input != null && input.contains("/")) {
String[] elts = input.split("/");
server = elts[0];
fileName = elts[elts.length - 1];
path = input.substring(server.length() - 1);
} else {
server = input;
path = null;
}
}
public FTPDownload(String server, String path, String destination) {
this.server = server;
this.path = path;
this.destination = destination;
if (path != null && path.contains("/")) {
String[] elts = path.split("/");
fileName = elts[elts.length - 1];
}
}
public boolean retrieveFile() throws IOException {
boolean error = false;
ftp.connect(server);
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return false;
}
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.enterRemotePassiveMode();
File download = new File(destination + "/" + fileName);
OutputStream outputStream;
outputStream = new FileOutputStream(download);
ftp.changeWorkingDirectory(path.substring(0, path.length() - fileName.length()));
ftp.setParserFactory(new DefaultFTPFileEntryParserFactory());
String[] list = ftp.listNames();
ftp.retrieveFile(fileName, outputStream);
outputStream.close();
ftp.logout();
return error;
}
public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
FTPDownload myFtp = new FTPDownload("webftp.vancouver.ca", "/opendata/bike_rack/BikeRackData.csv", "E:\\test");
myFtp.retrieveFile();
}
}
Hope the problem is understandable.
Thank you.

Related

Web server hanging. I have no idea why

I'm writing a very tiny, very sh*tty web server just for fun. It was working fine with GET requests or returning a 404. And worked very briefly working with POST requests. And now it just hangs on any POST request.
Here is the relevant bit of code. As you can see I put in some logging to both System.out and to a file. The logging to System.out works, but the logging to file never happens. If I remove the logging to file, it still hangs on the line after System.out log. I included the few lines previous so you can see that it is the exact same code as returning a 404. 404 works, but POST doesn't. This is using a ServerSocket. I'm at a complete loss at this point. Would appreciate any insight.
Edit: Have included the main and sendResponse methods in case there is anything in there that might be causing this.
Edit #2: Ima just post the whole thing.
package beerio;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class Beerio {
public static void main( String[] args ) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(80)) {
while (true) {
try (Socket client = serverSocket.accept()) {
handleClient(client);
}
catch(Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
BufferedWriter writer = new BufferedWriter(new FileWriter("errorlog.txt", true));
writer.append(System.lineSeparator());
writer.append(sw.toString());
writer.append(System.lineSeparator());
writer.close();
continue;
}
}
}
}
private static void handleClient(Socket client) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
//make request into string. this only parses until the first blank line
StringBuilder requestBuilder = new StringBuilder();
String line;
while (!(line = br.readLine()).isBlank()) {
requestBuilder.append(line + "\r\n");
}
//split string and parse into request info
String request = requestBuilder.toString();
String[] requestsLines = request.split("\r\n");
String[] requestLine = requestsLines[0].split(" ");
String method = requestLine[0];
String path = requestLine[1];
String version = requestLine[2];
String host = requestsLines[1].split(" ")[1];
List<String> headers = new ArrayList<>();
for (int h = 2; h < requestsLines.length; h++) {
String header = requestsLines[h];
headers.add(header);
}
//rest of request contains post info. parse that here
if(method.equals("POST")) {
String parameters;
parameters = br.readLine();
String[] temp = parameters.split("&");
String[][] params = new String[temp.length][2];
for(int i=0; i<temp.length; i++) {
params[i][0] = temp[i].substring(0,temp[i].indexOf("="));
params[i][1] = temp[i].substring(temp[i].indexOf("=")+1);
}
}
Path filePath = getFilePath(path);
if (method.equals("GET")) {
System.out.println("doGet");
if (Files.exists(filePath)) {
// file exist
String contentType = guessContentType(filePath);
sendResponse(client, "200 OK", contentType, Files.readAllBytes(filePath));
} else {
// 404
byte[] notFoundContent = "<h1>Not found :(</h1>".getBytes();
sendResponse(client, "404 Not Found", "text/html", notFoundContent);
}
} else if(method.equals("POST")){
byte[] postContent = "<h1>POST Failed Successfully</h1>".getBytes();
sendResponse(client, "200 OK", "text/html", postContent);
}
}
private static void sendResponse(Socket client, String status, String contentType, byte[] content) throws IOException {
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("HTTP/1.1 " + status+"/r/n").getBytes());
clientOutput.write(("ContentType: " + contentType + "\r\n").getBytes());
clientOutput.write("\r\n".getBytes());
clientOutput.write(content);
clientOutput.write("\r\n\r\n".getBytes());
clientOutput.flush();
client.close();
}
private static Path getFilePath(String path) {
if ("/".equals(path)) {
path = "\\index.html";
}
return Paths.get("C:\\Users\\shawn\\beerio\\beerio\\tmp\\www", path);
}
private static String guessContentType(Path filePath) throws IOException {
return Files.probeContentType(filePath);
}
}

Spring Boot Unit Testing

I'm currently developing a Rest service in Spring Boot and am attempting to develop unit tests. My Rest controller takes the request and utilizes an Sftp Connector defined within another package to directly interface with our servers. I've defined my test cases to mock the behavior of the Sftp Connector rather than have it execute with the mock data being fed into the Rest endpoints. I've been getting a ton of error logs during testing showing that exceptions are being raised from the Sftp connector. Which makes sense if the mock data sent to the endpoints is still being fed into the connector class. I'm guessing that I'm not mocking the connector properly. I've been unsuccessful so far in locating a method to mock the connector. Is this possible? Or can I only mock the classes defined within the same package as the test class?
Controller:
package RestAPI;
import JSch.SFTP.SftpConnector;
import JSch.SFTP.fileInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
#RestController
#Api( value = "Test Rest Controller", description = "Basic test for SFTP
connector with very basic operations.")
public class SftpRestController {
private Properties getProperties(){ //used to get connection values from
external file
InputStream input = null;
Properties prop = new Properties(); //new property
try{
if(System.getProperty("os.name").contains("Windows")){
input = new FileInputStream("C:\\tmp\\application.properties"); //get resources stream
}
else{
input = new FileInputStream("application.properties");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
while((line = reader.readLine()) != null){
String[] split = line.split("=");
prop.put(split[0], split[1]);
}
}catch(IOException IO){
IO.printStackTrace();
}finally{
if(input != null )
try{
input.close(); //close the stream
}catch(IOException IO2){
IO2.printStackTrace();
}
}
System.out.println(prop.getProperty("sftp.port"));
return prop;
}
#ApiOperation(value = "Check that service is up and running.", response = String.class)
#RequestMapping("/")
public #ResponseBody String index(){ return "Rest Test Service is up and running";}
#ApiOperation(value = "Upload a file", response = String.class)
#PostMapping(value="/Upload") //uploads files so long as the files are defined in one structure in the form body
public #ResponseBody String multipartUpload(#RequestBody MultipartFile[] files, #RequestParam("dest") String dest){
String fileMessage = ""; //need something to send back to the caller
SftpConnector connector = new SftpConnector(this.getProperties()); //plugs properties into the constructor and opens a connection
for( int i = 0; i < files.length; i++ ){ //for each file uploaded
connector.uploadFile(files[i], dest); //call the upload method with the file reference and where it's going
fileMessage = fileMessage + files[i].getOriginalFilename() + " has been uploaded to remote directory \n";
}
connector.closeSFTPConnection(); //manually close the connection
return fileMessage;
}
#ApiOperation(value = "Downloads a file over SFTP and writes it to local file system specified", response = String.class)
#GetMapping(value="/Download")
public #ResponseBody String downloadFile(#RequestParam("fileName") String fName, #RequestParam("dest") String dest){
SftpConnector connector = new SftpConnector(this.getProperties()); //new connector
connector.downloadFile(fName, dest); //pull the specified file down
connector.closeSFTPConnection(); //close the connection
return fName + " has been downloaded to the specified local directory";
}
#ApiOperation(value = "Moves all files on a remote server from one directory to another based on file type specified", response = String.class)
#PutMapping(value="/moveFiles")
public #ResponseBody String moveFiles(#RequestParam("dir") String origin, #RequestParam("fileType") String type,#RequestParam("dest") String dest){
SftpConnector connector = new SftpConnector(this.getProperties());
connector.moveFiles(origin, type, dest); //moves a group of files based file type from one directory to another
connector.closeSFTPConnection();
return "All files have been moved.";
}
#ApiOperation(value = "Moves a single specific file", response = String.class)
#GetMapping(value="/moveFile")
public #ResponseBody String moveFile(#RequestParam("dir") String origFile, #RequestParam("dest") String dest){
SftpConnector connector = new SftpConnector(this.getProperties());
connector.moveFile(origFile, dest); //moves a single file. file name must be specified.
connector.closeSFTPConnection();
return FilenameUtils.getName(origFile) + " has been moved to " + dest;
}
#ApiOperation(value = "Gets a specified file stream and returns it as a string", response = String.class)
#GetMapping(value="/readFile")
public #ResponseBody String readFile(#RequestParam("path") String path){
String fileContents;
try{
SftpConnector connector = new SftpConnector(this.getProperties());
InputStream fis = connector.readFile(path); //gets an open file stream
fileContents = IOUtils.toString(fis,"UTF-8"); //takes a file stream, reads into variable in specified encoding
fis.close(); //closes the stream
connector.closeSFTPConnection();
}catch(IOException IO){
fileContents = IO.toString();
}
return fileContents;
}
#ApiOperation(value="Returns a list of file names as a string", response = String.class)
#GetMapping(value="/listFiles")
public #ResponseBody String fileNames(#RequestParam("dir") String origin, #RequestParam("fileType") String type){
String base = "";
try{
SftpConnector connector = new SftpConnector(this.getProperties());
Collection<fileInfo> files = connector.listFiles(origin, type); //gets a list of files with name, type, and an input stream
Iterator<fileInfo> iterator = files.iterator(); //iterator to roll over collection
while(iterator.hasNext()){ //while not empty
fileInfo thisFile = iterator.next(); //get the next fileInfo
base = base + thisFile.getName() + '\n' ; //write the name to the base string
thisFile.getFileStream().close(); //close the file stream
}
connector.closeSFTPConnection();
}catch(Exception ex){
ex.printStackTrace();
}
return base;
}
#ApiOperation(value = "Moves a file by the connectors readFile and writeFile methods rather than SFTP rename", response = String.class)
#GetMapping(value="/test")
public #ResponseBody String StreamTest(#RequestParam("file") String file, #RequestParam("dest") String dest){
SftpConnector connector = new SftpConnector(this.getProperties());
connector.writeFile(dest, FilenameUtils.getName(file), connector.readFile(file));
connector.closeSFTPConnection();
return file + " has been successfully read, and written to destination";
}
}
Sftp Connector:
package JSch.SFTP;
import com.jcraft.jsch.*;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.*;
#Component
public class SftpConnector {
private String sftpHost;
private String sftpUser;
private int sftpPort;
private String sftpPass;
private Session session = null;
private ChannelSftp channelSftp = null;
public String getSftpHost() {
return sftpHost;
}
public void setSftpHost(String sftpHost) {
this.sftpHost = sftpHost;
}
public String getSftpUser() {
return sftpUser;
}
public void setSftpUser(String sftpUser) {
this.sftpUser = sftpUser;
}
public int getSftpPort() {
return sftpPort;
}
public void setSftpPort(int sftpPort) {
this.sftpPort = sftpPort;
}
public String getSftpPass() {
return sftpPass;
}
public void setSftpPass(String sftpPass) {
this.sftpPass = sftpPass;
}
public void setConnectionVars(String host, String user, String password, int port){
this.setSftpHost(host);
this.setSftpPort(port);
this.setSftpUser(user);
this.setSftpPass(password);
}
public SftpConnector(Properties prop){
this.setConnectionVars(prop.getProperty("sftp.host"), prop.getProperty("sftp.user"), prop.getProperty("sftp.pass"), Integer.parseInt(prop.getProperty("sftp.port"))); //set the connection variables
this.openSFTPConnection(); //open the sftp connection
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
public ChannelSftp getChannelSftp() {
return channelSftp;
}
public void setChannelSftp(ChannelSftp channelSftp) {
this.channelSftp = channelSftp;
}
public void openSFTPConnection(){
try{
JSch jsch = new JSch(); //create the new JSch var
Session baseSession = jsch.getSession(this.getSftpUser(), this.getSftpHost(),this.getSftpPort()); //establish the ssh session info
baseSession.setPassword(this.getSftpPass()); //auth over password
baseSession.setConfig("StrictHostKeyChecking","no"); // don't require hosting key check will need to change after testing
baseSession.setConfig("PreferredAuthentications","password"); //used to omit kerberos authentication
this.setSession(baseSession); //set the session to private variable
this.getSession().connect(); //open the session
ChannelSftp tempChannel = (ChannelSftp) this.getSession().openChannel("sftp"); //create an SFTP channel
this.setChannelSftp(tempChannel); //set the channel to the private variable
this.getChannelSftp().connect(); //open the SFTP connection
}catch(JSchException e){
e.printStackTrace();
}
}
public void closeSFTPConnection(){
try{
if(this.getChannelSftp().isConnected()){ //if the channel is open so must be the session close both
this.getChannelSftp().disconnect();
this.getSession().disconnect();
}else{ //if the channel is closed check to see if the session is still open
if(this.getSession().isConnected()){
this.getSession().disconnect();
}
}
}catch(Exception e){
e.printStackTrace();
}
}
public Collection<fileInfo> listFiles(String dir, String filter){
Collection<fileInfo> files = new ArrayList<fileInfo>();
try{
if(this.getChannelSftp() == null || !this.getChannelSftp().isConnected()) //make sure that the JSch sessions been opened.
this.openSFTPConnection();
this.getChannelSftp().cd(dir); //set the working directory
Vector<ChannelSftp.LsEntry> fileList = this.getChannelSftp().ls(filter); //Get a listing of the files in the directory depending on a filter
Iterator<ChannelSftp.LsEntry> iterator = fileList.iterator(); //iterate over the collection
while(iterator.hasNext()) {
ChannelSftp.LsEntry entry = iterator.next();
fileInfo thisFile = new fileInfo(entry.getFilename(), entry.getAttrs().getAtimeString(), FilenameUtils.getExtension(entry.getFilename()), this.getChannelSftp().get(entry.getFilename())); //get a buffered input stream for each file.
files.add(thisFile);
}
}catch(SftpException e){
e.printStackTrace();
}
return files;
}
public InputStream readFile(String filePath){ //built to read get a file stream from a given file path
InputStream inputStream = null;
try{
if(this.getChannelSftp() == null || !this.getChannelSftp().isConnected()) //if the channel isn't open, open it.
this.openSFTPConnection(); //open connection
inputStream = this.getChannelSftp().get(filePath); //get the stream
}catch(SftpException ex){
ex.printStackTrace();
}
return inputStream;
}
public String uploadFile(MultipartFile file, String dest){
try{
System.out.println(this.getSession().getConfig("FileUploadBaseSizeLimit"));
if(this.getChannelSftp() == null || !this.getChannelSftp().isConnected()) //if not connected open the connection
this.openSFTPConnection();
this.getChannelSftp().cd(dest); //set working dir
this.getChannelSftp().put(file.getInputStream(), dest + '/' + file.getOriginalFilename()); //get the input stream from the multipart file and put it in the destination
}catch(IOException IO){
IO.printStackTrace();
}catch(SftpException sftp){
sftp.printStackTrace();
}
return file.getOriginalFilename() + " has been uploaded";
}
public String downloadFile(String orig, String dest){
try{
if(this.getChannelSftp() == null || !this.getChannelSftp().isConnected()) //if not connected
this.openSFTPConnection();
File download = new File(dest + '/' + FilenameUtils.getName(orig)); //create a new local file
OutputStream outputStream = new FileOutputStream(download); //generate an output stream to the file
byte[] buffer = new byte[10000000]; //10MB buffer instance
BufferedInputStream bufferedInputStream = new BufferedInputStream(this.getChannelSftp().get(orig)); //create a buffered input stream off the input stream from the ssh get
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); // and a buffered output stream off the output stream we created
int readCount; //integer link to the buffer
while((readCount = bufferedInputStream.read(buffer)) > 0){ //read the buffered input stream into the buffer. while it's not empty...
bufferedOutputStream.write(buffer, 0, readCount); //write the buffer to the output stream
}
bufferedInputStream.close(); //close the streams
bufferedOutputStream.close();
outputStream.close();
}catch(IOException IO){
IO.printStackTrace();
}catch(SftpException sftp){
sftp.printStackTrace();
}
return "File " + FilenameUtils.getName(orig) + " has been downloaded."; //return that we've successfully uploaded the file
}
public void writeFile(String dir, String fileName, InputStream fileIS) { //writes a file given the destination directory, fileName, and an input stream
try{
if(this.getChannelSftp() == null || !this.getChannelSftp().isConnected() ) //if the connection isn't already open, open it
this.openSFTPConnection();
this.getChannelSftp().cd(dir); //set the working dir for better shorthand
this.getChannelSftp().put(fileIS, fileName); //put the file.
fileIS.close(); //close the file stream
}catch(SftpException e){
e.printStackTrace();
}catch(IOException IO){
IO.printStackTrace();
}
}
public void moveFile(String path, String dest){
try{
if(this.getChannelSftp() == null || !this.getChannelSftp().isConnected()){ //open connection if not done already
this.openSFTPConnection();
}
this.getChannelSftp().rename(path, dest + '/' + FilenameUtils.getName(path)); //ssh command to move the file.
}catch(SftpException e){
e.printStackTrace();
}
}
public String moveFiles(String dir, String filter, String dest){
try{
if(this.getChannelSftp() == null || !this.getChannelSftp().isConnected()){ //open if not done already
this.openSFTPConnection();
}
Collection<fileInfo> files = this.listFiles(dir, filter); //invoke the listFiles method and convert to an array
Iterator<fileInfo> iterator = files.iterator(); //iterator
while( iterator.hasNext()){ //while there is another value in the collection
fileInfo thisFile = iterator.next(); // have to store the fileInfo somewhere. can't just keep calling next.
this.getChannelSftp().rename(dir + '/' + thisFile.getName(), dest + '/' + thisFile.getName());
}
this.closeSFTPConnection(); //close the connection
}catch(Exception ex){
ex.printStackTrace();
}
return "all files moved";
}
}
Test Class:
package RestAPI;
import JSch.SFTP.SftpConnector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.io.FileInputStream;
import java.io.InputStream;
#RunWith(SpringRunner.class)
#WebMvcTest(value = SftpRestController.class, secure = false)
public class SftpRestUnitTest {
#Autowired
private MockMvc mockMvc;
#MockBean
SftpConnector connector ;
#Test
public void testFileUpload() throws Exception{
MockMultipartFile testFile1 = new MockMultipartFile("data", "WSUID1.csv", "application/csv", "some xml".getBytes());
Mockito.when(
connector.uploadFile(Mockito.any(),Mockito.anyString())
).thenReturn("WSUID1.csv has been uploaded");
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.multipart("/Upload").file(testFile1).param("dest", "/tmp/test")).andReturn();
System.out.println(result.getResponse().getContentAsString());
assert result.getResponse().getContentAsString().equals("WSUID1.csv has been uploaded to remote directory \n");
}
#Test
public void testDownload() throws Exception{
String expected = "TestFile.csv has been downloaded to the specified local directory";
Mockito.when(
connector.downloadFile(Mockito.anyString(), Mockito.anyString())
).thenReturn("File TestFile.csv has been downloaded.");
RequestBuilder request = MockMvcRequestBuilders.get("/Download").param("fileName","/tmp/TestFile.csv").param("dest", "/tmp");
MvcResult result = mockMvc.perform(request).andReturn();
System.out.println(result.getResponse().getContentAsString());
assert result.getResponse().getContentAsString().equals(expected);
}
#Test
public void testMoveFiles() throws Exception{
Mockito.when(
connector.moveFiles(Mockito.anyString(),Mockito.anyString(),Mockito.anyString())
).thenReturn("all files moved");
RequestBuilder request = MockMvcRequestBuilders.put("/moveFiles").param("dir","/IB_Test").param("fileType", "*.csv").param("dest", "/InternatlPgms/INTO/Archive/Receipt");
MvcResult result = mockMvc.perform(request).andReturn();
System.out.println(result.getResponse().getContentAsString());
assert result.getResponse().getStatus() == 200;
}
#Test
public void testReadFile() throws Exception{
String expected = "greetings from java test";
InputStream mockStream = Mockito.mock(FileInputStream.class);
Mockito.when(
connector.readFile(Mockito.anyString())
).thenReturn(mockStream);
RequestBuilder request = MockMvcRequestBuilders.get("/readFile").param("path", "IB_Test");
MvcResult result = mockMvc.perform(request).andReturn();
System.out.println(result.getResponse().getContentAsString());
assert result.equals(expected);
}
}
Error Logs:
The specified file is a directory.
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:1337)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:1290)
at JSch.SFTP.SftpConnector.readFile(SftpConnector.java:133)
at RestAPI.SftpRestController.readFile(SftpRestController.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:166)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
Any help is greatly appreciated.
You create a new instance of SftpConnector in every method of your controller. It is not an injected bean so it won't be replaced with your mock.
For an example have a look at this article (section 5):
https://www.baeldung.com/spring-boot-testing

Read from file inside Eclipse Project

I want to make an application that splits a big text file inside inputfolder into several small XML files to be put inside outputfolder.
This is project outline:
The following code works fine when it comes to getting a file from an outside folder, but when I modified it to read from a folder inside the project, it gave me this error:
Exception in thread "main" java.lang.NullPointerException
at com.zakaria.cut.XmlCutter.cut(XmlCutter.java:45)
at com.zakaria.cut.Main.main(Main.java:8)
[XmlCutter.java]
package com.zakaria.cut;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.MessageFormat;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class XmlCutter {
private static final String OUTPUT_FILE_NAME = "/file";
//private static String USER_HOME = System.getProperty("user.home");
private static final String INPUT_FOLDER = "../inputfolder";
private static String OUTPUT_FOLDER = "../outputfolder";
private static Logger LOG = Logger.getLogger("XmlCutter");
private static long COUNTER = 0;
public XmlCutter() {
super();
// TODO Auto-generated constructor stub
}
public void cut() {
Handler h = new ConsoleHandler();
h.setLevel(Level.FINE);
LOG.addHandler(h);
LOG.setLevel(Level.FINE);
File inputDir = new File(INPUT_FOLDER);
File[] filesInInputDir = inputDir.listFiles();
for (File f : filesInInputDir) {
if ((f.getName()).endsWith(".txt")) {
LOG.fine((MessageFormat.format(
"Found a text file {0}. Processing docs...",
f.getName())));
processFile(f);
}
}
}
private static void processFile(File f) {
StringBuilder out = new StringBuilder();
char prev = '#';
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(f), "UTF8"));
char[] buf = new char[1];
while (br.read(buf) >= 0) {
out.append(buf[0]);
if (prev == '<' && buf[0] == '?') {
LOG.finest((MessageFormat.format(
"Start of XML PI Found: {0}{1}", prev, buf[0])));
if (out.length() > 2) {
flushToFile(out.substring(0, out.length() - 2));
}
out.setLength(2);
}
prev = buf[0];
}
LOG.finest("Writing final file");
flushToFile(out.toString());
br.close();
} catch (IOException e) {
LOG.fine(e.getMessage());
}
LOG.fine(MessageFormat.format("Generated {0} XML Documents", COUNTER));
}
private static void flushToFile(String s) {
File f = new File(OUTPUT_FOLDER + OUTPUT_FILE_NAME + (++COUNTER)
+ ".xml");
LOG.finest(MessageFormat.format("Writing file: {0}", f.getName()));
try {
FileOutputStream fos = new FileOutputStream(f);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
osw.write(s);
osw.flush();
} catch (IOException e) {
LOG.fine(e.getMessage());
}
}
}
[Main.java]
package com.zakaria.cut;
public class Main {
public static void main(String[] args) {
XmlCutter cutter = new XmlCutter();
cutter.cut();
}
}
The problem, I guess, is definitely here:
private static final String INPUT_FOLDER = "../inputfolder";
private static String OUTPUT_FOLDER = "../outputfolder";
How can I fix it?
Do you know what folder the program is executing from? My guess is the relative links are pointing to the wrong spot? Have you tried hard coding the paths and see if they work? If they do you might have to look at the your execution folder and then change the relative paths accordingly?

Adding ADB to my Java PC application

I have developed a Java application. The application connects to an android device programmatically to transfer some files to connects Android devices.
In my application I have added the adb PATH so it can use it to connect to devices.
I was wondering if its possible to maybe package it within the application ? or just copying the adb into the application directory ? Because I want who ever to download this application, wouldn't need to also have download the adb or Android sdk for the application to work
Is it possible ?
After doing some research you can package an exe within a jar file but you have to extract the exe each run of the application. Following TofuBear's example here I was able to encapsulate adb within a jar file. You'll need to include the AdbWinApi.dll (or equivalent linux libraries).
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class Sandbox
{
public static void main(final String[] args)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI exe;
uri = getJarURI();
// Extract the adb application
exe = getFile(uri, "adb.exe");
// Extract the AdbWinApi dll file.
getFile(uri, "AdbWinApi.dll");
System.out.println(exe);
}
private static URI getJarURI()
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = Sandbox.class.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
//tempFile = File.createTempFile(fileName, Long.toString(System.currentTimeMillis()));
tempFile = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName);
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}
I had to change the file creation from TofuBear's example so that the file name of the exe would not be changed. It's still created in the temporary folder and will be deleted on exit. I left the original code as a comment.
Edit: Seems I got so caught up with the technical possiblity of it I forgot the legal ramifications. It's been stated here by Chris Stratton that the SDK Terms of Service prohibits redistribution of any part of the sdk. Which would include adb.
It should be easier to use the Java-native chimpchat to connect to the device.

How do I send Http trailers/footers in a chunked response from within a java servlet?

Basically my response headers contain
Transfer-encoding=chunked,
Trailer=[some trailer I want to send say e.g "SomeTrailer"]
Once I'm done writing the data to the Servlet outputstream, I'm writing the trailer
"SomeTrailer:[value]", but this is not being parsed by the httpclient correctly.
The httpclient considers the whole of inputstream (including the trailer) as a single
chunk.
I've also tried writing the trailer in a response header after the data has been written to the outputstream but without success.
Please help
I haven't found any good sources on this.
I ended up writing a simple single threaded webserver for this. Turned out it was quite easy. The server is pretty simple. The code's a bit rough though, but the main idea is there.
What it does it sends the filecontents as the first chunk and the checksum of the file as a footer.
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
public class ChunkedResponseServer implements Runnable {
private static final Logger LOGGER = Logger.getLogger(ChunkedResponseServer.class);
// Space ' '
static final byte SP = 32;
// Tab ' '
static final byte HT = 9;
// Carriage return
static final byte CR = 13;
// Line feed character
static final byte LF = 10;
final int port;
private volatile boolean cancelled = false;
public ChunkedResponseServer(int port) {
LOGGER.info("Chunked response server running on port " + port);
this.port = port;
}
#Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
while (!cancelled) {
final Socket connectionSocket = serverSocket.accept();
handle(connectionSocket);
}
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
public void cancel() {
LOGGER.info("Shutting down Chunked response Server");
cancelled = true;
}
private void handle(Socket socket) throws IOException {
BufferedReader input = null;
DataOutputStream output = null;
try {
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new DataOutputStream(socket.getOutputStream());
addHeaders(output);
addCRLR(output);
final String filename = readFilename(input);
final byte[] content = readContent(filename);
addContentAsChunk(output, content);
final String checksum = DigestUtils.md5Hex(content);
addLastChunkAndChecksumFooter(output, checksum);
addCRLR(output);
} finally {
IOUtils.closeQuietly(input);
IOUtils.closeQuietly(output);
}
}
private void addLastChunkAndChecksumFooter(DataOutputStream output, String checksum) throws IOException {
output.writeBytes("0");
addCRLR(output);
output.writeBytes("checksum: " + checksum);
addCRLR(output);
}
private void addContentAsChunk(DataOutputStream output, byte[] content) throws IOException {
output.writeBytes(Integer.toHexString(content.length));
addCRLR(output);
output.write(content);
addCRLR(output);
}
private void addCRLR(DataOutputStream output) throws IOException {
output.writeByte(CR);
output.writeByte(LF);
}
private void addHeaders(DataOutputStream output) throws IOException {
output.writeBytes("HTTP/1.1 200 OK");
addCRLR(output);
output.writeBytes("Content-type: text/plain");
addCRLR(output);
output.writeBytes("Transfer-encoding: chunked");
addCRLR(output);
output.writeBytes("Trailer: checksum");
addCRLR(output);
}
private String readFilename(BufferedReader input) throws IOException {
final String initialLine = input.readLine();
final String filePath = initialLine.split(" ")[1];
final String[] components = filePath.split("/");
return components[components.length - 1];
}
private byte[] readContent(String filename) throws IOException {
final InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
return IOUtils.toByteArray(in);
}
}

Categories