struts2 data cut in string send to jsp - java

i've got this problem again...
So i've got String data in my Struts2 app. this data is quite big, 36KB data read from html with code:
BufferedReader reader = new BufferedReader(new FileReader("FILE.html"));
String readData;
while( (readData = reader.readLine()) != null) {
fileData.append(new String(readData.getBytes(),"UTF-8"));
}
reader.close();
fileData.trimToSize();
this.data2display = fileData.toString();
this.setData2display(this.data2display.replaceAll("\\s+", " "));
I display data2display in my jsp file, with just:
<s:property value="data2display" escape="false" escapeJavaScript="false" />
Aaaaaand... This data is entire while i'm debugging controller, but while i try to display this in jsp. I've got only part of data. I haven't got any error/debug logs.
Any idea how to check it/fix it ?
My app: (struts2, jsp) everything is from appfuse-basic-struts archetype.

My personal start point would be the source of PropertyTag, and from there on follow the code.
In this case, start with PropertyTag. You see that it extends ComponentTagSupport, which in turn extends StrutsBodyTagSupport.
This is where it gets interesting; the toString method uses a FastByteArrayOutputStream which uses a default block size (buffer) of 8192 bytes. Using the default constructor, as done by StrutsBodyTagSupport you can't output a String with more data than that.
Being not an expert on Struts I hesitate to say that's an implementation bug; it should IMHO compute the buffer size from the value to be printed. Unfortunately, it doesn't. So I don't think there's an easy way around it.
The non-easy way is obviously defining a List of String data parts smaller than 8k bytes, and iterate over that list in the JSP, or just use c:out or something like that.
This may not be the answer you're looking for, but I hope this will at least help you understand the trouble you're in.

Related

Handling file downloads via REST API

I want to set up the REST API to support file downloads via Java (The java part is not needed at the moment -- I am saying it in here so you can make your answer more specific for my problem).
How would I do that?
For example, I have this file in a folder (./java.jar), how can I stream it in such a way for it to be downloadable by a Java client?
I forgot to say that this, is for some paid-content.
My app should be able to do this
Client: Post to server with username,pass.
Rest: Respond accordingly to what user has bought (so if it has bought that file, download it)
Client: Download file and put it in x folder.
I thought of encoding a file in base64 and then posting the encoded result into the usual .json (maybe with a nice name -- useful for the java application, and with the code inside -- though I would not know how I should rebuild the file at this point). <- Is this plausible? Or is there an easier way?
Also, please do not downvote if unnecessary, although there is no code in the question, that doesn't mean I haven't researched it, it just means that I found nothing suitable for my situation.
Thanks.
What you need is a regular file streaming, using a valid URL.
Below code is an excerpt from here
import java.net.*;
import java.io.*;
public class URLReader {
public static void main(String[] args) throws Exception {
URL oracle = new URL("http://www.oracle.com/");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
For your needs, based on your updated comments on the above answer, you could call your REST endpoint after user logs in(with Auth and other headers/body you wish to receive) and proceed to the download.
Convert your jar/downloadable content to bytes. More on this
Java Convert File to Byte Array and visa versa
Later, in case if you dont want regular streaming as aforementioned in previous answers, you can put the byte content in the body as Base64 String. You can encode to Base64 from your byte array using something like below.
Base64.encodeToString(byte[], Base64.NO_WRAP + Base64.URL_SAFE);
Reference from here: How to send byte[] and strings to a restful webservice and retrieve this information in the web method implementation
Again, there are many ways to do this, this is one of the ways you can probably do using REST.

Android OutputStreamWriter writes non-UTF-8 characters

There's something weird happening to my code. I'm trying to open a file and append a generated string (which is based on time) to it, so that it can be used later on. In my app, this happens more then once, but somehow, this time it doesn't give me the result I'd like to see. To clarify:
I'm using the following code inside my class:
try {
OutputStreamWriter oos = new OutputStreamWriter(context.openFileOutput(ARRANGED_TXT, Context.MODE_PRIVATE));
oos.write(ArrangedTxtAsString);
oos.close();
}
catch(FileNotFoundException e){
Log.e("File Error", "File not found: " + e.toString());
}
and ARRANGED_TXT being defined as:
private static final String ARRANGED_TXT = "arranged_txt.txt";
ArrangedTxtAsString is a string, which looks like this:
Banana
Pineapple
Orange
Coconut
Strawberry
It was made using a StringBuilder.
Now, the problem is, is that the generated file looks like this:
It's not a problem with NotePad++, as other programs give the same result. One important thing to mention, is that although the text looks like it is made up out of non-UTF-8 characters, it is perfectly processed by the rest of the program. This may sound a bit weird, but what I'm trying to tell, is that the code is working fine, but the only problem there is, is that the text shown through a text-editor, doensn't correspond with what it should look like. You see, I'm quite a perfectionist and that's why I want it to get fixed. This might also be a problem in the future (debugging puposes etc.).
Edit:
It appears that it doesn't matter what the string contains: a single character, a number, or whatever; it gives the exact same result. Even writing "" results in those weird characters!
I really hope someone knows what's happening here!
Thank you in advance.
If you need to write UTF-8 MUST use the constructor with charset like:
OutputStreamWriter oos = new OutputStreamWriter(context.openFileOutput(ARRANGED_TXT, Context.MODE_PRIVATE),"UTF-8");
OutputStreamWriter(OutputStreamĀ out, StringĀ charsetName)
Otherwise the default encoding is used and not is utf-8 in all systems

Scrape website for one data

I would like to extract the value of <div class="score">4.1</div> from a website with JAVA (Android). I tried Jsoup and even though it couldn't be simpler to use, it gives me the value in 8 seconds, which is very slow. You need to know, the page source of the site has 300,000 characters and this <div> is somewhere in the middle.
Even using HttpClient and getting the source into a StringBuilder then going through the whole string until the score part is found is faster (3-4 seconds).
I couldn't try out HtmlUnit as it requires a massive amount of jar files and after a while Eclipse always pissed itself in its confusion.
Is there a faster way?
You may simply send a XMLhttpRequest and then search the response using search() function. I think this would be much faster.
Similar Question: Retrieving source code using XMLhttpRequest in javascript
To make the search more fast, you can simply use indexOf([sting to search],[starting index]) and specify the starting index (it doesn't needs to be very accurate, you just have to decrease your search area).
Here is what I did. The problem was that I read the webpage line by line then glued them together into a StringBuilder and searched for the specific part. Then I asked myself: why do I read the page line by line then glue them together? So instead I read the page into a ByteArray and converted it into a String. The scraping time became less than a second!
try
{
InputStream is = new URL(url).openStream();
outputDoc = new ByteArrayOutputStream();
byte buf[]=new byte[1024];
int len;
while((len=is.read(buf))>0)
{
outputDoc.write(buf,0, len);
}
outputDoc.close();
} catch(Exception e) { e.printStackTrace(); }
try {
page = new String(outputDoc.toByteArray(), "UTF-8");
//here I used str.indexOf to find the part
}

Stopping a Servlet from returning a Response

Had a look through SO and couldn't find a question similar to what I'm after. I'll start off by explaining what I'm trying to do, then finish up with a more specific question..
My aim
I have a link that passes a query string parameter to my servlet. That parameter is report. If report = true in the servlet, then I'll generate a PDF document. The PDF document then returns this value, by setting the response's mime type to application/pdf. This code is shown below:
String mimeType = "application/pdf";
res.setContentType(mimeType);
res.setHeader("Content-Disposition", "attachment; filename=\"" +
getEventID(doc) + ".pdf\"");
// Set the response content type and pdf attachment.
out = new ByteArrayOutputStream();
// All PDF Data is pushed onto the output stream.
com.lowagie.text.Document pdfDoc = buildPDF(getEventID(doc));
This code is then written to the response object's output stream.
if(pdfDoc == null)
{
// Something went wrong in generating the report.
return false;
}
// Create the PDF document.
out.writeTo(res.getOutputStream());
If all goes well, the class returns true. If not, it returns false. Now, the problem I'm having is if it returns false. Essentially, I want to point blank stop the data from going anywhere. I added the check to make sure things went well, before I write anything to the output stream, so at the moment what I have is a response that is set to PDF type, but contains no data, if something goes wrong that is.
Next, I have a function that will test the output of the class. If it's true, then all is good, but if it is false, then it sets an error parameter:
if(!PdfReportGenerator.generateReport(res, repositoryURI)) {
req.getSession().setAttribute(SDRestServlet.PDF_ERROR, "error");
// This will then re-direct back to the current URL, meaning the page
// looks like it doesn't do anything.
res.sendRedirect(req.getRequestURI());
}
The problem is, this re-directing is really not helping at all. It's messing up other values that are stored in the request and, while it's making the page appear like it's doing nothing, it doesn't allow me to output an error message to the user.
The issue
While I know how to make it seem like the web response is not returning, it means that I can not output any meaningful information to the user, which is obviously not the ideal outcome.
My question
Is there a way to force the servlet to stop, or return something so that the browser ignores the data?
My second question is, if there is something I can send back to the browser, is there anything I can do on the client side to cause a message to pop up (can be as simple as alert())?
I've been as clear as I possibly can be, so if there's anything you need to know, just ask :)
Is there a way to force the servlet to stop, or return something so
that the browser ignores the data?
Please try setting zero response using method "ServletResponse.setContentLength(int)"
My second question is, if there is something I can send back to the
browser, is there anything I can do on the client side to cause a
message to pop up (can be as simple as alert())?
Yes you can but you need to update back header to say "text/html" and set all the variable as you would do in a normal scenario of a server request
SECOND APPROACH:
If I have to build it from scratch, would following following approach:
First make and AJAX call to find whether pdf need to be generated or not
If response is false show error message.
If response is true send request to server to generate PDF
Hopefully I was able to help you a bit here.

How to change the Properties.store() divider symbol from "=" to ":"?

I recently found out about java.util.Properties, which allows me to write and read from a config without writing my own function for it.
I was excited since it is so easy to use, but later noticed a flaw when I stored the modified config file.
Here is my code, quite simple for now:
FileWriter writer = null;
Properties configFile = new Properties();
configFile.load(ReadFileTest.class.getClassLoader().getResourceAsStream("config.txt"));
String screenwidth = configFile.getProperty("screenwidth");
String screenheight = configFile.getProperty("screenheight");
System.out.println(screenwidth);
System.out.println(screenheight);
configFile.setProperty("screenwidth", "1024");
configFile.setProperty("screenheight", "600");
try {
writer = new FileWriter("config.txt" );
configFile.store(writer, null);
} catch (IOException e) {
e.printStackTrace();
}
writer.flush();
writer.close();
The problem I noticed was that the config file I try to edit is stored like this:
foo: bar
bar: foo
foobar: barfoo
However, the output after properties.store(writer, null) is this:
foo=bar
bar=foo
foobar=barfoo
The config file I edit is not for my program, it is for an other application that needs the config file to be in the format shown above with : as divider or else it will reset the configuration to default.
Does anybody know how to easily change this?
I searched through the first 5 Google pages now but found noone with a similar problem.
I also checked the Javadoc and found no function that allows me to change it without writing a class for myself.
I would like to use Properties for now since it is there and quite easy to use.
I also got the idea of just replacing all = with : after I saved the file but maybe someone got a better suggestion?
Don't use a tool that isn't designed for the task - don't use Properties here. Instead, I'd just write your own - should be easy enough.
You can still use a Properties instance as your "store", but don't use it for serializing the properties to text. Instead, just use a FileWriter, iterate through the properties, and write the lines yourself - as key + ": " + value.
New idea here
Your comment about converting the = to : got me thinking: Properties.store() writes to a Stream. You could use an in-memory ByteArrayOutputStream, convert as appropriate in memory before you write to a file, then write the file. Likewise for Properties.load(). Or you could insert FilterXXXs instead. (I'd probably do it in memory).
I was looking into how hard it would be to subclass. It's nearly impossible. :-(
If you look at the source code for Properties, (I'm looking at Java 6) store() calls store0(). Now, unfortunately, store0 is private, not protected, and the "=" is given as a magic constant, not something read from a property. And it calls another private method called saveConvert() that also has a lot of magic constants.
Overall, I rate this code as D- quality. It breaks almost all the rules of good code and good style.
But, it's open source, so, theoretically, you could copy and paste (and improve!) a bunch of code into your own BetterProperties class.

Categories

Resources