I'm trying to upload a file to a restful - Jersey web service deployed on Tomcat server that is a receives uploaded files as multipart . It works fully correct on Windows OS but on Linux the file fails to save with no exception thrown from the following saving method :
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadProductImage(
#FormDataParam("file") final InputStream uploadedInputStream,
#FormDataParam("file") final FormDataContentDisposition cdh,
#FormDataParam("file") final FormDataBodyPart body
) {
FileManager fileManager = new FileManager();
String fileName;
try {
int read = 0;
byte[] bytes = new byte[1024];
OutputStream out = new FileOutputStream(new File("/home/files"));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
return Response.status(Response.Status.CREATED).entity(gson.toJson(cdh.getName())).build();
}
The multipart variable is already declared in the web.xml file as :
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
As seen in the code the target path is "/home/files".
I'm sure that the path exists and I already tried to change the owner of the target file to the tomcat group , and granted all the permissions to the path without any results.
I appreciate your help.
So after working on this I found out that file write fails or permission errors are not thrown as exceptions , the code would work normally , and in this case what can be done to solve this type of problem is the following:
Since the path is outside the war body it has to be indicated to within the server.xml file in the tomcat directory.
The directory group has to be same as Tomcat group , it can be changed through chgrp command in linux terminal.
Permission has to be granted to the directory's group using the chmod command in linux.
Related
I made a HTML server using com.sun.net.httpserver library. I want to send a jar file to the client to make them download it.
This method below actually make the client download the file:
#Override
public void handle(HttpExchange httpExchange) {
File file = new File("Test.jar");
try {
httpExchange.sendResponseHeaders(200, file.length());
OutputStream outputStream = httpExchange.getResponseBody();
Files.copy(file.toPath(), outputStream);
outputStream.close();
} catch (IOException exception) {
exception.printStackTrace();
}
}
but it sends the jar file as a zip. How do I get it to send it as a jar file instead? And is there a better way to send files?
Please try adding the following to get correct filename for the download:
httpExchange.getResponseHeaders().add("Content-Disposition", "attachment; filename=Test.jar");
You might also want do add the following to get the corrent content-type:
httpExchange.setAttribute(HTTPExchange.HeaderFields.Content_Type.toString(), "application/java-archive");
Please see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types for a listing of content-types for different suffixes.
I am trying to download the files from ftp server using java FTPClient and FTPFile classes(commons-net.jar).How do i conclude if the file is partial or full(i.e., file is completely uploaded or not) using those classes?
Probably you could use the storeFile method form the Apache FTPClient:
public boolean storeFile(String remote, InputStream local)
throws IOException
Stores a file on the server using the given name and taking input from
the given InputStream. This method does NOT close the given
InputStream. If the current file type is ASCII, line separators in the
file are transparently converted to the NETASCII format (i.e., you
should not attempt to create a special InputStream to do this).
Parameters:
remote - The name to give the remote file. local - The
local - InputStream from which to read the file.
Returns: True if successfully completed, false if not.
Please note the following link Apache FTPClient for more information.
A simple implementation that you could try, would be something like this:
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(server, port);
ftpClient.login(user, pass);
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// APPROACH #1: uploads first file using an InputStream
File firstLocalFile = new File("D:/Test/Projects.zip");
String firstRemoteFile = "Projects.zip";
InputStream inputStream = new FileInputStream(firstLocalFile);
System.out.println("Start uploading first file");
boolean done = ftpClient.storeFile(firstRemoteFile, inputStream);
inputStream.close();
if (done) {
System.out.println("The first file is uploaded successfully.");
}
...
}
Regards.
Just before starting to explain you my problem, I would like to share with you the libraries' versions that I use and the server:
javax.ws.rs-api: 2.0.1
jersey-container-servlet: 2.13
jersey-media-multipart: 2.13
jackson: 2.4.3
I also use Apache Tomcat Server version 7.0.55.
So I coded that below:
/**
* On the client side.
*/
public void uploadAFile() {
Client client = ClientBuilder.newBuilder()
.register(MultiPartFeature.class)
.build();
WebTarget target = null;
try {
target = client
.target("https://blo-bla.rhcloud.com/rest")
.path("v1").path("upload");
} catch (IllegalArgumentException | NullPointerException e) {
LOG_TO_CONSOLE.fatal(e, e);
LOG_TO_FILE.fatal(e, e);
}
Builder builder = target.request(MediaType.TEXT_PLAIN);
builder.header("Authorization",
getValidBasicAuthenticationStrEncrypted());
FormDataMultiPart form = new FormDataMultiPart();
form.field("anotherParam", "Bozo");
String fileName = "/Users/drizzy/Documents/Divx/CaseDepartFolder/sample.avi";
File file = new File(fileName);
form.bodyPart(new FileDataBodyPart("file", file,
MediaType.APPLICATION_OCTET_STREAM_TYPE));
Response response = builder.post(Entity.entity(form,
MediaType.MULTIPART_FORM_DATA_TYPE));
LOG_TO_CONSOLE.debug(response.getStatus());
LOG_TO_CONSOLE.debug(response.readEntity(String.class));
}
/**
* On the server side.
*/
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.TEXT_PLAIN)
public String uploadFile(#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition fileDisposition,
#FormDataParam("anotherParam") String str)
throws FileNotFoundException, IOException
{
System.out.println("str: " + str);
final String basePath = "/Users/drizzy/eclipse-workspace/tomcat7jbossews"
+ "/src/main/resources/uploads/";
final String fileName = fileDisposition.getFileName();
System.out.println(new StringBuilder().append("***** fileName ")
.append(fileName)
.toString());
final String filePath = new StringBuilder().append(basePath)
.append(fileName)
.toString();
System.out.println(filePath);
try (OutputStream fileOutputStream = new FileOutputStream(filePath)) {
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = fileInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, read);
}
}
return "File Upload Successfully !!";
}
Which generates these exceptions at the client side:
Java Heap space error
and
Java binding Exception: Already connected
So my question is to know if somebody could please provide me an example of code with a client using jersey-client V2.13 which uploads a big file from the client to the server? Or even could telling me what is wrong in my code above?
Note: I only want to use jersey-client version V2.13 for handling that problem, so please do not provide me solutions using third party libraries or which do not use jersey-client version V2.13.
Finally I have found a solution to my problem:
1 - For fixing the "Already connected" Exception.
Java 7 introduced SNI support which is enabled by default. I have found out that certain misconfigured servers send an "Unrecognized Name" warning in the SSL handshake which is ignored by most clients... except for Java. As #Bob Kerns mentioned, the Oracle engineers refuse to "fix" this bug/feature.
As workaround, they suggest to set the jsse.enableSNIExtension property. To allow your programs to work without re-compiling, run your app as:
"-Djsse.enableSNIExtension=false"
Source of this information here.
The property can also be set in the Java code, but it must be set before any SSL actions. Once the SSL library has loaded, you can change the property, but it won't have any effect on the SNI status. To disable SNI on runtime (with the aforementioned limitations), use:
System.setProperty("jsse.enableSNIExtension", "false");
2 - For fixing the chunkedTransferMode's activation and java heap space error.
Java heap space error: I had to increase the jvm memory used by the client:
For doing that In eclipse, go to Run > Run Configurations ... > Select the client class > Arguments > VM arguments:
-Xms1024m -Xmx2500m -XX:+PrintFlagsFinal
Sources that I used myself for fixing that problem: source 1, source 2, source 3.
Regarding the fact of enabling the chunkedTransferMode, I did not need to do that, because I found in the documentation of jersey-client that the chunkedTransferMode was enabled by default in jersey-client V2.13.
In the end we pass these parameters to the JVM at the client side:
"-Djsse.enableSNIExtension=false" "your classes ..." -Xms1024m -Xmx2500m -XX:+PrintFlagsFinal
Ok it seems that the problem is a really large file (350Mb) and you are hitting various limits. Therefore I would suggest to address the problem in a different way.
Possible solutions:
Split the file on the client and upload it via "smaller" parts to the server where it is assembled back in original order.
Stream a file to the server: http://commons.apache.org/proper/commons-fileupload/streaming.html
I would prefer the 2. solution as it is probably the easiest to implement.
Hope this helps.
I am using spring MVC with REST service for one of my project. I am having a service to attach and download user files.
I am using below service API for upload and save file into server directory
http://myrestserver/attachmentService/attach/userKey
And below service API for download files from server directory
http://myrestserver/attachmentService/download/userKey/fileKey
The issue is that when a file is downloaded, the downloaded URL shows the REST service API URL. To avoid this, I thought of write a controller for attach and download file.
I wrote a spring controller which handle file attachment process. Even I wrote a controller(say download.do) for download a file, but when a file downloaded, the file name shows as the same name of the controller(downloaded file name shows "download.do" always) instead of original file name.
Below code is from my download.do controller
WebResource resource = null;
resource = client.resource("http://myrestserver/attachmentService/download/userKey/fileKey");
clientResponse = resource.accept(MediaType.APPLICATION_OCTET_STREAM).get(
ClientResponse.class);
InputStream inputStream = clientResponse.getEntityInputStream();
if(inputStream != null){
byteArrayOutputStream = new ByteArrayOutputStream();
try {
IOUtil.copyStream(inputStream, byteArrayOutputStream);
} catch (IOException e) {
log.error("Exception in download:"+ e);
}
}
And, in my service API, the code is
file = new File(directory, attachmentFileName);
fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(attachmentContent);
fileOutputStream.close();
response = Response.ok((Object) file).type(MediaType.APPLICATION_OCTET_STREAM);
response.header("Content-Disposition", "attachment; filename=" + "\"" + attachmentFileName
+ "\"");
return response.build();
By analyzing the issue, I understood that, am not setting file header in downloaded file through download.do controller.
If I am using outstream in download.do controller, I will not be able to set the file header.
Can any one help me to resolve this issue. My primary aim is to hide my rest service URL from downloaded file by stream through a MVC controller.
I found a post (Downloading a file from spring controllers )in stack overflow almost like my question, but the file type is previously known. Please note that, in my application user can attach any type of file.
You have to set the Content-Disposition prior to writing the file to the output stream. Once you start writing to the output stream, you cannot set headers any longer.
I'm writing code to read a file from an FTP URL in order to parse it and store the data in Google App Engine's Datastore. I'm able to get the code working fine when reading test files hosted on my own web server, however when I try to read the data file I need I'm getting a FileNotFoundException.
I'm able to use the same FTP URL in a browser to download the file, and can anonymously connect to the FTP URL in FileZilla, so access shouldn't be a problem, and the file is definitely there. It's a pretty big file, but I've tried to grab smaller files from the same FTP server with no luck either.
Here's the code I have at the moment:
public void doGet(HttpServletRequest req,
HttpServletResponse resp) throws IOException, ServletException {
// works with a URL to my own server & a test.zip, but not this one
final URL url = new URL(
"ftp://gisftp.metc.state.mn.us/google_transit.zip");
// without the privileged action, I get an AccessControlException
ZipInputStream zin = AccessController.doPrivileged(
new PrivilegedAction<ZipInputStream>() {
public ZipInputStream run() {
return getZipStream(url);
}
}
);
ZipEntry zipentry = zin.getNextEntry();
// processing files here
zin.close();
}
// but using the privileged method, we get a FileNotFoundException
public ZipInputStream getZipStream(URL url) {
ZipInputStream zipin = null;
try {
zipin = new ZipInputStream(url.openStream());
} catch (IOException e) {
e.printStackTrace();
}
return zipin;
}
At first I was getting an AccessControlException, but using a PrivilegedAction to open the stream seems to fix that.
I don't have access to the server where the file is stored, so can't change anything there.
I think there is a restriction on the ports that can be connected to from App Engine and FTP (21) is not in the list, this maybe causing the issue. From the URL Fetch documentation;
An app can fetch a URL using HTTP (normal) or HTTPS (secure). The URL specifies the scheme to use: http://... or https://...
The URL to be fetched can use any port number in the following ranges: 80-90, 440-450, 1024-65535. If the port is not mentioned in the URL, the port is implied by the scheme: http://... is port 80, https://... is port 443.