How To Modify The Raw XML message of an Outbound CXF Request? - java

I would like to modify an outgoing SOAP Request.
I would like to remove 2 xml nodes from the Envelope's body.
I managed to set up an Interceptor and get the generated String value of the message set to the endpoint.
However, the following code does not seem to work as the outgoing message is not edited as expected. Does anyone have some code or ideas on how to do this?
public class MyOutInterceptor extends AbstractSoapInterceptor {
public MyOutInterceptor() {
super(Phase.SEND);
}
public void handleMessage(SoapMessage message) throws Fault {
// Get message content for dirty editing...
StringWriter writer = new StringWriter();
CachedOutputStream cos = (CachedOutputStream)message.getContent(OutputStream.class);
InputStream inputStream = cos.getInputStream();
IOUtils.copy(inputStream, writer, "UTF-8");
String content = writer.toString();
// remove the substrings from envelope...
content = content.replace("<idJustification>0</idJustification>", "");
content = content.replace("<indicRdv>false</indicRdv>", "");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(content.getBytes(Charset.forName("UTF-8")));
message.setContent(OutputStream.class, outputStream);
}

Based on the first comment, I created an abstract class which can easily be used to change the whole soap envelope.
Just in case someone wants a ready-to-use code part.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.log4j.Logger;
/**
* http://www.mastertheboss.com/jboss-web-services/apache-cxf-interceptors
* http://stackoverflow.com/questions/6915428/how-to-modify-the-raw-xml-message-of-an-outbound-cxf-request
*
*/
public abstract class MessageChangeInterceptor extends AbstractPhaseInterceptor<Message> {
public MessageChangeInterceptor() {
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
protected abstract Logger getLogger();
protected abstract String changeOutboundMessage(String currentEnvelope);
protected abstract String changeInboundMessage(String currentEnvelope);
public void handleMessage(Message message) {
boolean isOutbound = false;
isOutbound = message == message.getExchange().getOutMessage()
|| message == message.getExchange().getOutFaultMessage();
if (isOutbound) {
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
IOUtils.closeQuietly(cs);
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString(csnew.getInputStream(), "UTF-8");
csnew.flush();
IOUtils.closeQuietly(csnew);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Outbound message: " + currentEnvelopeMessage);
}
String res = changeOutboundMessage(currentEnvelopeMessage);
if (res != null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Outbound message has been changed: " + res);
}
}
res = res != null ? res : currentEnvelopeMessage;
InputStream replaceInStream = IOUtils.toInputStream(res, "UTF-8");
IOUtils.copy(replaceInStream, os);
replaceInStream.close();
IOUtils.closeQuietly(replaceInStream);
os.flush();
message.setContent(OutputStream.class, os);
IOUtils.closeQuietly(os);
} catch (IOException ioe) {
getLogger().warn("Unable to perform change.", ioe);
throw new RuntimeException(ioe);
}
} else {
try {
InputStream is = message.getContent(InputStream.class);
String currentEnvelopeMessage = IOUtils.toString(is, "UTF-8");
IOUtils.closeQuietly(is);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Inbound message: " + currentEnvelopeMessage);
}
String res = changeInboundMessage(currentEnvelopeMessage);
if (res != null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Inbound message has been changed: " + res);
}
}
res = res != null ? res : currentEnvelopeMessage;
is = IOUtils.toInputStream(res, "UTF-8");
message.setContent(InputStream.class, is);
IOUtils.closeQuietly(is);
} catch (IOException ioe) {
getLogger().warn("Unable to perform change.", ioe);
throw new RuntimeException(ioe);
}
}
}
public void handleFault(Message message) {
}
private class CachedStream extends CachedOutputStream {
public CachedStream() {
super();
}
protected void doFlush() throws IOException {
currentStream.flush();
}
protected void doClose() throws IOException {
}
protected void onWrite() throws IOException {
}
}
}

I had this problem as well today. After much weeping and gnashing of teeth, I was able to alter the StreamInterceptor class in the configuration_interceptor demo that comes with the CXF source:
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
String soapMessage = IOUtils.toString(csnew.getInputStream());
...
The soapMessage variable will contain the complete SOAP message. You should be able to manipulate the soap message, flush it to an output stream and do a message.setContent(OutputStream.class... call to put your modifications on the message. This comes with no warranty, since I'm pretty new to CXF myself!
Note: CachedStream is a private class in the StreamInterceptor class. Don't forget to configure your interceptor to run in the PRE_STREAM phase so that the SOAP interceptors have a chance to write the SOAP message.

Following is able to bubble up server side exceptions. Use of os.close() instead of IOUtils.closeQuietly(os) in previous solution is also able to bubble up exceptions.
public class OutInterceptor extends AbstractPhaseInterceptor<Message> {
public OutInterceptor() {
super(Phase.PRE_STREAM);
addBefore(StaxOutInterceptor.class.getName());
}
public void handleMessage(Message message) {
OutputStream os = message.getContent(OutputStream.class);
CachedOutputStream cos = new CachedOutputStream();
message.setContent(OutputStream.class, cos);
message.getInterceptorChain.aad(new PDWSOutMessageChangingInterceptor(os));
}
}
public class OutMessageChangingInterceptor extends AbstractPhaseInterceptor<Message> {
private OutputStream os;
public OutMessageChangingInterceptor(OutputStream os){
super(Phase.PRE_STREAM_ENDING);
addAfter(StaxOutEndingInterceptor.class.getName());
this.os = os;
}
public void handleMessage(Message message) {
try {
CachedOutputStream csnew = (CachedOutputStream) message .getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString( csnew.getInputStream(), (String) message.get(Message.ENCODING));
csnew.flush();
IOUtils.closeQuietly(csnew);
String res = changeOutboundMessage(currentEnvelopeMessage);
res = res != null ? res : currentEnvelopeMessage;
InputStream replaceInStream = IOUtils.tolnputStream(res, (String) message.get(Message.ENCODING));
IOUtils.copy(replaceInStream, os);
replaceInStream.close();
IOUtils.closeQuietly(replaceInStream);
message.setContent(OutputStream.class, os);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}

Good example for replacing outbound soap content based on this
package kz.bee.bip;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class SOAPOutboundInterceptor extends AbstractPhaseInterceptor<Message> {
public SOAPOutboundInterceptor() {
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
public void handleMessage(Message message) {
boolean isOutbound = false;
isOutbound = message == message.getExchange().getOutMessage()
|| message == message.getExchange().getOutFaultMessage();
if (isOutbound) {
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
IOUtils.closeQuietly(cs);
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString(csnew.getInputStream(), "UTF-8");
csnew.flush();
IOUtils.closeQuietly(csnew);
/* here we can set new data instead of currentEnvelopeMessage*/
InputStream replaceInStream = IOUtils.toInputStream(currentEnvelopeMessage, "UTF-8");
IOUtils.copy(replaceInStream, os);
replaceInStream.close();
IOUtils.closeQuietly(replaceInStream);
os.flush();
message.setContent(OutputStream.class, os);
IOUtils.closeQuietly(os);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
public void handleFault(Message message) {
}
private static class CachedStream extends CachedOutputStream {
public CachedStream() {
super();
}
protected void doFlush() throws IOException {
currentStream.flush();
}
protected void doClose() throws IOException {
}
protected void onWrite() throws IOException {
}
}
}

a better way would be to modify the message using the DOM interface, you need to add the SAAJOutInterceptor first (this might have a performance hit for big requests) and then your custom interceptor that is executed in phase USER_PROTOCOL
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Node;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
abstract public class SoapNodeModifierInterceptor extends AbstractSoapInterceptor {
SoapNodeModifierInterceptor() { super(Phase.USER_PROTOCOL); }
#Override public void handleMessage(SoapMessage message) throws Fault {
try {
if (message == null) {
return;
}
SOAPMessage sm = message.getContent(SOAPMessage.class);
if (sm == null) {
throw new RuntimeException("You must add the SAAJOutInterceptor to the chain");
}
modifyNodes(sm.getSOAPBody());
} catch (SOAPException e) {
throw new RuntimeException(e);
}
}
abstract void modifyNodes(Node node);
}

this one's working for me. It's based on StreamInterceptor class from configuration_interceptor example in Apache CXF samples.
It's in Scala instead of Java but the conversion is straightforward.
I tried to add comments to explain what's happening (as far as I understand).
import java.io.OutputStream
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor
import org.apache.cxf.helpers.IOUtils
import org.apache.cxf.io.CachedOutputStream
import org.apache.cxf.message.Message
import org.apache.cxf.phase.AbstractPhaseInterceptor
import org.apache.cxf.phase.Phase
// java note: base constructor call is hidden at the end of class declaration
class StreamInterceptor() extends AbstractPhaseInterceptor[Message](Phase.PRE_STREAM) {
// java note: put this into the constructor after calling super(Phase.PRE_STREAM);
addBefore(classOf[SoapPreProtocolOutInterceptor].getName)
override def handleMessage(message: Message) = {
// get original output stream
val osOrig = message.getContent(classOf[OutputStream])
// our output stream
val osNew = new CachedOutputStream
// replace it with ours
message.setContent(classOf[OutputStream], osNew)
// fills the osNew instead of osOrig
message.getInterceptorChain.doIntercept(message)
// flush before getting content
osNew.flush()
// get filled content
val content = IOUtils.toString(osNew.getInputStream, "UTF-8")
// we got the content, we may close our output stream now
osNew.close()
// modified content
val modifiedContent = content.replace("a-string", "another-string")
// fill original output stream
osOrig.write(modifiedContent.getBytes("UTF-8"))
// flush before set
osOrig.flush()
// replace with original output stream filled with our modified content
message.setContent(classOf[OutputStream], osOrig)
}
}

Related

REST Streaming JSON Output

We have JAX RS implementation which needs to send back JSON output. But the response size is huge. And the client expects the same synchronously.
Hence I tried to use StreamingOutput... but the client is not really getting the data in chunks.
Below is sample snippet:
Server Side
streamingOutput = new StreamingOutput() {
#Override
public void write(OutputStream out) throws IOException, WebApplicationException {
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(out);
jsonGenerator.writeStartArray();
for(int i=0; i < 10; i++) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("Response_State", "Response State - " + i);
jsonGenerator.writeStringField("Response_Report", "Response Report - " + i);
jsonGenerator.writeStringField("Error_details", "Error Details - " + i);
jsonGenerator.writeEndObject();;
jsonGenerator.flush();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
jsonGenerator.writeEndArray();
jsonGenerator.close();
}
};
return Response.status(200).entity(streamingOutput).build();
Client
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost("http://localhost:8080/AccessData/FetchReport");
post.setHeader("Content-type", "application/json");
ResponseHandler<HttpResponse> responseHandler = new BasicResponseHandler();
StringEntity entity = new StringEntity(jsonRequest); //jsonRequest is request string
post.setEntity(entity);
HttpResponse response = client.execute(post);
BufferedReader buffReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
JsonParser jsonParser = new JsonFactory().createParser(buffReader);
while(jsonParser.nextToken() != JsonToken.END_OBJECT) {
System.out.println(jsonParser.getCurrentName() + ":" + jsonParser.getCurrentValue());
}
String output;
while((output = buffReader.readLine()) != null) {
System.out.println(output);
}
In the server side code, I am putting sleep call just to simulate a gap between chunks of data. What I need is that the client should receive chunks of data as and when it is thrown back by the server.
But here the client gets the response in entirety always.
Any possible solution?
Thanks in advance.
It looks like the client side is not implemented correctly: reading the array of the objects using the parser.
Also, I would like to recommend reading and writing a data transfer object instead of low level field-by-field reading and writing.
For the sake of completeness, here is a complete draft example that uses: Jersey 2.25.1, Jetty 9.2.14.v20151106.
Common
ResponseData class
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ResponseData {
private final String responseState;
private final String responseReport;
private final String errorDetails;
#JsonCreator
public ResponseData(
#JsonProperty("Response_State") final String responseState,
#JsonProperty("Response_Report") final String responseReport,
#JsonProperty("Error_details") final String errorDetails) {
this.responseState = responseState;
this.responseReport = responseReport;
this.errorDetails = errorDetails;
}
public String getResponseState() {
return this.responseState;
}
public String getResponseReport() {
return this.responseReport;
}
public String getErrorDetails() {
return this.errorDetails;
}
#Override
public String toString() {
return String.format(
"ResponseData: responseState: %s; responseReport: %s; errorDetails: %s",
this.responseState,
this.responseReport,
this.errorDetails
);
}
}
Service
ServerProgram class
import java.net.URI;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
public class ServerProgram {
public static void main(final String[] args) {
final URI uri = URI.create("http://localhost:8080/");
final ResourceConfig resourceConfig = new ResourceConfig(TestResource.class);
resourceConfig.register(JacksonFeature.class);
JettyHttpContainerFactory.createServer(uri, resourceConfig);
}
}
TestResource class
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.OutputStream;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
#Path("/")
public class TestResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getData() {
final StreamingOutput streamingOutput = new JsonStreamingOutput();
return Response.status(200).entity(streamingOutput).build();
}
private static class JsonStreamingOutput implements StreamingOutput {
#Override
public void write(final OutputStream outputStream) throws IOException, WebApplicationException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonFactory jsonFactory = objectMapper.getFactory();
try (final JsonGenerator jsonGenerator = jsonFactory.createGenerator(outputStream)) {
jsonGenerator.writeStartArray();
for (int i = 0; i < 10; i++) {
final ResponseData responseData = new ResponseData(
"Response State - " + i,
"Response Report - " + i,
"Error Details - " + i
);
jsonGenerator.writeObject(responseData);
jsonGenerator.flush();
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
jsonGenerator.writeEndArray();
}
}
}
}
Client
ClientProgram class
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.client.ClientProperties;
public class ClientProgram {
public static void main(final String[] args) throws IOException {
Client client = null;
try {
client = ClientBuilder.newClient();
client.property(ClientProperties.READ_TIMEOUT, 10000);
try (final InputStream inputStream = client
.target("http://localhost:8080/")
.request(MediaType.APPLICATION_JSON)
.get(InputStream.class);
final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
processStream(bufferedInputStream);
}
} finally {
if (client != null) {
client.close();
}
}
}
private static void processStream(final InputStream inputStream) throws IOException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonFactory jsonFactory = objectMapper.getFactory();
try (final JsonParser jsonParser = jsonFactory.createParser(inputStream)) {
final JsonToken arrayToken = jsonParser.nextToken();
if (arrayToken == null) {
// TODO: Return or throw exception.
return;
}
if (!JsonToken.START_ARRAY.equals(arrayToken)) {
// TODO: Return or throw exception.
return;
}
// Iterate through the objects of the array.
while (JsonToken.START_OBJECT.equals(jsonParser.nextToken())) {
final ResponseData responseData = jsonParser.readValueAs(ResponseData.class);
System.out.println(responseData);
}
}
}
}
Hope this helps.

Asynchronous HTTP call doesn't work

I am working on an Android app (min API 8) and I want to make an activity where there is a preloader GIF running while some tasks are executed in the background.
These tasks involve connection to a database and queries. So in some way, I want to achieve something that involves techniques like you would use to make a progress bar.
I know I can't make a connection in the main thread in Java so I made a class that does this in another thread. The connection works fine, but I can't make the whole behaviour work properly. More precisely, if I use thread.join()then the main thread is blocked (which is the opposite of what I want) and if I don't use it, the code of the main thread goes on and finishes before the background process has terminated.
Can someone help me with this please ?
This is the class I created to manage POST queries to an URL :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.concurrent.atomic.AtomicReference;
public class Request
{
private URL m_url;
private StringBuilder m_parameters;
private HttpURLConnection m_connection;
public Request(String url)
{
try
{
m_url = new URL(url);
}
catch(MalformedURLException exception)
{
System.exit(1);
}
m_connection = null;
m_parameters = new StringBuilder();
}
public void put(String key, String value)
{
if(m_parameters.length() != 0)
m_parameters.append('&');
try
{
m_parameters.append(URLEncoder.encode(key, "UTF-8"));
m_parameters.append('=');
m_parameters.append(URLEncoder.encode(value, "UTF-8"));
}
catch(UnsupportedEncodingException exception)
{
System.exit(1);
}
}
private void sendRequest()
{
try
{
byte[] data = m_parameters.toString().getBytes("UTF-8");
m_connection = (HttpURLConnection) m_url.openConnection();
m_connection.setAllowUserInteraction(true);
m_connection.setRequestMethod("POST");
m_connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
m_connection.setRequestProperty("Content-Length", String.valueOf(data.length));
m_connection.setDoOutput(true);
m_connection.getOutputStream().write(data);
}
catch(Exception exception)
{
System.exit(1);
}
}
private String getResponse()
{
String response = "";
try
{
if(m_connection.getResponseCode() == HttpURLConnection.HTTP_OK)
{
Reader reader = new BufferedReader(new InputStreamReader(m_connection.getInputStream(), "UTF-8"));
int c;
do {
c = reader.read();
response += (char) c;
}
while (c >= 0);
}
}
catch(IOException exception)
{
System.exit(1);
}
m_connection.disconnect();
return response;
}
public String get()
{
final AtomicReference<String> response = new AtomicReference<>();
Thread thread = new Thread(new Runnable()
{
public void run()
{
sendRequest();
response.set(getResponse());
}
});
thread.start();
/*
try
{
thread.join();
}
catch(InterruptedException exception)
{
System.exit(1);
}
*/
return response.get();
}
}
And this is how I use it in the main thread (the activity) :
Request request = new Request("http://posttestserver.com/post.php?dump&html&sleep=5");
request.put("name", "bob");
String response = request.get();
Thanks.
Okay, I finally solved that problem using standard IntentServiceof Android :
https://developer.android.com/training/run-background-service/create-service.html
This tutorial helped a lot too :
http://code.tutsplus.com/tutorials/android-fundamentals-intentservice-basics--mobile-6183
Here is my new class Request:
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Set;
public class Request extends IntentService
{
private URL m_url;
private StringBuilder m_parameters;
private HttpURLConnection m_connection;
public Request()
{
super("Request");
m_url = null;
m_connection = null;
m_parameters = new StringBuilder();
}
public void put(String key, String value)
{
if(m_parameters.length() != 0)
m_parameters.append('&');
try
{
m_parameters.append(URLEncoder.encode(key, "UTF-8"));
m_parameters.append('=');
m_parameters.append(URLEncoder.encode(value, "UTF-8"));
}
catch(UnsupportedEncodingException exception)
{
System.exit(1);
}
}
private void sendRequest()
{
try
{
byte[] data = m_parameters.toString().getBytes("UTF-8");
m_connection = (HttpURLConnection) m_url.openConnection();
m_connection.setAllowUserInteraction(true);
m_connection.setRequestMethod("POST");
m_connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
m_connection.setRequestProperty("Content-Length", String.valueOf(data.length));
m_connection.setDoOutput(true);
m_connection.getOutputStream().write(data);
}
catch(Exception exception)
{
System.exit(1);
}
}
private String getResponse()
{
String response = "";
try
{
if(m_connection.getResponseCode() == HttpURLConnection.HTTP_OK)
{
Reader reader = new BufferedReader(new InputStreamReader(m_connection.getInputStream(), "UTF-8"));
int c;
do {
c = reader.read();
response += (char) c;
}
while (c >= 0);
}
}
catch(IOException exception)
{
System.exit(1);
}
m_connection.disconnect();
return response;
}
protected void onHandleIntent(Intent intent)
{
Bundle bundle = intent.getExtras();
Set<String> keys = bundle.keySet();
for(String key : keys)
put(key, bundle.getString(key));
try
{
m_url = new URL(bundle.getString("url"));
}
catch(MalformedURLException exception)
{
System.exit(1);
}
sendRequest();
String response = getResponse();
Intent broadcast = new Intent();
broadcast.setAction(ReadyActivity.ResponseReceiver.m_broadcastKey);
broadcast.putExtra("response", response);
sendBroadcast(broadcast);
}
}
Here is the ResponseReceiversubclass of my main activity :
public class ResponseReceiver extends BroadcastReceiver
{
public static final String m_broadcastKey = "Uz258e3wZm77Z3Tdebn7PqgW3CLBJ8";
public void onReceive(Context context, Intent intent)
{
String response = intent.getStringExtra("response");
clear();
((TextView) m_widgets.get("text")).setText("Finally found someone !" + response);
show(m_widgets.get("text"));
((Button) m_widgets.get("button1")).setText("OK let's do this !");
show(m_widgets.get("button1"));
((Button) m_widgets.get("button2")).setText("Later ?");
show(m_widgets.get("button2"));
unregisterReceiver(m_receiver);
}
}
Then I also had to instantiate the ResponseReceiver in the activity:
private ResponseReceiver m_receiver;
...
IntentFilter filter = new IntentFilter(ResponseReceiver.m_broadcastKey);
m_receiver = new ResponseReceiver();
registerReceiver(m_receiver, filter);
And finally call the service :
Intent service = new Intent(this, Request.class);
ArrayList<CharSequence> parameters = new ArrayList<>();
service.putExtra("url", "http://posttestserver.com/post.php?dump&html&sleep=10");
service.putExtra("username", "bob");
service.putExtra("age", "20");
startService(service);
Maybe it will help someone in the future.

Java : InputStream to Multi-part file conversion, result file is empty

I am working on a Java application in which I am trying to create a Multipart file out of downloaded InputStream. Unfortunately, it is not working and the Multipart file is empty. I checked the size of savedFile on disk before copying it to Multipart, and it has correct size, attributes, content.
What am I doing wrong in the conversion, there is no stacktrace, as I am catching it.
Code :
// InputStream contains file data.
byte[] bytes = IOUtils.toByteArray(inputStream);
File file = new File(msg + "temp");
if (file.exists() && file.isDirectory()) {
OutputStream outputStream = new FileOutputStream(new File(msg + "temp" + "/" +
groupAttachments.getFileName()));
outputStream.write(bytes);
outputStream.close();
}
java.io.File savedFile = new java.io.File(msg + "temp" + "/" +
groupAttachments.getFileName());
DiskFileItem fileItem = new DiskFileItem("file", "text/plain", false,
savedFile.getName(), (int) savedFile.length(), savedFile.getParentFile());
fileItem.getOutputStream();
MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
System.out.println("Saved file size is "+savedFile.length());
if (multipartFile.isEmpty()) {
System.out.println("Dropbox uploaded multipart file is empty");
} else {
System.out.println("Multipart file is not empty.");
}
this.dropboxTask.insertFile(multipartFile, "",
savedPersonalNoteObject.getNoteid(), (long) 0, true);
Path path = Paths.get(msg + "temp" + "/" + groupAttachments.getFileName());
Console output :
Multipart file is not empty
Bytes are not null
File path is /My Group
Input stream is not null
Saved file size is 4765
Dropbox uploaded multipart file is empty
Multipart file is empty
Bytes are not null
What am I doing wrong in the conversion? Any help would be nice. Thanks a lot.
The DiskFileItem uses a DeferredFileOutputStream which uses an in-memory byte-array that is only filled when bytes are actually transferred.
Since files are used directly and no bytes are actually copied,
the byte-array is never filled. See for yourself in the source code:
Source code CommonsMultipartFile
Source code DiskFileItem
Source code DeferredFileOutputStream
So, instead of just calling fileItem.getOutputStream();, transfer the bytes to fill the in-memory byte-array:
try (OutputStream out = fileItem.getOutputStream();
InputStream in = Files.newInputStream(file.toPath())) {
IOUtils.copy(in, dfos);
}
and then the tranferTo call will work.
This appears to be a bit cumbersome for just moving a file: CommonsMultipartFile only calls fileItem.write((File)dest) in the transferTo method.
Below are two test cases, one using the DiskFileItem and one using the LocalFileItem. The code for LocalFileItem is shown further below.
I used dependencies org.springframework:spring-web:4.2.2.RELEASE, commons-fileupload:commons-fileupload:1.3.1 and junit:junit:4.12
Test class CommonMp:
import static org.junit.Assert.*;
import java.io.*;
import java.nio.charset.*;
import java.nio.file.*;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
public class CommonMp {
private final Charset CS = StandardCharsets.UTF_8;
#Test
public void testLocalMp() {
Path testInputFile = null, testOutputFile = null;
try {
testInputFile = prepareInputFile();
LocalFileItem lfi = new LocalFileItem(testInputFile);
CommonsMultipartFile cmf = new CommonsMultipartFile(lfi);
System.out.println("Empty: " + cmf.isEmpty());
testOutputFile = testInputFile.getParent().resolve("testMpOutput.txt");
cmf.transferTo(testOutputFile.toFile());
System.out.println("Size: " + cmf.getSize());
printOutput(testOutputFile);
} catch (Exception e) {
e.printStackTrace();
fail();
} finally {
deleteSilent(testInputFile, testOutputFile);
}
}
#Test
public void testMp() {
Path testInputFile = null, testOutputFile = null;
try {
testInputFile = prepareInputFile();
DiskFileItem di = new DiskFileItem("file", "text/plain", false, testInputFile.getFileName().toString(),
(int) Files.size(testInputFile), testInputFile.getParent().toFile());
try (OutputStream out = di.getOutputStream();
InputStream in = Files.newInputStream(testInputFile)) {
IOUtils.copy(in, out);
}
CommonsMultipartFile cmf = new CommonsMultipartFile(di);
System.out.println("Size: " + cmf.getSize());
testOutputFile = testInputFile.getParent().resolve("testMpOutput.txt");
cmf.transferTo(testOutputFile.toFile());
printOutput(testOutputFile);
} catch (Exception e) {
e.printStackTrace();
fail();
} finally {
deleteSilent(testInputFile, testOutputFile);
}
}
private Path prepareInputFile() throws IOException {
Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));
Path testInputFile = tmpDir.resolve("testMpinput.txt");
try (OutputStream out = Files.newOutputStream(testInputFile)){
out.write("Just a test.".getBytes(CS));
}
return testInputFile;
}
private void printOutput(Path p) throws IOException {
byte[] outBytes = Files.readAllBytes(p);
System.out.println("Output: " + new String(outBytes, CS));
}
private void deleteSilent(Path... paths) {
for (Path p : paths) {
try { if (p != null) p.toFile().delete(); } catch (Exception ignored) {}
}
}
}
The custom LocalFileItem class, YMMV!
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemHeaders;
public class LocalFileItem implements FileItem {
private static final long serialVersionUID = 2467880290855097332L;
private final Path localFile;
public LocalFileItem(Path localFile) {
this.localFile = localFile;
}
#Override
public void write(File file) throws Exception {
Files.move(localFile, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
#Override
public long getSize() {
// Spring's CommonsMultipartFile caches the file size and uses it to determine availability.
long size = -1L;
try {
size = Files.size(localFile);
} catch (IOException ignored) {}
return size;
}
#Override
public void delete() {
localFile.toFile().delete();
}
/* *** properties and unsupported methods *** */
private FileItemHeaders headers;
private String contentType;
private String fieldName;
private boolean formField;
#Override
public FileItemHeaders getHeaders() {
return headers;
}
#Override
public void setHeaders(FileItemHeaders headers) {
this.headers = headers;
}
#Override
public InputStream getInputStream() throws IOException {
throw new IOException("Only method write(File) is supported.");
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
#Override
public String getContentType() {
return contentType;
}
#Override
public String getName() {
return localFile.getFileName().toString();
}
#Override
public boolean isInMemory() {
return false;
}
#Override
public byte[] get() {
throw new RuntimeException("Only method write(File) is supported.");
}
#Override
public String getString(String encoding)
throws UnsupportedEncodingException {
throw new RuntimeException("Only method write(File) is supported.");
}
#Override
public String getString() {
throw new RuntimeException("Only method write(File) is supported.");
}
#Override
public String getFieldName() {
return fieldName;
}
#Override
public void setFieldName(String name) {
this.fieldName = name;
}
#Override
public boolean isFormField() {
return formField;
}
#Override
public void setFormField(boolean state) {
this.formField = state;
}
#Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("Only method write(File) is supported.");
}
}

Apache HttpCore, simple server to echo received post data

Using the ElementalHttpServer example class found here:
https://hc.apache.org/httpcomponents-core-4.3.x/httpcore/examples/org/apache/http/examples/ElementalHttpServer.java
I am able to successfully receive post data, my goal is to convert the received post data into a string I can print. I've modified the HttpFileHandler as follows, using eneity.getContent() to get the inputStream, but i'm not sure how I can convert the inputStream into a String.
static class HttpFileHandler implements HttpRequestHandler {
private final String docRoot;
public HttpFileHandler(final String docRoot) {
super();
this.docRoot = docRoot;
}
public void handle(
final HttpRequest request,
final HttpResponse response,
final HttpContext context) throws HttpException, IOException {
String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) {
throw new MethodNotSupportedException(method + " method not supported");
}
String target = request.getRequestLine().getUri();
if (request instanceof HttpEntityEnclosingRequest) {
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
byte[] entityContent = EntityUtils.toByteArray(entity);
InputStream inputStream = entity.getContent();
String str= inputStream.toString();
byte[] b3=str.getBytes();
String st = new String(b3);
System.out.println(st);
for(int i=0;i<b3.length;i++) {
System.out.print(b3[i]+"\t");
}
System.out.println("Incoming entity content (bytes): " + entityContent.length);
}
}
}
Thanks for any ideas
Here is simple console logging handler; it logs every request (not only POST) - both headers and payload:
package com.mycompany;
import org.apache.http.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.util.EntityUtils;
import org.omg.CORBA.Request;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Created by IntelliJ IDEA.
* User: Piotrek
* To change this template use File | Settings | File Templates.
*/
public class LoggingHandler implements HttpRequestHandler {
public void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException {
System.out.println(""); // empty line before each request
System.out.println(httpRequest.getRequestLine());
System.out.println("-------- HEADERS --------");
for(Header header: httpRequest.getAllHeaders()) {
System.out.println(header.getName() + " : " + header.getValue());
}
System.out.println("--------");
HttpEntity entity = null;
if (httpRequest instanceof HttpEntityEnclosingRequest)
entity = ((HttpEntityEnclosingRequest)httpRequest).getEntity();
// For some reason, just putting the incoming entity into
// the response will not work. We have to buffer the message.
byte[] data;
if (entity == null) {
data = new byte [0];
} else {
data = EntityUtils.toByteArray(entity);
}
System.out.println(new String(data));
httpResponse.setEntity(new StringEntity("dummy response"));
}
}
Registration of handler using org.apache.http.localserver.LocalTestServer (with ElementalHttpServer it is similar - you also have HttpRequestHandler implementation above):
public static void main(String[] args) throws Exception {
LocalTestServer server = new LocalTestServer(null, null);
try {
server.start();
server.register("/*", new LoggingHandler());
server.awaitTermination(3600 * 1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
server.stop();
}
}

How to get a progress bar for a file upload with Apache HttpClient 4?

I've got the following code for a file upload with Apache's HTTP-Client (org.apache.http.client):
public static void main(String[] args) throws Exception
{
String fileName = "test.avi";
File file = new File(fileName);
String serverResponse = null;
HttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient client = new DefaultHttpClient(params);
HttpPut put = new HttpPut("http://localhost:8080/" + fileName);
FileEntity fileEntity = new FileEntity(file, "binary/octet-stream");
put.setEntity(fileEntity);
HttpResponse response = client.execute(put);
HttpEntity entity = response.getEntity();
if (entity != null)
{
serverResponse = EntityUtils.toString(entity);
System.out.println(serverResponse);
}
}
It work's quite well but now I want to have a progress bar which shows the progress of the file upload. How can this be made? I found a code snippet at File Upload with Java (with progress bar) but it is designed for Apache HTTP Client 3 (org.apache.commons.httpclient) and the RequestEntity class does not exist in Apache HTTP Client 4. ;(
Maybe someone of you has an approach?
Many greetings
Benny
I introduced a derived FileEntity that just counts the written bytes.
It uses OutputStreamProgress that does the actual counting (kind of a decorator to the actual OutputStream).
The advantage of this (and decoration in general) is that I do not need to copy the actual implementation, like the the actual copying from the file stream to the output stream. I can also change to use a different (newer) implementation, like the NFileEntity.
Enjoy...
FileEntity.java
public class FileEntity extends org.apache.http.entity.FileEntity {
private OutputStreamProgress outstream;
public FileEntity(File file, String contentType) {
super(file, contentType);
}
#Override
public void writeTo(OutputStream outstream) throws IOException {
this.outstream = new OutputStreamProgress(outstream);
super.writeTo(this.outstream);
}
/**
* Progress: 0-100
*/
public int getProgress() {
if (outstream == null) {
return 0;
}
long contentLength = getContentLength();
if (contentLength <= 0) { // Prevent division by zero and negative values
return 0;
}
long writtenLength = outstream.getWrittenLength();
return (int) (100*writtenLength/contentLength);
}
}
OutputStreamProgress.java
public class OutputStreamProgress extends OutputStream {
private final OutputStream outstream;
private volatile long bytesWritten=0;
public OutputStreamProgress(OutputStream outstream) {
this.outstream = outstream;
}
#Override
public void write(int b) throws IOException {
outstream.write(b);
bytesWritten++;
}
#Override
public void write(byte[] b) throws IOException {
outstream.write(b);
bytesWritten += b.length;
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
outstream.write(b, off, len);
bytesWritten += len;
}
#Override
public void flush() throws IOException {
outstream.flush();
}
#Override
public void close() throws IOException {
outstream.close();
}
public long getWrittenLength() {
return bytesWritten;
}
}
A new version using the package org.apache.commons.io.output from commons-io (2.4) and its class CountingOutputStream.
I changed the initial code to reflect my project needs to use a multipart form as input and the post method (this dues to the requirements imposed by the server side).
Consider that the delta of large file correspond in my tests to 4096 bytes. This means that the listener method counterChanged() is called every 4096 bytes of transfered data, what is acceptable for my use case.
The method looks like:
public void post(String url, File sendFile) {
HttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient client = new DefaultHttpClient(params);
HttpPost post = new HttpPost(url + "/" + sendFile.getName());
MultipartEntity multiEntity = new MultipartEntity();
MyFileBody fileBody = new MyFileBody(sendFile);
fileBody.setListener(new IStreamListener(){
#Override
public void counterChanged(int delta) {
// do something
System.out.println(delta);
}});
multiEntity.addPart("file", fileBody);
StringBody stringBody = new StringBody(sendFile.getName());
multiEntity.addPart("fileName", stringBody);
post.setEntity(multiEntity);
HttpResponse response = client.execute(post);
}
The class MyFileBody becomes:
public class MyFileBody extends FileBody {
private IStreamListener listener;
public MyFileBody(File file) {
super(file);
}
#Override
public void writeTo(OutputStream out) throws IOException {
CountingOutputStream output = new CountingOutputStream(out) {
#Override
protected void beforeWrite(int n) {
if (listener != null && n != 0)
listener.counterChanged(n);
super.beforeWrite(n);
}
};
super.writeTo(output);
}
public void setListener(IStreamListener listener) {
this.listener = listener;
}
public IStreamListener getListener() {
return listener;
}
}
Finally, the listener interface looks like:
public interface IStreamListener {
void counterChanged(int delta);
}
This answer extends kilaka's answer by adding a simple listener to the OutputStreamProgress.java class instead of having the public getProgress() method (I'm honestly not sure how you are suppose to call the getProgress() method since the thread will be executing inside of httpclient's code the entire time you might want to call getProgress()!).
Please note you'll need to extend the entity class for each entity type you want to use, and when you write your HttpClient code, you'll need to create the entity of that new type.
I wrote a very basic write listener that implements the WriteListener interface. This is where you'll add your logic to do something with the write reports from the OutputStreamProgress, something like updating a progress bar :)
Big thanks to kilaka for using the decorator idea to sneak in a counting outstream.
WriteLisener.java
public interface WriteListener {
void registerWrite(long amountOfBytesWritten);
}
OutputStreamProgress.java
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamProgress extends OutputStream {
private final OutputStream outstream;
private long bytesWritten=0;
private final WriteListener writeListener;
public OutputStreamProgress(OutputStream outstream, WriteListener writeListener) {
this.outstream = outstream;
this.writeListener = writeListener;
}
#Override
public void write(int b) throws IOException {
outstream.write(b);
bytesWritten++;
writeListener.registerWrite(bytesWritten);
}
#Override
public void write(byte[] b) throws IOException {
outstream.write(b);
bytesWritten += b.length;
writeListener.registerWrite(bytesWritten);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
outstream.write(b, off, len);
bytesWritten += len;
writeListener.registerWrite(bytesWritten);
}
#Override
public void flush() throws IOException {
outstream.flush();
}
#Override
public void close() throws IOException {
outstream.close();
}
}
BasicWriteListener
public class BasicWriteListener implements WriteListener {
public BasicWriteListener() {
// TODO Auto-generated constructor stub
}
public void registerWrite(long amountOfBytesWritten) {
System.out.println(amountOfBytesWritten);
}
}
MultipartEntityWithProgressBar
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
public class MultipartEntityWithProgressBar extends MultipartEntity {
private OutputStreamProgress outstream;
private WriteListener writeListener;
#Override
public void writeTo(OutputStream outstream) throws IOException {
this.outstream = new OutputStreamProgress(outstream, writeListener);
super.writeTo(this.outstream);
}
public MultipartEntityWithProgressBar(WriteListener writeListener)
{
super();
this.writeListener = writeListener;
}
public MultipartEntityWithProgressBar(HttpMultipartMode mode, WriteListener writeListener)
{
super(mode);
this.writeListener = writeListener;
}
public MultipartEntityWithProgressBar(HttpMultipartMode mode, String boundary, Charset charset, WriteListener writeListener)
{
super(mode, boundary, charset);
this.writeListener = writeListener;
}
// Left in for clarity to show where I took from kilaka's answer
// /**
// * Progress: 0-100
// */
// public int getProgress() {
// if (outstream == null) {
// return 0;
// }
// long contentLength = getContentLength();
// if (contentLength <= 0) { // Prevent division by zero and negative values
// return 0;
// }
// long writtenLength = outstream.getWrittenLength();
// return (int) (100*writtenLength/contentLength);
// }
}
Hello guys!
I solved the problem myself and made ​​a simple example to it.
If there are any questions, feel free to ask.
Here we go!
ApplicationView.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
public class ApplicationView implements ActionListener
{
File file = new File("C:/Temp/my-upload.avi");
JProgressBar progressBar = null;
public ApplicationView()
{
super();
}
public void createView()
{
JFrame frame = new JFrame("File Upload with progress bar - Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 200);
frame.setVisible(true);
progressBar = new JProgressBar(0, 100);
progressBar.setBounds(20, 20, 200, 30);
progressBar.setStringPainted(true);
progressBar.setVisible(true);
JButton button = new JButton("upload");
button.setBounds(progressBar.getX(),
progressBar.getY() + progressBar.getHeight() + 20,
100,
40);
button.addActionListener(this);
JPanel panel = (JPanel) frame.getContentPane();
panel.setLayout(null);
panel.add(progressBar);
panel.add(button);
panel.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
try
{
sendFile(this.file, this.progressBar);
}
catch (Exception ex)
{
System.out.println(ex.getLocalizedMessage());
}
}
private void sendFile(File file, JProgressBar progressBar) throws Exception
{
String serverResponse = null;
HttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient client = new DefaultHttpClient(params);
HttpPut put = new HttpPut("http://localhost:8080/" + file.getName());
ProgressBarListener listener = new ProgressBarListener(progressBar);
FileEntityWithProgressBar fileEntity = new FileEntityWithProgressBar(file, "binary/octet-stream", listener);
put.setEntity(fileEntity);
HttpResponse response = client.execute(put);
HttpEntity entity = response.getEntity();
if (entity != null)
{
serverResponse = EntityUtils.toString(entity);
System.out.println(serverResponse);
}
}
}
FileEntityWithProgressBar.java
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.http.entity.AbstractHttpEntity;
/**
* File entity which supports a progress bar.<br/>
* Based on "org.apache.http.entity.FileEntity".
* #author Benny Neugebauer (www.bennyn.de)
*/
public class FileEntityWithProgressBar extends AbstractHttpEntity implements Cloneable
{
protected final File file;
private final ProgressBarListener listener;
private long transferredBytes;
public FileEntityWithProgressBar(final File file, final String contentType, ProgressBarListener listener)
{
super();
if (file == null)
{
throw new IllegalArgumentException("File may not be null");
}
this.file = file;
this.listener = listener;
this.transferredBytes = 0;
setContentType(contentType);
}
public boolean isRepeatable()
{
return true;
}
public long getContentLength()
{
return this.file.length();
}
public InputStream getContent() throws IOException
{
return new FileInputStream(this.file);
}
public void writeTo(final OutputStream outstream) throws IOException
{
if (outstream == null)
{
throw new IllegalArgumentException("Output stream may not be null");
}
InputStream instream = new FileInputStream(this.file);
try
{
byte[] tmp = new byte[4096];
int l;
while ((l = instream.read(tmp)) != -1)
{
outstream.write(tmp, 0, l);
this.transferredBytes += l;
this.listener.updateTransferred(this.transferredBytes);
}
outstream.flush();
}
finally
{
instream.close();
}
}
public boolean isStreaming()
{
return false;
}
#Override
public Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
ProgressBarListener.java
import javax.swing.JProgressBar;
public class ProgressBarListener
{
private int transferedMegaBytes = 0;
private JProgressBar progressBar = null;
public ProgressBarListener()
{
super();
}
public ProgressBarListener(JProgressBar progressBar)
{
this();
this.progressBar = progressBar;
}
public void updateTransferred(long transferedBytes)
{
transferedMegaBytes = (int) (transferedBytes / 1048576);
this.progressBar.setValue(transferedMegaBytes);
this.progressBar.paint(progressBar.getGraphics());
System.out.println("Transferred: " + transferedMegaBytes + " Megabytes.");
}
}
Happy Coding!

Categories

Resources