Incremental Upload Processing Using FileEntryCallback

compared with
Current by Matthew Cowell
on Aug 23, 2012 10:04.

(show comment)
 
Key
These lines were removed. This word was removed.
These lines were added. This word was added.

View page history


There are 9 changes. View first change.

 h1. Incremental Upload Processing Using FileEntryCallback
  
 {attachments:patterns=file-callback-tutorial.zip}The ACE FileEntry component introduces in-memory file processing. This feature is designed to provide for antivirus scanning, checksum verification or a scenario where the upload doesn't _need_ to be saved to disk, and doing so immediately is excessive I/O.
  
 The functionality requires that a listener bean implement FileEntryCallback to handle the incrementally uploaded bytes.
 Instances of FileEntryCallback must implement:
  
 {code:java}/* Notification for upload handler when a file begins uploading.
  * fileInfo - information known about the file, before downloading the contents */
 public void begin(FileEntryResults.FileInfo fileInfo);
  
 /* We're working with chunks of bytes, as we receive them... */
 public void write(byte[] buffer, int offset, int length);
 public void write(int data);
  
 /* Notification for upload handler that the file is finished. */
 public void end(FileEntryResults.FileInfo fileInfo);
 {code}
 This example demos in-memory processing to provide an MD5 hash for an uploaded file.
 {gallery}{gallery}
  
 \\
 {panel}
 * [*Implementing FileEntryCallback*|#interface]
 * [*Adding the FileEntry Component to Facelet Page*|#addFileFacelet]
 {panel}\\
 ----
 h2. {anchor:interface}Implementing FileEntryCallback
  
 \\
 Creating our handler is the most important step of this tutorial. Everything else is just wiring up the dependant parts.
  
{note:File Attributes}Check fileInfo.getStatus() to determine if the file has pre-failed uploading, due to too many files uploaded, an invalid file extension, or content type.{note}
 * h3. The Class Properties
  {note:File Attributes}Check fileInfo.getStatus() to determine if the file has pre-failed uploading, due to too many files uploaded, an invalid file extension, or content type.{note}* h3. The Class Properties
  
 The MessageDigest class is an Apache Commons class for using one-way hash algorithms like MD5 and SHA.
 {code:title=FileEntryMD5Callback.java|borderStyle=solid} private MessageDigest digest;
private boolean md5NotFound = false;{code}
  
  private boolean md5NotFound = false;
  private List<String> extensionList = Arrays.asList("pptx","ppt","zip","etc"); // List of file types we would like to custom fail{code}
 * h3. The {{begin}} Method
  
 The begin method is where your callback should request any resources it will require.
 The example sets up a MessageDigest object.
 {code:title=FileEntryMD5Callback.java|borderStyle=solid} public void begin(FileEntryResults.FileInfo fileInfo) {
  try { digest = MessageDigest.getInstance("MD5"); }
  catch (NoSuchAlgorithmException e) {
  md5NotFound = true;
  }
  }
 {code}
 
 * h3. The {{write}} Methods
  
 These methods will be passed portions of file data. If there is a chance the file will eventually be saved, the byte input should be cached here.
 This example immediately computes the data as part of our hash.
 {code:title=FileEntryMD5Callback.java|borderStyle=solid} public void write(byte[] bytes, int offset, int length) {
  if (!md5NotFound) digest.update(bytes, offset, length);
  }
  // Hash a single byte
  public void write(int i) {
  if (!md5NotFound) digest.update((byte) i);
  }
 {code}
 
 * h3. The {{end}} Method
  
 This method triggers when a file upload is complete, either successfully or with errors.
If you want to invalidate a successful upload, perhaps it's over quota, then this method should handle the case. It may massage the result (raising some prompts and accepting something), or possibly fail the upload for good by calling FileInfo.updateStatus(...) with the status "FileEntryStatuses.INVALID".
 The example below either prints a custom success FileEntryStatus, a custom MD5 error status, or, in other fail cases, lets the failed status passed to end() propagate to the view.
   
 If you want to invalidate a successful upload, perhaps for certain file types, or if a users account is over quota, then this method should handle the case. It may massage the result (raising some prompts and accepting something), or possibly fail the upload for good by calling FileInfo.updateStatus(...) with the status "FileEntryStatuses.INVALID".
 The example below either prints a custom FileEntryStatus for failure due to an invalid file type, a custom success FileEntryStatus, a custom MD5 error status, or, in other fail cases, lets the failed status passed to end() propagate to the view.
 {code:title=FileEntryMD5Callback.java|borderStyle=solid} // When FileEntryCallback ends for a file:
  public void end(FileEntryResults.FileInfo fileEntryInfo) {
// We can fail the file here for invalid file type, or some other reason
  if (extensionList.contains(FilenameUtils.getExtension(fileEntryInfo.getFileName()))) {
  fileEntryInfo.updateStatus(new InvalidFileStatus(), false);
  }
  // If the file upload was completed properly
if (md5NotFound) {
  else if (md5NotFound) {
  // Work-around for ICEfaces 3.0.0 issue ICE-7712, where setting
  // invalidate=true will mess up the lifecycle. Instead, manually
  // invalidate the form ourselves
  fileEntryInfo.updateStatus(new EncodingNotFoundUploadStatus(), false);
  FacesContext context = FacesContext.getCurrentInstance();
  context.validationFailed();
  }
  else if (fileEntryInfo.getStatus().isSuccess()) {
  fileEntryInfo.updateStatus(new EncodingSuccessStatus(getHash()), false);
  }
  digest = null;
  }
 {code}
  
 ----
 h2. {anchor:addFileFacelet}Adding the FileEntry Component to a Facelet Page
 ----
 Nothing special is required in the facelet of this tutorial. The sample below just has some simple styling and an EL reference to the callback bean.
 {code:title=main.xhtml|borderStyle=solid}<ace:fileEntry id="fileEntry" callback="#{fileMD5EncodingCallback}" styleClass="ib" />
 <h:commandButton styleClass="ib" value="Get MD5 Checksum" />
 <div class="messages-holder"><h:messages styleClass="messages" showDetails="true" /></div>
 <div style="clear:both; height:0px;">&#160;</div>
 {code}
 That concludes this overview of the new in-memory processing feature. If you're interested in further details of how this example works, take a look at the complete source code below; or sign up for ICEfaces training for a complete guide to this example and every feature of ICEfaces\!
  
 {attachments:patterns=file-callback-tutorial.zip}

© Copyright 2018 ICEsoft Technologies Canada Corp.