Capture current JSF page content - session

I want to capture the current page and send it to an application that converts it to pdf.
This is what I am using:
FacesContext facesContext=FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)
facesContext.getExternalContext().getResponse();
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
// RequestPrinter.debugString();
response.reset();
// download a pdf file
response.setContentType("application/pdf");
response.setHeader("Content-Disposition","attachment;filename="+new Date().toString()+".pdf");
prince.setVerbose(true);
prince.setLog(logFile);
try{
//getPath() to the page the user is currently on
URL pagePath=new URL(this.getPath());
URLConnection urlConnection = pagePath.openConnection();
urlConnection.setDoOutput(true);
int length = urlConnection.getContentLength();
//Lets use inputStream
BufferedInputStream bis=new BufferedInputStream(urlConnection.getInputStream());
response.setContentLength(length);
//this.getPageUsingJSoup().data().getBytes();
//call prince and pass params for inputstream outputStream
prince.convert(bis,response.getOutputStream());
urlConnection.getInputStream().close();
}catch(MalformedURLException mu){
mu.printStackTrace();
}
catch(IOException ioe){
ioe.printStackTrace();
}
facesContext.responseComplete();
Since the website requires authentication, the pdf generated is the loging error page.
Is there a way to capture the page's content that uses the current user's session?
Thank you in advance.

Just request the page in the same HTTP session as the current request. If your webapp supports URL rewriting (as by default), then just append session ID as jsessionid path fragment:
String sessionId = ((HttpSession) externalContext.getSession()).getId();
InputStream input = new URL("http://localhost:8080/context/page.jsf;jsessionid=" + sessionId).openStream();
// ...
Or if your webapp doesn't accept URL rewriting, but accepts cookies only, then set it as a request cookie the usual way:
URLConnection connection = new URL("http://localhost:8080/context/page.jsf").openConnection();
connection.setRequestProperty("Cookie", "JSESSIONID=" + sessionId);
InputStream input = connection.getInputStream();
// ...
Note that I removed setDoOutput() since you don't seem to be interested in performing a POST request.

I do not know how to capture the page's content using the current user's session, but I can suggest another way to do it - you could move the pdf conversion logic inside a Selenium test-case and use the test-case to navigate and login to the page requiring authentication. After the automated tc has logged in, you could call your pdf conversion logic...?

Yes of course there is. You are sending this content, so you have it. You should store the Content Object. If you dont have it, inspect your byte streams. The content should be there ;)

There of couple of websites which allow you to convert the entire page to pdf and save it as .pdf file. Try out the site http://pdfcrowd.com/ Hope this helps you.

Related

Spring RestTemplate API query parameter encoding for doing a GET HTTP Request

The url-string contains a back-slash character that needs to be encoded. The url string is as follows.
String folder = "\\Foo\\Bar\\"; // some folder search path.
String urlString= "http://localhost:8081/certificates/?mypath=%5CFoo%5CBar%5C" // (after encoding)
Here I use Spring RestTemplate to do a GET request. I setup a mock-server to examine the request in detail (mock server setup using Mulesoft, if u must know!).
ResponseEntity<String> responseEntity = api.exchange(urlString, HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), String.class);
Here I use plain vanilla Java URLConnection to perform the request. Attached image with detailed request snapshot.
// 2. Plain vanilla java URLConnection. "result.toString()" has certificate match.
StringBuilder result = new StringBuilder();
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("X-Venafi-Api-Key", apiKey);
conn.setRequestMethod("GET");
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
result.append(line);
}
rd.close();
System.out.println(result.toString());
In the images, you can see that the queryString value is different for these two requests. One of them shows \\ while the other shows %5C, although the parsed parameter value for myPath is still the same.
I am having to deal with an api that seems to work if-and-only-if the queryString looks like the former (i.e. "\\"). Why does the parsed queryString for Spring show "%5C" while this value shows double-backslash for requests originating from plain Java, curl, and even a simple browser?
What baffles me EVEN more, is that just about everything about the two HTTP Requests are IDENTICAL! And yet, why does the queryString/requestUri parse differently for these two requests? Shouldn't it be that a HTTP GET method is completely defined by its header contents and the requestUri? What am I missing to capture in these two GET requests?
Lots of questions. Spent an entire day, but at least I could verify that the way the requestUri/queryString is parsed seems to align with how the remote api-server responds.
Thanks.
Did some digging around the following morning. Turn out, with
ResponseEntity<String> responseEntity = api.exchange(urlString, HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), String.class);
You should NOT have the "urlString" already encoded. The 'exchange' method does that encoding for you under-the-hood.

Sending Images to the client from tomcat server

I am building a framework for e-commerce site. I have used jersey to create REST APIs. I need to send images to the clients as per the request.
How can I do so from my application server as Tomcat and jersey as REST API?
Since I am new to this, I have no clue how to send images to an Android client when they are shown as item.
Every resource is identified by the URI, client will ask for a particular image or a bunch of images by quering the URL, So you just need to expose a service, following service is an example to send single image to client.
#GET
#Path("/images/{imageId}")
#Produces("image/png")
public Response downloadImage(#PathParam("imageId") String imageId) {
MultiMediaDB imageDb = new MultiMediaDB();
String filePath = imageDb.getImage(imageId);
File file = new File(filePath);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition",
"attachment; filename=\"fileName.png\"");
return response.build();
}
MultiMediaDB is my custom class to get the file location from the DB, you can hardcode it as of now for testing purpose like D:\server_image.png.
You need to mention Content-Disposition as an attachment so that file will not be downloaded, instead attached to the form. In android you just need to read inputstream from a HttpURLConnection object and send that to bitmap as shown below
URL url = new URL(BaseUrl + "/images/" + imageId);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
iStream = urlConnection.getInputStream();
bitmap = BitmapFactory.decodeStream(iStream);
The you can set that bitmap to imageview or what ever you have as a container.

Storing a (possibly large) file between requests in Spring

I have this controller methods that depending on the parameters introduced by the user downloads a certain PDF file and shows a view with its different pages converted to PNG.
So the way I approached it works like this:
First I map a method to receive the post data sent by the user, then generate the URL of the actual PDF converter and pass it to the model:
#RequestMapping(method = RequestMethod.POST)
public String formPost(Model model, HttpServletRequest request) {
//Gather parameters and generate PDF url
Long idPdf = Long.parseLong(request.getParam("idPdf"));
//feed the jsp the url of the to-be-generated image
model.addAttribute("image", "getImage?idPdf=" + idPdf);
}
Then in getImageMethod I download the PDF and then generate a PNG out of it:
#RequestMapping("/getImage")
public HttpEntity<byte[]> getPdfToImage(#RequestParam Long idPdf) {
String url = "myPDFrepository?idPDF=" + idPdf;
URL urlUrl = new URL(url);
URLConnection urlConnection;
urlConnection = urlUrl.openConnection();
InputStream is = urlConnection.getInputStream();
return PDFtoPNGConverter.convert(is);
}
My JSP just has an img tag that refers to this url:
<img src="${image}" />
So far this work perfectly. But now I need to allow the possibility of viewing multi page PDFs, converted as PNGS, each of them in a different page. So I would add a page parameter, then feed my model with the image url including that page parameter, and in my getImage method I would convert only that page.
But the way it is implemented, I would be downloading the PDF again for each page, plus an additional time for the view, so it can find out whether this specific PDF has more pages and then show the "prev" and "next" buttons.
What would be a good way to preserve the same file during these requests, so I download it just once? I thought about using temp files but then managing its deletion might be a problem. So maybe storing the PDF in the session would be a good solution? I don't even know if this is good practice or not.
I am using Spring MVC by the way.
I think the simplest way would be using spring cache abstraction. Look at tutorial and will need to change your code a little: move logic that load pdf to separate class.
it will looks like:
interface PDFRepository {
byte[] getImage(long id);
}
#Repository
public class PDFRepositoryImpl implements PDFRepository {
#Cacheable
public byte[] getImage(long id) {
String url = "myPDFrepository?idPDF=" + idPdf;
URL urlUrl = new URL(url);
URLConnection urlConnection;
urlConnection = urlUrl.openConnection();
InputStream is = urlConnection.getInputStream();
return PDFtoPNGConverter.convert(is);
}
}
You will get pluggable cache implementation support and good cache expiration management.

p:commandButton does not open window with update

I generate an exportList in my Bean:
public void exportExcel() throws WriteException {
try {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"hours.xls\";");
OutputStream out = response.getOutputStream();
WorkbookSettings ws = new WorkbookSettings();
ws.setLocale(new Locale("de", "DE"));
WritableWorkbook workbook = Workbook.createWorkbook(out, ws);
WritableSheet sheet = workbook.createSheet("Sheet1", 0);
sheet.addCell(new Label(0, 0, "ID", bold));
int row = 1;
for (Hour hour : this.listHours) {
sheet.addCell(new Label(0, row, String.valueOf(hour.getId())));
row++;
}
SheetFormatter.setOptimalColumnWidth(sheet);
workbook.write();
workbook.close();
response.flushBuffer();
context.responseComplete();
context.addMessage(null, new FacesMessage("Liste Exportiert"));
}
catch (Exception e) {
}
}
In my page I call method in p:commandButton
<p:commandButton value="#{msg.export}" update="growl"
immediate="true" action="#{hoursView.exportExcel()}" />
My page will not open the excel-List... If if add the attribute ajax="false" it works but then update will not execute...
For information my Bean is SessionScoped if this makes some differences
Your first mistake is that you're trying to download a file using ajax. That just isn't possible. Ajax is executed by JavaScript code which has due to security reasons no facilities to force a "Save as" dialogue and/or write the retrieved response to the local disk file system. That would otherwise open doors to various nasty security breach possibilities.
So, using ajax="false" is absolutely necessary.
Your second mistake is that you're trying to mix different responses into a single response. That just isn't possible. You can only return either a file download, or an ajax update, not both. To retrieve two different responses, you basically need to let the client send two different requests. You could approach this as follows:
Let client send an ajax request to backing bean.
Let server create and save Excel file in server's temporary storage system and generate an unique URL so that it could be accessed by a servlet.
Let server send an ajax response containing the message and the URL.
Let client display the message and invoke a new GET request on the URL. You could use window.location=url; to let JavaScript invoke a new GET request on the URL.

Dispatcher.forward and response.flush() in AJAX

I'm working on a Java EE based application and we are heavily using AJAX there.
In there we use two type of techniques to write ajax response.
1) Pass some data throgh ajax
res.setContentType("text/xml");
res.setHeader("Cache-Control", "no-cache");
PrintWriter writer = null;
writer = res.getWriter();
StringBuffer xmlDoc = new StringBuffer("<?xml version='1.0'?>");
xmlDoc.append("<selectChoice>");
xmlDoc.append("<selectElement>");
writer.print(xmlDoc.toString());
writer.flush();
writer.close();
2)send complete jsp fragment via ajax
firstly ajax call servlet,
then servlet set some variable sessions,
and then forward into jsp page rendered the variable stored previously
RequestDispatcher disp = context.getRequestDispatcher(APP_pagePath + page);
disp.forward((HttpServletRequest)req, res);
in the first one as a standard practise we use flush() method. Then my question is how it is handling on second scenario (dispatcher.forward). In there we do not explicitly flush(). can you guys please explain the difference between these two and how the flushing handles in second scenario.

Resources