MultiPartRequest replaces space with "+" sign - codenameone

I have some arguments in multiPartRequest post along with image. It replaces all spaces with + sign. eg: if titleString is "Hey there", it uploads "Hey+there". I've checked the same api with connectionRequest which works alright.
public static void multipartConnection(String picture, String title, String description) {
if (picture != null) {
MultipartRequest request = new MultipartRequest() {
protected void readResponse(InputStream input) throws IOException {
JSONParser jp = new JSONParser();
Map<String, Object> result = jp.parseJSON(new InputStreamReader(input, "UTF-8"));
}
#Override
protected void postResponse() {
}
};
request.setPost(true);
request.setUrl(urlString);
request.setTimeout(5000);
request.addArgument("title", title);
request.addArgument("description, description);
if (picture != null && !picture.equals("")) {
try {
request.addData("image", picture, "image/jpeg");
request.setFilename("image", "myPicture.jpg");
} catch (IOException err) {
System.out.println("bbeck " + err);
}
}
request.addRequestHeader("Accept", "application/json");
NetworkManager.getInstance().addToQueue(request);
}
}

That's how multipart works: URL encoding the space character: + or %20?
The MultipartRequest class works like a HTML form submit that includes a file. If you try that in a web browser you will see + signs too. If you use proper multipart handling on the server side (which is pretty standard) you will get proper spaces parsed out.

Related

ConnectionRequest is not working in iOS

I've a year & a half old app to update. It was written in statemachine. Now I added a few things but the connectionRequest doesn't seem to work in iOS (which was built for iOS debug). I built it in android and it works very well.
public void connectionForLogin(String username, String password) {
ConnectionRequest cr = new ConnectionRequest() {
#Override
protected void readResponse(InputStream input) throws IOException {
JSONParser jSONParser = new JSONParser();
Map<String, Object> parsedData = jSONParser.parseJSON(new InputStreamReader(input));
ArrayList<Map<String, Object>> response = (ArrayList<Map<String, Object>>) parsedData.get("root");
if (response != null) {
for (Map<String, Object> element : response) {
success = (String) element.get("login");
msg = (String) element.get("msg");
ArrayList<Map<String, Object>> userInfoArray = (ArrayList) element.get("user_info");
Storage.getInstance().writeObject("userInfo", userInfoArray);
}
}
}
#Override
protected void postResponse() {
super.postResponse();
}
#Override
protected void handleErrorResponseCode(int code, String message) {
}
#Override
protected void handleException(Exception err) {
}
#Override
protected void handleIOException(IOException err) {
}
#Override
protected void handleRuntimeException(RuntimeException err) {
}
};
cr.setPost(true);
cr.setDuplicateSupported(true);
cr.setTimeout(30000);
AllUrl au = new AllUrl();
InfiniteProgress ip = new InfiniteProgress();
Dialog d = ip.showInifiniteBlocking();
cr.setDisposeOnCompletion(d);
cr.setUrl(http://zzz.com/api/logins/match? + "username=" + username + "&password=" + password);
NetworkManager.getInstance().addToQueueAndWait(cr);
}
This may be due to new Apple regulations that prevents apps from fetching data from non secure URL http. You can fix this temporarily by adding below build hint:
ios.plistInject=<key>NSAppTransportSecurity</key><dict><key>NSAllowsArbitraryLoads</key><true/></dict><key>CFBundleURLTypes</key><array><dict><key>CFBundleURLName</key><string>com.mycompany.myapp</string></dict><dict><key>CFBundleURLSchemes</key><array><string>MyApp</string></array></dict></array>
Note that your app may be rejected if connected to a non secure URL.

Accept Multipart file upload as camel restlet or cxfrs endpoint

I am looking to implement a route where reslet/cxfrs end point will accept file as multipart request and process. (Request may have some JSON data as well.
Thanks in advance.
Regards.
[EDIT]
Have tried following code. Also tried sending file using curl. I can see file related info in headers and debug output, but not able to retrieve attachment.
from("servlet:///hello").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
Message in = exchange.getIn();
StringBuffer v = new StringBuffer();
HttpServletRequest request = (HttpServletRequest) in
.getHeaders().get(Exchange.HTTP_SERVLET_REQUEST);
DiskFileItemFactory diskFile = new DiskFileItemFactory();
FileItemFactory factory = diskFile;
ServletFileUpload upload = new ServletFileUpload(factory);
List items = upload.parseRequest(request);
.....
curl :
curl -vvv -i -X POST -H "Content-Type: multipart/form-data" -F "image=#/Users/navaltiger/1.jpg; type=image/jpg" http://:8080/JettySample/camel/hello
following code works (but can't use as it embeds jetty, and we would like to deploy it on tomcat/weblogic)
public void configure() throws Exception {
// getContext().getProperties().put("CamelJettyTempDir", "target");
getContext().setStreamCaching(true);
getContext().setTracing(true);
from("jetty:///test").process(new Processor() {
// from("servlet:///hello").process(new Processor() {
public void process(Exchange exchange) throws Exception {
String body = exchange.getIn().getBody(String.class);
HttpServletRequest request = exchange.getIn().getBody(
HttpServletRequest.class);
StringBuffer v = new StringBuffer();
// byte[] picture = (request.getParameter("image")).getBytes();
v.append("\n Printing All Request Parameters From HttpSerlvetRequest: \n+"+body +" \n\n");
Enumeration<String> requestParameters = request
.getParameterNames();
while (requestParameters.hasMoreElements()) {
String paramName = (String) requestParameters.nextElement();
v.append("\n Request Paramter Name: " + paramName
+ ", Value - " + request.getParameter(paramName));
}
I had a similar problem and managed to resolve inspired by the answer of brentos. The rest endpoint in my case is defined via xml:
<restContext id="UploaderServices" xmlns="http://camel.apache.org/schema/spring">
<rest path="/uploader">
<post bindingMode="off" uri="/upload" produces="application/json">
<to uri="bean:UploaderService?method=uploadData"/>
</post>
</rest>
</restContext>
I had to use "bindingMode=off" to disable xml/json unmarshalling because the HttpRequest body contains multipart data (json/text+file) and obviously the standard unmarshaling process was unable to process the request because it's expecting a string in the body and not a multipart payload.
The file and other parameters are sent from a front end that uses the file upload angular module: https://github.com/danialfarid/ng-file-upload
To solve CORS problems I had to add a CORSFilter filter in the web.xml like the one here:
public class CORSFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
ServletException {
HttpServletResponse httpResp = (HttpServletResponse) resp;
HttpServletRequest httpReq = (HttpServletRequest) req;
httpResp.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH");
httpResp.setHeader("Access-Control-Allow-Origin", "*");
if (httpReq.getMethod().equalsIgnoreCase("OPTIONS")) {
httpResp.setHeader("Access-Control-Allow-Headers",
httpReq.getHeader("Access-Control-Request-Headers"));
}
chain.doFilter(req, resp);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
#Override
public void destroy() {
}
}
Also, I had to modify a little bit the unmarshaling part:
public String uploadData(Message exchange) {
String contentType=(String) exchange.getIn().getHeader(Exchange.CONTENT_TYPE);
MediaType mediaType = MediaType.valueOf(contentType); //otherwise the boundary parameter is lost
InputRepresentation representation = new InputRepresentation(exchange
.getBody(InputStream.class), mediaType);
try {
List<FileItem> items = new RestletFileUpload(
new DiskFileItemFactory())
.parseRepresentation(representation);
for (FileItem item : items) {
if (!item.isFormField()) {
InputStream inputStream = item.getInputStream();
// Path destination = Paths.get("MyFile.jpg");
// Files.copy(inputStream, destination,
// StandardCopyOption.REPLACE_EXISTING);
System.out.println("found file in request:" + item);
}else{
System.out.println("found string in request:" + new String(item.get(), "UTF-8"));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "200";
}
I'm using the Camel REST DSL with Restlet and was able to get file uploads working with the following code.
rest("/images").description("Image Upload Service")
.consumes("multipart/form-data").produces("application/json")
.post().description("Uploads image")
.to("direct:uploadImage");
from("direct:uploadImage")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
MediaType mediaType =
exchange.getIn().getHeader(Exchange.CONTENT_TYPE, MediaType.class);
InputRepresentation representation =
new InputRepresentation(
exchange.getIn().getBody(InputStream.class), mediaType);
try {
List<FileItem> items =
new RestletFileUpload(
new DiskFileItemFactory()).parseRepresentation(representation);
for (FileItem item : items) {
if (!item.isFormField()) {
InputStream inputStream = item.getInputStream();
Path destination = Paths.get("MyFile.jpg");
Files.copy(inputStream, destination,
StandardCopyOption.REPLACE_EXISTING);
}
}
} catch (FileUploadException | IOException e) {
e.printStackTrace();
}
}
});
you can do this with restdsl even if you are not using restlet (exemple jetty) for your restdsl component.
you need to turn restdinding of first for that route and reate two classes to handle the multipart that is in your body.
you need two classes :
DWRequestContext
DWFileUpload
and then you use them in your custom processor
here is the code :
DWRequestContext.java
import org.apache.camel.Exchange;
import org.apache.commons.fileupload.RequestContext;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class DWRequestContext implements RequestContext {
private Exchange exchange;
public DWRequestContext(Exchange exchange) {
this.exchange = exchange;
}
public String getCharacterEncoding() {
return StandardCharsets.UTF_8.toString();
}
//could compute here (we have stream cache enabled)
public int getContentLength() {
return (int) -1;
}
public String getContentType() {
return exchange.getIn().getHeader("Content-Type").toString();
}
public InputStream getInputStream() throws IOException {
return this.exchange.getIn().getBody(InputStream.class);
}
}
DWFileUpload.java
import org.apache.camel.Exchange;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import java.util.List;
public class DWFileUpload extends
FileUpload {
public DWFileUpload() {
super();
}
public DWFileUpload(FileItemFactory fileItemFactory) {
super(fileItemFactory);
}
public List<FileItem> parseInputStream(Exchange exchange)
throws FileUploadException {
return parseRequest(new DWRequestContext(exchange));
}
}
you can define your processor like this:
routeDefinition.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
DWFileUpload upload = new DWFileUpload(factory);
java.util.List<FileItem> items = upload.parseInputStream(exchange);
//here I assume I have only one, but I could split it here somehow and link them to camel properties...
//with this, the first file sended with your multipart replaces the body
// of the exchange for the next processor to handle it
exchange.getIn().setBody(items.get(0).getInputStream());
}
});
I stumbled into the same requirement of having to consume a multipart request (containing file data including binary) through Apache Camel Restlet component.
Even though 2.17.x is out, since my project was part of a wider framework / application, I had to be using version 2.12.4.
Initially, my solution drew a lot from restlet-jdbc example yielded data in exchange that although was successfully retrieving text files but I was unable to retrieve correct binary content.
I attempted to dump the data directly into a file to inspect the content using following code (abridged).
from("restlet:/upload?restletMethod=POST")
.to("direct:save-files");
from("direct:save-files")
.process(new org.apache.camel.Processor(){
public void process(org.apache.camel.Exchange exchange){
/*
* Code to sniff exchange content
*/
}
})
.to("file:///C:/<path to a folder>");
;
I used org.apache.commons.fileupload.MultipartStream from apache fileuplaod library to write following utility class to parse Multipart request from a file. It worked successfully when the output of a mulitpart request from Postman was fed to it. However, failed to parse content of the file created by Camel (even through to eyes content of both files looked similar).
public class MultipartParserFileCreator{
public static final String DELIMITER = "\\r?\\n";
public static void main(String[] args) throws Exception {
// taking it from the content-type in exchange
byte[] boundary = "------5lXVNrZvONBWFXxd".getBytes();
FileInputStream fis = new FileInputStream(new File("<path-to-file>"));
extractFile(fis, boundary);
}
public static void extractFile(InputStream is, byte[] boundary) throws Exception {
MultipartStream multipartStream = new MultipartStream(is, boundary, 1024*4, null);
boolean nextPart = multipartStream.skipPreamble();
while (nextPart) {
String headers = multipartStream.readHeaders();
if(isFileContent(headers)) {
String filename = getFileName(headers);
File file = new File("<dir-where-file-created>"+filename);
if(!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
multipartStream.readBodyData(fos);
fos.flush();
fos.close();
}else {
multipartStream.readBodyData(System.out);
}
nextPart = multipartStream.readBoundary();
}
}
public static String[] getContentDispositionTokens(String headersJoined) {
String[] headers = headersJoined.split(DELIMITER, -1);
for(String header: headers) {
System.out.println("Processing header: "+header);
if(header != null && header.startsWith("Content-Disposition:")) {
return header.split(";");
}
}
throw new RuntimeException(
String.format("[%s] header not found in supplied headers [%s]", "Content-Disposition:", headersJoined));
}
public static boolean isFileContent(String header) {
String[] tokens = getContentDispositionTokens(header);
for (String token : tokens) {
if (token.trim().startsWith("filename")) {
return true;
}
}
return false;
}
public static String getFileName(String header) {
String[] tokens = getContentDispositionTokens(header);
for (String token : tokens) {
if (token.trim().startsWith("filename")) {
String filename = token.substring(token.indexOf("=") + 2, token.length()-1);
System.out.println("fileName is " + filename);
return filename;
}
}
return null;
}
}
On debugging through the Camel code, I noticed that at one stage Camel is converting the entire content into String. After a point I had to stop pursuing this approach as there was very little on net applicable for version 2.12.4 and my work was not going anywhere.
Finally, I resorted to following solution
Write an implementation of HttpServletRequestWrapper to allow
multiple read of input stream. One can get an idea from
How to read request.getInputStream() multiple times
Create a filter that uses the above to wrap HttpServletRequest object, reads and extract the file to a directory Convenient way to parse incoming multipart/form-data parameters in a Servlet and attach the path to the request using request.setAttribute() method. With web.xml, configure this filter on restlet servlet
In the process method of camel route, type cast the
exchange.getIn().getBody() in HttpServletRequest object, extract the
attribute (path) use it to read the file as ByteStreamArray for
further processing
Not the cleanest, but I could achieve the objective.

Signing base_string in OAuth

Hi i am trying to implement OAuth1.0 following this tutorial in this tutorial there is a heading OAuthGetRequestToken
in which for getting request token we have to send a post request to URL
www.google.com/accounts/OAuthGetRequestToken
i am sending a post request in my code in google app engine my code is:
public class HelloWorldServlet extends HttpServlet {
#SuppressWarnings({ "unchecked", "unchecked" })
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
resp.getWriter().println("<html><head> <meta name=\"google-site-verification\" content=\"OBFeK6hFEbTkNdcYc-SQNH9tCTpcht-HkUdj6IgCaLg\" </head>");
resp.getWriter().println("<body>Hello, world");
//String post="key=AIzaSyBgmwbZaW3-1uaVOQ9UqlyHAUxvQtHe7X0&oauth_consumer_key=iriteshmehandiratta.appspot.com";
//String param= "&oauth_callback=\"https://www.iriteshmehandiratta.appspot.com\"&scope=\"http://www.google.com/calendar/feeds\"";
//URL url=new URL("https://www.googleapis.com/prediction/v1.5/trainedmodels/10/predict?");
TreeMap<String,String> tree=new TreeMap<String,String>();
tree.put("oauth_version","1.0");
tree.put("oauth_nonce", System.currentTimeMillis()+"");
tree.put("oauth_timestamp",System.currentTimeMillis()/1000+"");
tree.put("oauth_consumer_key", "imehandirattaritesh.appspot.com");
tree.put("oauth_signature_method", "RSA-SHA1");
ServletContext context = getServletContext();
PrivateKey privKey = getPrivateKey(context,"/myrsakey11.pk8");
tree.put("oauth_callback", "https://imehandirattaritesh.appspot.com/authsub");
tree.put("scope", "https://www.google.com/calendar/feeds");
Set set = tree.entrySet();
Iterator<Map.Entry<String, String>> i = set.iterator();
String datastring="";
Map.Entry me=(Map.Entry)i.next();
datastring=me.getKey()+"=";
datastring+=me.getValue();
while(i.hasNext()) {
me = (Map.Entry)i.next();
datastring+="&"+me.getKey()+"=";
datastring+=(me.getValue());
}
String data_string="GET&https://www.google.com/accounts/OAuthGetRequestToken&"+datastring;
byte[] xx11;
String str = null;
try {
xx11 = sign(privKey,data_string);
str=new String(xx11);
resp.getWriter().println(str);
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URL url=new URL("https://www.google.com/accounts/OAuthGetRequestToken?"+str);
// resp.getWriter().println(""+datastring);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection.setRequestProperty("Authorization", " OAuth");
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
resp.getWriter().println( urlConnection.getResponseCode());
String xx="";
String xx1="";
while((xx1=in.readLine()) != null)
{
xx+=xx1;
}
resp.getWriter().println("response");
resp.getWriter().println(xx);
resp.getWriter().println("</body></html>");
}
public static PrivateKey getPrivateKey(ServletContext context,String privKeyFileName) throws IOException {
InputStream resourceContent = context.getResourceAsStream("/WEB-INF/myrsakey11.pk8");
// FileInputStream fis = new FileInputStream(privKeyFile);
DataInputStream dis = new DataInputStream(resourceContent);
#SuppressWarnings("deprecation")
String str="";
String str1="";
while((str=dis.readLine())!=null)
{
str1+=str;
}
String BEGIN = "-----BEGIN PRIVATE KEY-----";
String END = "-----END PRIVATE KEY-----";
// String str = new String(privKeyBytes);
if (str1.contains(BEGIN) && str1.contains(END)) {
str1 = str1.substring(BEGIN.length(), str1.lastIndexOf(END));
}
KeyFactory fac;
try {
fac = KeyFactory.getInstance("RSA");
EncodedKeySpec privKeySpec= new PKCS8EncodedKeySpec(Base64.decode(str1));
return fac.generatePrivate(privKeySpec);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Base64DecoderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
byte[] sign(PrivateKey key, String data) throws GeneralSecurityException {
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(key);
signature.update(data.getBytes());
return signature.sign();
}
}
first i generate data_string then sign it using my private key i get an encrypted string like this
F????T???&??$????????l:v????x???}??U-'?"?????U?[?kr^?G?(? ???qT0??]??j???5??`??$??AD??T??#<t?,#:`V????????????
then i concatenate it with
url : https://www.google.com/accounts/OAuthGetRequestToken?
and i get 400 error obviously it is not a valid uri format so i get this error.i post a query on stackoverflow a person suggest me to use sign method and after signing data_string i will get oauth_signature embedded in the return string which is variable str but in place of oauth_signature included i am getting an encrypted string can any one please tell me how to sign this data_string and what mistake i am doing ??
I would suggest you use an existing Java library for doing the OAuth. It will be much easier in the long term and you won't have to worry about debugging the protocol.

Servlet File concurrency

I have quite a simple question really.
I wrote a servlet for suppliers to upload XML-files to.
These files get written to a location on the server.
All the files get renamed with a timestamp.
Is there a risk of concurrency problems with the code below?
I ask because we receive files from a supplier, that look like
they have content from 2 different XML-files
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
public String getServletInfo() {
return "Short description";
}// </editor-fold>
protected void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
File dirToUse;
boolean mountExists = this.getDirmount().exists();
if (!mountExists) {
this.log("MOUNT " + this.getDirmount() + " does not exist!");
dirToUse = this.getDiras400();
} else {
dirToUse = this.getDirmount();
}
boolean useSimpleRead = true;
if (request.getMethod().equalsIgnoreCase("POST")) {
useSimpleRead = !ServletFileUpload.isMultipartContent(request);
}
if (useSimpleRead) {
this.log("Handle simple request.");
handleSimpleRequest(request, response, dirToUse);
} else {
this.log("Handle Multpart Post request.");
handleMultipart(request, response, dirToUse);
}
}
protected void handleMultipart(HttpServletRequest request,
HttpServletResponse response, File dir) throws IOException,
ServletException {
try {
FileItemFactory fac = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(fac);
List<FileItem> items = upload.parseRequest(request);
if (items.isEmpty()) {
this.log("No content to read in request.");
throw new IOException("No content to read in request.");
}
boolean savedToDisk = true;
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
getFilename(request);
File diskFile = new File(dir, this.getFilename(request));
item.write(diskFile);
if (!diskFile.exists()) {
savedToDisk = false;
}
}
if (!savedToDisk) {
throw new IOException("Data not saved to disk.");
}
} catch (FileUploadException fue) {
throw new ServletException(fue);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
protected void handleSimpleRequest(HttpServletRequest request,
HttpServletResponse response, File dir) throws IOException {
// READINPUT DATA TO STRINGBUFFER
InputStream in = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuffer sb = new StringBuffer();
String line = reader.readLine();
while (line != null) {
sb.append(line + "\r\n");
line = reader.readLine();
}
if (sb.length() == 0) {
this.log("No content to read in request.");
throw new IOException("No content to read in request.");
}
//Get new Filename
String newFilename = getFilename(request);
File diskFile = new File(dir, newFilename);
saveDataToFile(sb, diskFile);
if (!diskFile.exists()) {
throw new IOException("Data not saved to disk.");
}
}
protected abstract String getFilename(HttpServletRequest request);
protected void saveDataToFile(StringBuffer sb, File diskFile) throws IOException {
BufferedWriter out = new BufferedWriter(new FileWriter(diskFile));
out.write(sb.toString());
out.flush();
out.close();
}
getFileName implementation:
#Override
protected String getFilename(HttpServletRequest request) {
Calendar current = new GregorianCalendar(TimeZone.getTimeZone("GMT+1"));
long currentTimeMillis = current.getTimeInMillis();
System.out.println(currentTimeMillis);
return "disp_" + request.getRemoteHost() + "_" + currentTimeMillis + ".xml";
}
Anyway, thanks in advance!
There would not be synchronization problems but there can be race conditions, for example, two threads might return the same file name using the method getFileName()

Serve JSF from database

is it possible to load jsf 2 page from database, not from xhtml file?
Eg., the request comes for /faces/foo.xhtml, FacesServet intercepts request and VieHanlder creates view foo.xhtml by loading foo.xhtml from a DB, not from the server?
Thanks
It is in theory possible if you put it from the database into the public webcontent exactly there where the FacesServlet expect it to be, before it kicks in. A Filter is suitable for the job.
Here's a kickoff example:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String rootPath = req.getSession().getServletContext().getRealPath("/");
String fileName = req.getServletPath().substring(1);
File file = new File(rootPath, fileName);
if (!file.exists()) {
InputStream input = null;
OutputStream output = null;
try {
input = yourDAO.find(fileName);
output = response.getOutputStream();
byte[] buffer = new byte[10240];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
} finally {
if (output != null) try { output.close(); } catch (IOException ignore) {}
if (input != null) try { input.close(); } catch (IOException ignore) {}
}
}
chain.doFilter(request, response);
}
Map this on the <servlet-name> of the FacesServlet.

Resources