0 Replies Latest reply on Dec 30, 2010 7:51 AM by cleric

    Download files & filename



      Hello.


      In my application users can upload and download files. And they want to download files with names which they upload. Those can be files with names on different languages. So, i must return their names in UTF-8 encoding.
      But the Seam



      DocumentStoreServlet

      doesn't apply any encoding for this approach.
      For some research i'd gone for conclusion: seam doesn't support all existing browsers.
      i took the DocumentStoreServlet class and I wrote own. It is his source:





      public class MyDocumentStoreServlet extends HttpServlet {
          private static final String ENCODING = "UTF-8";
      
          protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
              new ContextualHttpServletRequest(request) {
                  @Override
                  public void process() throws ServletException, IOException {
                      doWork(request, response);
                  }
              }.run();
          }
      
          private static void doWork(HttpServletRequest request, HttpServletResponse response) throws IOException {
              Parameters params = Parameters.instance();
              String contentId = (String) params.convertMultiValueRequestParameter(params.getRequestParameters(), "docId", String.class);
      
              DocumentStore store = DocumentStore.instance();
      
              if (store.idIsValid(contentId)) {
                  DocumentData documentData = store.getDocumentData(contentId);
      
                  response.setContentType(documentData.getDocumentType().getMimeType());
      
                  new ContentDispositionBuilder(request, response, documentData).build();
      
                  documentData.writeDataToStream(response.getOutputStream());
              } else {
                  String error = store.getErrorPage();
                  if (error != null) {
                      if (error.startsWith("/")) {
                          error = request.getContextPath() + error;
                      }
                      response.sendRedirect(error);
                  } else {
                      response.sendError(404);
                  }
              }
          }
      
          private static class ContentDispositionBuilder {
              private HttpServletRequest request;
      
              private HttpServletResponse response;
      
              private DocumentData documentData;
      
              private String userAgent;
      
              private ContentDispositionBuilder(HttpServletRequest request, HttpServletResponse response, DocumentData documentData) {
                  this.request = request;
                  this.response = response;
                  this.documentData = documentData;
              }
      
              public void build() throws UnsupportedEncodingException {
                  userAgent = request.getHeader("User-Agent").toLowerCase();
      
                  String fileName = buildFileName();
      
                  String fileNameAttr = "filename=";
      
                  if (isIE() || isChrome()) {
                      fileName = "\"" + fileName + "\"";
                  } else {
                      fileNameAttr = fileNameAttr.replace("=", "*=") + ENCODING + "''";
                  }
      
                  response.setHeader("Content-Disposition", documentData.getDisposition() + "; " + fileNameAttr + fileName);
              }
      
              private String buildFileName() throws UnsupportedEncodingException {
                  String fileName = documentData.getFileName();
                  return URLEncoder.encode(fileName, ENCODING).replaceAll("\\+", "%20");
              }
      
              private boolean isFirefox() {
                  return userAgent.contains("gecko");
              }
      
              private boolean isIE() {
                  return userAgent.contains("msie");
              }
      
              private boolean isOpera() {
                  return userAgent.contains("opera");
              }
      
              private boolean isChrome() {
                  return userAgent.contains("webkit");
              }
          }
      }
      
      




      It is a sample of usage this approche:
      1. My facelet messageFile.xhtml:



      <s:resource xmlns="http://www.w3.org/1999/xhtml"
                  xmlns:s="http://jboss.com/products/seam/taglib"
                  data="#{messageFileResource.body}"
                  fileName="#{messageFileResource.fileName}"/>




      and second sample:



      <s:resource xmlns="http://www.w3.org/1999/xhtml"
                  xmlns:s="http://jboss.com/products/seam/taglib"
                  data="#{reqDocumentResource.body}"
                  fileName="#{reqDocumentResource.fileName}"/>





      2. My component:



      public abstract class DownloadFileResource<T> {
          protected byte[] body;
      
          protected String fileName;
      
          public byte[] getBody() {
              return body;
          }
      
          public String getFileName() {
              return fileName;
          }
      
          protected abstract String buildFileName(T o);
      }



      3. And implementation:



      @Name("messageFileResource")
      @Scope(ScopeType.EVENT)
      public class MessageFileResource extends DownloadFileResource<MessageFile> {
          @RequestParameter
          private String name;
      
          @RequestParameter
          private Long messageId;
      
          @In
          private EntityHome<MessageFile> messageFileHome;
      
          @Create
          public void create() throws UnsupportedEncodingException {
              MessageFilePk pk = new MessageFilePk(new Message(messageId), name);
              messageFileHome.setId(pk);
              MessageFile file = messageFileHome.getInstance();
              body = file.getFileBody();
              fileName = buildFileName(file);
              messageFileHome.clearInstance();
          }
      
          @Override
          protected String buildFileName(MessageFile o) {
              return o.getId().getFileName() + "." + o.getContentType();
          }
      }



      In my logic the ContentType is the file extension.


      I think my solution may help for many developers who make applications with internationalized interface and they is cross-browser.