3 Replies Latest reply on Jun 10, 2014 6:31 AM by michpetrov

    richfaces 4 mediaOutput throwing PropertyNotFoundException

    pramanish

      Hi,

       

      I am using richfaces 4.3.6 Final along with JSF 2 and wildfly-8.1.0.CR1. In my application I am uploading image and showing that uploaded image into <rich:mediaOutput> but I am getting below exception while rendering <rich:mediaOutput> .Below is my xhtml and java code, please take a look at this and let me know If I am doing anything wrong.

       

      Any workaround or solution to fix it.

       

      Thanks in advance.

       

      upload.xhtml

       

      <ui:composition xmlns="http://www.w3.org/1999/xhtml"

          xmlns:ui="http://java.sun.com/jsf/facelets"

          xmlns:h="http://java.sun.com/jsf/html"

          xmlns:f="http://java.sun.com/jsf/core"

          xmlns:a4j="http://richfaces.org/a4j"

          xmlns:rich="http://richfaces.org/rich"

          xmlns:c="http://java.sun.com/jsp/jstl/core"

          xmlns:s="http://jboss.org/schema/seam/taglib"

          xmlns:cu="http://ext.test.com/cu/functions"

          xmlns:el="http://ext.test.com/el/functions">

       

          <h:form id="docupload" style="margin-left:5px; width: 100%;">

              <h:messages layout="horizontal" globalOnly="true" showDetail="false"

                  showSummary="true" />

       

              <c:choose>

                  <c:when test="#{featureConfig.OFLOWS_MOBILIZED_ENABLED().booleanValue() eq 'true' and themeResolver.canvasEnabled}">

                  <br/>

                      <span id="submitButton"> <s:link styleClass="button" view="/oconsole/appuploadhelper.seam"

                          ><span>Upload

                                  Documents</span>

                                      <s:conversationPropagation type="join"></s:conversationPropagation>

                                  </s:link>

                      </span>

                      <br/>

                      <br/>

                  </c:when>

                  <c:otherwise>

                      <rich:fileUpload  fileUploadListener="#{fileUploadBean.listener}"

                          maxFilesQuantity="#{fileUploadBean.uploadsAvailable}" id="upload"

                          immediateUpload="false"

                          acceptedTypes="jpg,gif,png,pdf,bmp,tif,tiff,jpeg"

                          allowFlash="#{featureConfig.ENABLE_FLASH_UPLOADS()}"

                          style="width:100%;"

                          disabled="#{appRequest.checkApplicationsStatus()}">

                          <a4j:ajax event="uploadcomplete" render="info" />

                      </rich:fileUpload>

                  </c:otherwise>

              </c:choose>

       

       

              <p>Once you've uploaded your documents, classify each one using

                  the categories below.</p>

       

              <rich:panel bodyClass="info" id="info">

                  <f:facet name="header">

                      <h:outputText value="Classify uploaded documents" />

                  </f:facet>

                  <h:outputText value="No files currently uploaded"

                      rendered="#{fileUploadBean.size==0}" />

                  <s:div id="docuploadTable" style="border:none;">

                      <c:forEach items="#{fileUploadBean.files}" var="file"

                          varStatus="row">

                          <s:div id="docRow#{row.index}" styleClass="documentRow">

                              <s:div id="docImageCol#{row.index}"

                                  styleClass="docUploadImageColumn">

                                  <a4j:mediaOutput id="docImage#{row.index}" element="img"

                                      mimeType="#{file.mime}" createContent="#{fileUploadBean.paint}"

                                      value="#{row.index}" style="max-width:200px;" cacheable="false">

                                      <f:param value="#{fileUploadBean.timeStamp}" name="time" />

                                      <s:conversationId value="#{conversation.id}" />

                                  </a4j:mediaOutput>

                              </s:div>

                              <s:div id="docCategoryCol#{row.index}"

                                  styleClass="docUploadCategoryColumn">

                                  <h:selectOneMenu id="docCategory#{row.index}" name="docCategory" value="">

                                      <el:setValueBinding var="selectionmap"

                                          valueBinding="#{fileUploadBean.documentCategory}" />

                                      <s:selectItems var="selection"

                                          value="#{selectionmap.entrySet()}" label="#{selection.value}"

                                          itemValue="#{selection.key}" hideNoSelectionLabel="true" />

                                  </h:selectOneMenu>

                              </s:div>

                          </s:div>

                          <br class="clearfloat" />

                          <br class="clearfloat" />

                      </c:forEach>

                  </s:div>

              </rich:panel>

       

              <br />

              <span id="uploadSaveBtn"> <a4j:commandLink id="saveLink"

                      onclick="replaceWithSpinner(this);"

                      action="#{fileUploadBean.saveSupportingDocuments()}"

                      styleClass="button" render="docupload">

                      <s:conversationPropagation type="join"></s:conversationPropagation>

                      <span>Save</span>

                  </a4j:commandLink>

              </span>

          </h:form>

      </ui:composition>

       

      DocUploadBean.java


      package com.test.seam.action.oweb;

       

      import static org.apache.commons.lang3.ArrayUtils.isEmpty;

      import static org.apache.commons.lang3.StringUtils.isEmpty;

       

      import java.awt.image.BufferedImage;

      import java.io.BufferedInputStream;

      import java.io.ByteArrayInputStream;

      import java.io.ByteArrayOutputStream;

      import java.io.IOException;

      import java.io.OutputStream;

      import java.io.Serializable;

      import java.util.ArrayList;

      import java.util.Collection;

      import java.util.Date;

      import java.util.HashMap;

      import java.util.Iterator;

      import java.util.List;

      import java.util.Map;

       

      import javax.el.ELContext;

      import javax.faces.application.FacesMessage;

      import javax.faces.component.UIComponent;

      import javax.faces.component.html.HtmlSelectOneMenu;

      import javax.faces.context.FacesContext;

      import javax.imageio.ImageIO;

       

      import org.apache.commons.lang3.StringUtils;

      import org.jboss.seam.Component;

      import org.jboss.seam.ScopeType;

      import org.jboss.seam.annotations.AutoCreate;

      import org.jboss.seam.annotations.Begin;

      import org.jboss.seam.annotations.Create;

      import org.jboss.seam.annotations.Destroy;

      import org.jboss.seam.annotations.End;

      import org.jboss.seam.annotations.Factory;

      import org.jboss.seam.annotations.In;

      import org.jboss.seam.annotations.Name;

      import org.jboss.seam.annotations.Scope;

      import org.jboss.seam.annotations.Synchronized;

      import org.jboss.seam.annotations.web.RequestParameter;

      import org.jboss.seam.contexts.Contexts;

      import org.jboss.seam.core.Conversation;

      import org.jboss.seam.log.Log;

      import org.jboss.seam.log.Logging;

      import org.jboss.seam.ui.component.html.HtmlDiv;

      import org.richfaces.event.FileUploadEvent;

      import org.richfaces.model.UploadedFile;

       

      import com.drew.imaging.ImageMetadataReader;

      import com.drew.metadata.Metadata;

      import com.drew.metadata.exif.ExifIFD0Directory;

      import com.drew.metadata.exif.ExifSubIFDDirectory;

      import com.lowagie.text.DocumentException;

      import com.lowagie.text.Image;

      import com.lowagie.text.PageSize;

      import com.lowagie.text.pdf.PdfContentByte;

      import com.lowagie.text.pdf.PdfCopyFields;

      import com.lowagie.text.pdf.PdfImportedPage;

      import com.lowagie.text.pdf.PdfReader;

      import com.lowagie.text.pdf.PdfWriter;

      import com.lowagie.text.pdf.RandomAccessFileOrArray;

      import com.lowagie.text.pdf.codec.TiffImage;

      import com.test.seam.entity.ApplicationRequest;

      import com.test.seam.entity.Customer;

      import com.test.seam.entity.Document;

      import com.test.seam.entity.DocumentImage;

      import com.test.seam.entity.InputField;

      import com.test.seam.entity.RawSupportingDocument;

      import com.test.seam.entity.SupportingDocument;

      import com.test.seam.entity.UserType;

      import com.test.seam.infrastructure.ELEvaluator;

      import com.test.seam.infrastructure.UserContext;

      import com.test.seam.session.oconsole.OConsoleDocUploadManagerBean;

      import com.test.seam.session.oconsole.ProductsInfo;

      import com.test.seam.session.oweb.DocUploadManager;

      import com.test.seam.session.oweb.DocUploadManagerBean;

      import com.test.seam.util.PDFToImageConvertor;

      import com.test.seam.web.util.PageScopeUtil;

       

       

      @Name(DocUploadBean.COMPONENT_NAME)

      @Scope(ScopeType.CONVERSATION)

      // TODO: change this to page scope and fix the interaction

      @Synchronized(timeout = 100000)

      @AutoCreate

      public class DocUploadBean implements Serializable {

       

          private static final int MAX_FILE_SIZE_IN_DATABASE = 5 * 1014 * 1024;

       

          public static final String COMPONENT_NAME = "fileUploadBean";

       

          /**

           *

           */

          private static final long serialVersionUID = 5339410002696528789L;

       

          // http://itextdocs.lowagie.com/tutorial/general/index.php - See Step 1, and

          // description of margin width

          private static final float ONE_INCH = 72.0f;

       

          private String customerLevelUpload;

       

          public String getCustomerLevelUpload() {

              return customerLevelUpload;

          }

       

          public void setCustomerLevelUpload(String customerLevelUpload) {

              this.customerLevelUpload = customerLevelUpload;

          }

       

          private static final float MAX_CONTENT_WIDTH = PageSize.LETTER.getWidth() - ONE_INCH; // 1 inch margin

          private static final float MAX_CONTENT_HEIGHT = PageSize.LETTER.getHeight() - ONE_INCH; // 1 inch margin

       

          private boolean decisionTableEnabled;

          // @In (create=true) DocUploadManager docUploadManager;

          private static Log log = Logging.getLog(DocUploadBean.class);

       

          @In

          UserContext userContext;

       

          @In(required=false, create=false)

          ApplicationRequest appRequest;

       

          @Create

          @Begin(join=true)

          public void create(){

              log.debug("Creating DocUploadBean in conversation: " +Conversation.instance().getId() );

          }

       

          @Destroy

          public void remove(){

              log.debug("Destroying DocUploadBean in conversation: " +Conversation.instance().getId() );

          }

       

       

          public static String className = DocUploadManagerBean.class.getName();

       

          // files holds atomic support docs.  each page in a multi page pdf is separated

          // into individual pdf doc that can be used as different supporting documents.

          // e.g. a multipage pdf has 1 page of passport img, 1 page of insurance id

          // This will get separated into 2 pdf docs and stored in files

          private ArrayList<DocumentAndCategory> files = new ArrayList<DocumentAndCategory>();

       

          // separate compound supporting documents into individual page of separate pdf docs

          // private List<DocumentAndCategory> atomicSupportingDocs;

       

       

          private int uploadsAvailable = 10;

          private boolean autoUpload = false;

          private boolean useFlash = false;

          //private SupportingDocumentCategory defaultCategory = SupportingDocumentCategory.BANK_STATEMENT;

          //private List<SupportingDocumentCategory> documentCategory;

       

          public int getSize() {

              if (getFiles().size() > 0) {

                  return getFiles().size();

              } else {

                  return 0;

              }

          }

       

          public DocUploadBean() {

       

          }

       

          public void paint(OutputStream stream, Object object) throws IOException {

              log.debug("DocUploadBean.paint()");

              log.debug("size: " + files.size());

              log.debug("index: " + object);

              stream.write(getFiles().get((Integer) object).getData());

          }

       

          public void listener(FileUploadEvent event) throws Exception {

              log.debug(className +".listener() is called to convert and store uploaded files.");

              PageScopeUtil pageScopeUtil = PageScopeUtil.instance();

              pageScopeUtil.setErrMsg(null);//clear if previous request had errors, note cannot use event scope for the uploader as the upload is its own request

              UploadedFile item = event.getUploadedFile();

              //By default this flag variable will be false. When user is on validate decision table

              //tab in console page that time, this flag variable will be true means it will  invoke code

              //related to validating decision table which is in else section of this condition.

              if(!decisionTableEnabled){

       

                  RawSupportingDocument rawDocument = createRawDocument(item);

                  saveRawDocument(rawDocument);

       

                  if (!isEmpty(rawDocument.getDocumentImage().getContent())) {

                      log.info("Processing uploaded file '#0'", rawDocument.getDocumentImage().getFileName());

                      try{

                          if (StringUtils.endsWithIgnoreCase(item.getName(), ".pdf")) {

                              log.debug("process uploaded pdf file");

                              preparePdf(rawDocument.getDocumentImage().getFileName(), rawDocument.getDocumentImage().getContent());

                          } else if (StringUtils.endsWithIgnoreCase(item.getName(), ".tif")

                                  || StringUtils.endsWithIgnoreCase(item.getName(), ".tiff")) {

                              log.debug("process uploaded tiff file");

                              prepareTiff(item.getName(), rawDocument.getDocumentImage().getContent());

                          } else {

                              log.debug("process uploaded file (jpg,gif,png,pdf,bmp)");

                              prepareImage(item.getName(), rawDocument.getDocumentImage().getContent());

                          }

                      } catch(PDFSecurityException pse){

                          String errMsg = "Your PDF document has security settings that prevented us from processing it.";

                          pageScopeUtil.setErrMsg(errMsg);

                          log.error(errMsg, pse);

                          return;

                      }catch(Throwable t){

                          String errMsg = "There is some problem with the uploaded file, we can't process it.";

                          pageScopeUtil.setErrMsg(errMsg);

                          log.error(t, t.getMessage());

                          return;

                      }

                  }

                  uploadsAvailable--;

              } else {

                  validateDecisionTable(item);

              }

          }

       

          private void prepareImage(String fileName, byte[] data) throws Exception {

              files.add(extractPageFromImage(data, fileName, null));

          }

       

          private DocumentAndCategory extractPageFromImage(final byte[] data, final String fileName, String documentCategory) throws Exception {

              // pdf wrapper around the image

              DocumentAndCategory pdfDoc = new DocumentAndCategory();

              pdfDoc.setName(fileName);

              pdfDoc.setDocumentCategory(documentCategory);

              byte[] pdfBytes = convertOtherToPDFDoc(data);

              pdfDoc.setPdfByte(pdfBytes);

       

              // the image

              pdfDoc.setData(data);

              pdfDoc.setLength(data.length);

              return pdfDoc;

          }

       

          private DocumentAndCategory extractPageFromImage(byte[] data, String fileName) throws Exception {

              return extractPageFromImage(data, fileName, null);

          }

       

          private void prepareTiff(String fileName, byte[] data) throws Exception {

              final List<DocumentAndCategory> docs = extractPagesFromTiff(data, fileName, null);

              for (DocumentAndCategory doc: docs) {

                  files.add(doc);

              }

          }

       

          private List<DocumentAndCategory> extractPagesFromTiff(final byte[] data,

                  String fileName, String documentCategory) throws Exception {

              // convert each page in the tiff into a separate pdf

              // note each tiff image can have multiple pages

              List<byte[]> pdfByteList = convertTiffToPDFDocs(data);

       

              final List<DocumentAndCategory> docs = new ArrayList<DocUploadBean.DocumentAndCategory>();

       

              // store each pdf in this.files list, also include the thumb nails

              for (int c = 0; c < pdfByteList.size(); c++) {

                  DocumentAndCategory pdfDoc = new DocumentAndCategory();

                  // store the pdf for each page

                  pdfDoc.setName(fileName);

                  pdfDoc.setDocumentCategory(documentCategory);

                  byte[] pdfBytes = pdfByteList.get(c);

                  pdfDoc.setPdfByte(pdfBytes);

       

                  // store the thumb nail image

                  List<byte[]> imageBytesList = convertPDFToImagePages(pdfBytes, true);

                  byte[] imageBytes = imageBytesList.get(0);

                  pdfDoc.setData(imageBytes);

                  pdfDoc.setLength(imageBytes.length);

                  docs.add(pdfDoc);

              }

              return docs;

          }

       

          private Collection<DocumentAndCategory> extractPagesFromTiff(byte[] data, String fileName) throws Exception {

              return extractPagesFromTiff(data, fileName, null);

          }

       

          private void preparePdf(String fileName, byte[] data) throws Exception {

              final List<DocumentAndCategory> docs = extractPagesFromPdf(data, fileName, null);

              for (DocumentAndCategory doc: docs) {

                  files.add(doc);

              }

          }

       

          private List<DocumentAndCategory> extractPagesFromPdf(final byte[] data, final String fileName, String documentCategory) throws Exception {

              // separate the pdf into separate pages, one page per doc

              List<byte[]> pdfByteList = separatePDFPages(data);

       

              // get the individual page image

              List<byte[]> imageBytesList = convertPDFToImagePages(data, true);

       

              final List<DocumentAndCategory> docs = new ArrayList<DocUploadBean.DocumentAndCategory>();

       

              // save each jpg image in the files object.  files object is later used to categorize each doc.

              for (int c = 0; c < imageBytesList.size(); c++) {

                  DocumentAndCategory pdfDoc = new DocumentAndCategory();

                  // store the pdf for each page

                  pdfDoc.setName(fileName);

                  pdfDoc.setDocumentCategory(documentCategory);

                  byte[] pdfBytes = pdfByteList.get(c);

                  pdfDoc.setPdfByte(pdfBytes);

       

                  // store the thumb nail image

                  byte[] imageBytes = imageBytesList.get(c);

                  pdfDoc.setData(imageBytes);

                  pdfDoc.setLength(imageBytes.length);

                  docs.add(pdfDoc);

              }

              return docs;

          }

       

          private List<DocumentAndCategory> extractPagesFromPdf(byte[] data, String fileName) throws Exception {

              return extractPagesFromPdf(data, fileName, null);

          }

       

          private void saveRawDocument(RawSupportingDocument rsd) {

              log.info("Saving File Name: #0, Content Type: #1", rsd.getDocumentImage().getFileName(), rsd.getDocumentImage().getMimeType());

              String componentName = "";

              if (userContext.getNamespace().getUserType() == UserType.OFFICER)

                  componentName = OConsoleDocUploadManagerBean.COMPONENT_NAME;

              else

                  componentName = DocUploadManagerBean.COMPONENT_NAME;

              DocUploadManager docUploadManager = (DocUploadManager) Component

                      .getInstance(componentName);

              docUploadManager.saveRaw(rsd);

          }

       

          private RawSupportingDocument createRawDocument(UploadedFile item) throws IOException {

              DocumentImage d = new DocumentImage();

              // TODO: item.isTempFile() -- alternate in RF4?

      //        if (item.isTempFile()) {

      //            if (item.getFile().length() < MAX_FILE_SIZE_IN_DATABASE) {

      //                log.info("Loading file '#0' (#1K) into DB", item.getName(), item.getFile().length() / 1024);

      //                FileInputStream fileInput = null;

      //                try {

      //                    fileInput = new FileInputStream(item.getFile());

      //                    d.setContent(IOUtils.toByteArray(fileInput));

      //                } finally {

      //                    IOUtils.closeQuietly(fileInput);

      //                }

      //                try {

      //                    item.getFile().delete();

      //                } catch (Exception e) {

      //                    log.warn("Can't remove uploaded file '#0'", e, item.getFile().getAbsolutePath());

      //                }

      //            } else {

      //                log.info("Uploaded file '#0' is to big (#1K), leaving it in the file system", item.getName(), item.getFile().length() / 1024);

      //                d.setFilePath(item.getFile().getAbsolutePath());

      //            }

      //        } else {

                  log.info("Loading file '#0' (#1K) into DB", item.getName(), item.getData().length / 1024);

                  d.setContent(item.getData());

      //        }

              d.setFileName(item.getName());

              d.setDescription(item.getName());

              d.setMimeType(item.getContentType());

              d.setLabel(item.getName());

       

              RawSupportingDocument rsd = new RawSupportingDocument();

              rsd.setDocumentImage(d);

              return rsd;

          }

       

          /**

           * Use by console to save uploaded supporting docs

           */

          public void saveSupportingDocuments() {

              try {

                  saveSupportingDocuments(OConsoleDocUploadManagerBean.COMPONENT_NAME);

                  FacesContext.getCurrentInstance().addMessage(

                          null,

                          new FacesMessage(FacesMessage.SEVERITY_INFO,

                                  "Supporting Documents are uploaded", null));

              } catch (Exception e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

          }

       

          /**

           * responsible for saving uploaded document from docupload.xhtml in app

           * It will append the new supporting doc to the existing set in the database

           *

           * @param componentName

           */

          public void saveSupportingDocuments(String componentName) {

              saveSupportingDocuments(componentName, true);

              clearUploadData();

          }

          /**

           * This method is responsible for saving the changes made on already

           * uploaded supporting documents on Re-categorization of supporting

           * documents page.

           *

           * It will not append.  Instead it will erase what is in db and than save

           *

           */

          public void saveRecategorizedSupportingDocuments() {

              saveSupportingDocuments(DocUploadManagerBean.COMPONENT_NAME, false);

       

          }

       

       

          /**

           * helper function to save supporting documents.

           *

           * @param componentName

           * @param isAppend

           */

          @End

          public void saveSupportingDocuments(String componentName, boolean isAppend) {

              try {

                  UIComponent dependenciesComp = FacesContext.getCurrentInstance().getViewRoot().findComponent("docupload:docuploadTable");

                  HtmlDiv html = (HtmlDiv) dependenciesComp;

                  // setup categorizedDocMap which maps category to each file in this.files (contains jpg image)

                  Map<String, List<DocumentAndCategory>> categorizedDocMap = new HashMap<String, List<DocumentAndCategory>>();

                  for (int i = 0; i < html.getChildren().size(); i++) {

                      DocumentAndCategory file = files.get(i);

       

                      // process those not mark for delete

                      if (file.getMarkForDelete()==false) {

                          HtmlDiv innerDiv = (HtmlDiv) html.getChildren().get(i);

                          HtmlSelectOneMenu selectMenu = (HtmlSelectOneMenu) innerDiv.getChildren().get(1).getChildren().get(0);

                          if(selectMenu != null && selectMenu.getValue() != null){

                              String category = selectMenu.getValue().toString();

                              if (categorizedDocMap.get(category) != null) {

                                  List<DocumentAndCategory> documentList = categorizedDocMap.get(category);

                                  documentList.add(file);

                              } else {

                                  List<DocumentAndCategory> documentList = new ArrayList<DocumentAndCategory>();

                                  documentList.add(file);

                                  categorizedDocMap.put(category, documentList);

                              }

                          }else{

                              log.warn("Uploaded supporting document was not categorized.");

                          }

                      }

                  }

       

                  // convert categorizedDocMap to pdf documents.

                  List<SupportingDocument> supportingDocList = mergePdfDocByCategory(categorizedDocMap);

       

                  // save the pdf docs

                  DocUploadManager docUploadManager = (DocUploadManager) Component.getInstance(componentName);

                  docUploadManager.save(supportingDocList, isAppend);

       

                  // clean up; scan backward and remove those in the files that have been deleted

                  for (int count = files.size(); count>0; count--) {

                      if (files.get(count-1).getMarkForDelete()==true) {

                          files.remove(count-1);

                      }

                  }

       

              } catch (Exception e) {

                  log.error(e);

              }

          }

       

          @Factory(value = "documentCategory")

          public Map<String, String> getDocumentCategory() {

              String componentName = "";

              if (userContext.getNamespace().getUserType() == UserType.OFFICER) componentName = OConsoleDocUploadManagerBean.COMPONENT_NAME;

              else componentName = DocUploadManagerBean.COMPONENT_NAME;

              DocUploadManager docUploadManager = (DocUploadManager)Component.getInstance(componentName);

              return docUploadManager.getSupportingDocumentCtgry();

          }

       

          /*@Factory(value = "documentCategory")

          public List<SupportingDocumentCategory> getDocumentCategory() {

              SupportingDocumentCategory[] sdcArray = SupportingDocumentCategory

                      .values();

              List<SupportingDocumentCategory> sdcList = new ArrayList<SupportingDocumentCategory>();

              for (int i = 0; i < sdcArray.length; i++) {

                  sdcList.add(sdcArray[i]);

              }

              return sdcList;

          }

       

          public SupportingDocumentCategory getDefaultCategory() {

              return defaultCategory;

          }

       

          public void setDefaultCategory(SupportingDocumentCategory defaultCategory) {

              this.defaultCategory = defaultCategory;

          }

       

          public void setDocumentCategory(

                  List<SupportingDocumentCategory> documentCategory) {

              this.documentCategory = documentCategory;

          }*/

       

          public String clearUploadData() {

              files.clear();

              setUploadsAvailable(10);

              return null;

          }

       

       

          /**

           * convert a multipage tiff into multiple pdf docs

           *

           * @param imageBytes

           * @return

           */

          public List<byte[]> convertTiffToPDFDocs(byte[] imageBytes) {

              // each item in the list is a byte array of a pdf document.  the pdf document holds the one image in the multi-page tiff

              List<byte[]> pdfByteList = new ArrayList<byte[]>();

       

              RandomAccessFileOrArray ra = new RandomAccessFileOrArray(imageBytes);

              int pages = TiffImage.getNumberOfPages(ra);

              for(int i = 1; i <= pages; i++){

                  // construct the pdf doc

                  com.lowagie.text.Document document = new com.lowagie.text.Document();

                  ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

                  try {

                      PdfWriter w = PdfWriter.getInstance(document, byteArrayOutputStream);

                  } catch (DocumentException e) {

                      log.error("failed to create PdfWriter: #0", e);

                      e.printStackTrace();

                  }

                  document.open();

                  // resize the tiff if necessary

                  Image tiff = TiffImage.getTiffImage(ra, i);

                  if (tiff == null)

                      break;

       

                  // scale and rotate if the img is too big

                  if (tiff.getHeight() > MAX_CONTENT_HEIGHT || tiff.getWidth() > MAX_CONTENT_WIDTH) {

                      // if image length is shorter than width by more than an inch

                      if ((tiff.getHeight() + ONE_INCH) < tiff.getWidth()) {

                          tiff.setRotationDegrees(-90);

                      }

                      tiff.scaleToFit(MAX_CONTENT_WIDTH, MAX_CONTENT_HEIGHT);

                  }

       

                  adjustRotation(imageBytes, tiff);

       

                  // add tiff to doc

                  try {

                      document.add(tiff);

                  } catch (DocumentException e) {

                      log.error("failed to add tiff to pdf doc: #0", e);

                      e.printStackTrace();

                  }

                  document.close();

                  pdfByteList.add(byteArrayOutputStream.toByteArray());

              }

       

              return pdfByteList;

          }

       

          /**

           * convert jpg,gif,png,pdf,bmp to pdf

           * @param imageBytes

           * @return

           * @throws Exception

           */

          public byte[] convertOtherToPDFDoc(byte[] imageBytes) throws Exception {

              com.lowagie.text.Document document = new com.lowagie.text.Document();

              ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

              PdfWriter w = PdfWriter.getInstance(document, byteArrayOutputStream);

              // w.setFullCompression();

              // w.setCompressionLevel(9);

              document.open();

              Image jpg = Image.getInstance(imageBytes);

       

              if (jpg == null)

                  return null;

              if (jpg.getHeight() > MAX_CONTENT_HEIGHT || jpg.getWidth() > MAX_CONTENT_WIDTH)

                  jpg.scaleToFit(MAX_CONTENT_WIDTH, MAX_CONTENT_HEIGHT);

       

              adjustRotation(imageBytes, jpg);

              document.add(jpg);

              document.close();

              return byteArrayOutputStream.toByteArray();

          }

       

          /**

           * Fixes the rotation of the image if the initial orientation was not normal.

           * Requires the image has EXIF meta data and is of supported formatts, JPEG, TIFF, or GIF

           *

           * TODO - use apache Tika instead?

           *

           * Drew Metadata-extractor image library is used

           *     http://code.google.com/p/metadata-extractor/wiki/GettingStarted

           * reference to orientation codes:

           *     http://jpegclub.org/exif_orientation.html

           *

           * @param imageBytes - used by parse out the EXIF image meta data

           * @param iTextImg - used to rotate the image before embedding into a PDF

           */

          private void adjustRotation(byte[] imageBytes, Image iTextImg){

              if(imageBytes == null)

                  return;

       

              if(iTextImg == null)

                  return;

       

              BufferedInputStream bis= null;

              try {

                  bis = new BufferedInputStream(new ByteArrayInputStream(imageBytes));

                  boolean waitForBytes = false;

                  int exifOrientation = 1;//default to normal, which needs no rotation

       

                  Metadata metadata = ImageMetadataReader.readMetadata(bis, waitForBytes);

       

                  if(log.isTraceEnabled()){

                      //list image's taken date

                      ExifSubIFDDirectory directory = metadata.getDirectory(ExifSubIFDDirectory.class);

                      if(directory != null && directory.containsTag(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL)){

                          Date date = directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);

                          log.trace("Image taken on: " + date);

                      }

                  }

       

                  //find tag orientation

                  final ExifIFD0Directory exifIFD0Directory = metadata.getDirectory(ExifIFD0Directory.class);

                  if(exifIFD0Directory != null && exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)){

                      exifOrientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);

                      log.debug("Image EXIF orientation: " + exifOrientation);

                  }else{

                       log.debug("Image did not have EXIF orientation meta tag specified, not adjusting rotation");

                       return;

                  }

       

                  //Note rotation will turn it to the left, counter clockwise

                  switch(exifOrientation){

                      case 1:

                          log.debug("EXIF orientation of 1, no adjustment rotation required.");

                          break;//normal

                      case 2:

                          log.debug("EXIF orientation of 2, no adjustment rotation required.");

                          break;//flip/mirror, consider unflipping

                      case 3:

                          iTextImg.setRotationDegrees(180);//upside down

                          log.info("Adjusted uploaded image rotation by 180 degrees to compensate for EXIF orientation of 3, upside down.");

                          break;

                      case 4:

                          iTextImg.setRotationDegrees(180);//upside down

                          log.info("Adjusted uploaded image rotation by 180 degrees to compensate for EXIF orientation of 4, upside down.");

                          break;

                      case 5:

                          iTextImg.setRotationDegrees(-90);//right side is up

                          log.info("Adjusted uploaded image rotation by -90 degrees to compensate for EXIF orientation of 5, right side is up.");

                          break;

                      case 6:

                          iTextImg.setRotationDegrees(-90);//left side is down

                          log.info("Adjusted uploaded image rotation by -90 degrees to compensate for EXIF orientation of 6, left side is down.");

                          break;

                      case 7:

                          iTextImg.setRotationDegrees(90);//right side is down

                          log.info("Adjusted uploaded image rotation by 90 degrees to compensate for EXIF orientation of 7, right side is down.");

                          break;

                      case 8:

                          iTextImg.setRotationDegrees(90);//left side is up

                          log.info("Adjusted uploaded image rotation by 90 degrees to compensate for EXIF orientation of 6, left side is up.");

                          break;

                  }

              }catch(Exception e) {

                  String errMsg = "Problem attempting to identify and rotate image based on EXIF metadata, error=" + e.getMessage();

                  log.error(errMsg, e);

              }finally{

                  if(bis != null){

                      try {

                          bis.close();

                      } catch (Exception ie) {

                          log.error("Error closing buffered input stream for docupload bean meta data read, error=" + ie.getMessage(), ie);

                      }

                  }

              }

          }

       

          /**

           * merge a list of documents into a single pdf document

           *

           * @param pages

           * @return

           * @throws DocumentException

           * @throws IOException

           */

          public byte[] mergeDocList(List<DocumentAndCategory> pages) throws DocumentException, IOException {

              if (pages != null && pages.size() > 0) {

       

                  List<PdfReader> readers = new ArrayList<PdfReader>();

                  Iterator<DocumentAndCategory> iteratorPDFs = pages.iterator();

       

                  // Create readers for each pdfs in the docList.

                  while (iteratorPDFs.hasNext()) {

                      DocumentAndCategory doc = iteratorPDFs.next();

                      PdfReader pdfReader = new PdfReader(doc.pdfData);

                      readers.add(pdfReader);

                  }

       

                  // create a pdf copy to hold the merged doc

                  ByteArrayOutputStream baos = new ByteArrayOutputStream();

                  PdfCopyFields copy = new PdfCopyFields(baos);

                  copy.open();

       

                  // iterate every pdf reader and append to the pdf copy

                  Iterator<PdfReader> iter = readers.iterator();

                  while (iter.hasNext()) {

                      PdfReader pdfReader = iter.next();

                      copy.addDocument(pdfReader);

                  }

                  copy.close();

                  return baos.toByteArray();

              }

              return null;

          }

       

          /**

           * each catagory can have multiple docs.  this function

           * converts all pdfs for each category into one category pdf.

           *

           * @param categorizedDocMap

           * @return

           * @throws Exception

           */

          public List<SupportingDocument> mergePdfDocByCategory(Map<String, List<DocumentAndCategory>> categorizedDocMap) throws Exception {

              List<SupportingDocument> pdfDocumentsList = new ArrayList<SupportingDocument>();

              // iterate every category

              Iterator<String> categoryIter = categorizedDocMap.keySet().iterator();

              while (categoryIter.hasNext()) {

                  String category = categoryIter.next();

                  List<DocumentAndCategory> documentList = categorizedDocMap.get(category);

                  SupportingDocument sDocument = createSupportingDoc(documentList, category);

                  pdfDocumentsList.add(sDocument);

              }

              return pdfDocumentsList;

          }

       

          private SupportingDocument createSupportingDoc(List<DocumentAndCategory> pages, String category) throws DocumentException, IOException {

              // merge all docs into 1 pdf

              byte pdfBytes[] = mergeDocList(pages);

       

              SupportingDocument sDocument = new SupportingDocument();

              DocumentImage docImage = new DocumentImage();

              docImage.setContent(pdfBytes);

              docImage.setFileName(category + ".pdf");

              docImage.setDescription(category + " Documents");

              docImage.setMimeType("application/pdf");

              sDocument.setDocumentImage(docImage);

              //sDocument.setDocumentCategory(SupportingDocumentCategory.valueOf(category));

              //sDocument.setDocumentCategory(appLookupManager.getApplicationLookupByName(EnumCtgry.DOCUMENT_CATEGORY, category));

              sDocument.setDocumentCategory(category);

              return sDocument;

          }

       

          /**

           * Separate a multipage pdf into individual pages with 1 pdf document each

           *

           * @param pdfBytes

           * @return

           */

          public List<byte[]> separatePDFPages(byte[] pdfBytes) throws Exception {

              List<byte[]> results = new ArrayList<byte[]>();

              try {

                  PdfReader srcPdf = new PdfReader(pdfBytes);

                  boolean encryptedPDF = srcPdf.isEncrypted();

                  if(encryptedPDF){

                      log.debug("PDF is encrypted");

                      //byte[] userPwd = srcPdf.computeUserPassword();

                      //srcPdf = new PdfReader(pdfBytes, userPwd);

                      //srcPdf = new PdfReader(pdfBytes, "test".getBytes());

                      //com.lowagie.tools.plugins.Decrypt;

                  }

                  int totalPages = srcPdf.getNumberOfPages();

       

                  // itext pdf start with page 1

                  for (int c=1; c<=totalPages; c++) {

                      // each page gets its own document

                      com.lowagie.text.Document document = new com.lowagie.text.Document();

       

                      // Create a writer for the outputstream for each page doc

                      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

                      PdfWriter writer = PdfWriter.getInstance(document, outputStream);

       

                      document.open();

                      PdfContentByte cb = writer.getDirectContent(); // Holds the PDF data

                      PdfImportedPage srcPage = null;

       

                      document.newPage();

                      //writer.setEncryption(1, 2, 2, PdfWriter.STANDARD_ENCRYPTION_128);

                      try{

                          srcPage = writer.getImportedPage(srcPdf, c);

                      }catch(Exception e){

                          if(e.getMessage().toLowerCase().contains("password") ||

                                  e.getMessage().toLowerCase().contains("security")){

                              throw new PDFSecurityException(e);

                          }else{

                              throw e;

                          }

                      }

                      cb.addTemplate(srcPage, 0, 0);

       

                      outputStream.flush();

                      document.close();

                      outputStream.close();

                      results.add(outputStream.toByteArray());

                  }

              } catch(PDFSecurityException pse){

                  throw pse;

              }catch (Exception e) {

                  log.error("separatePDFPages() failed to separate pdf document into individual pages.  " + e.getMessage());

                  e.printStackTrace();

              }

              return results;

          }

       

          /**

           * convert each page in the pdf to jpg images

           *

           * @param pdfBytes

           * @param allPages

           * @return

           * @throws Exception

           */

          public List<byte[]> convertPDFToImagePages(byte[] pdfBytes, boolean allPages)

                  throws Exception {

              List<byte[]> bytesList = new ArrayList<byte[]>();

              PDFToImageConvertor pdfToImage = (PDFToImageConvertor) Component.getInstance(PDFToImageConvertor.class);

              List<BufferedImage> bufferedImageList = pdfToImage.convertPDFToImage(pdfBytes, true, false);

              for (int i = 0; i < bufferedImageList.size(); i++) {

                  BufferedImage bufferedImage = bufferedImageList.get(i);

                  ByteArrayOutputStream baos = new ByteArrayOutputStream();

                  ImageIO.write(bufferedImage, "jpg", baos);

                  byte[] imageBytes = baos.toByteArray();

                  bytesList.add(imageBytes);

              }

              return bytesList;

          }

       

       

          /**

           * Call by docupload.page.xml (docupload.xhtml) to load supporting_document from database.

           * @throws Exception

           */

          // @Create

          public void loadFaxedDocuments() throws Exception {

              log.debug(" getFaxedDocuments() of " + className + " is called to retrieve faxed documents.");

       

              // load the pdf doc, one per category, from database

              DocUploadManager docUploadManager = (DocUploadManager) Component.getInstance(DocUploadManagerBean.class);

              loadSupportingDocuments(docUploadManager.getFaxedDocuments());

          }

          /**

           *  This method will be called from UI while entering into the validation decision table Tab.( productslist.xhtml)

           *  It will enable decisionTableEnabled instance variable so that listner method which is common for all other file uploads

           *  will execute code specific to validate decision table.

           */

          public void enableDecisionTableConfig(){

              log.info("Entered into enableDecisionTableConfig");

              decisionTableEnabled = true;

          }

          /**

           * This method is responsible for validating the uploaded xls file. It will be called from listener method

           * if decisionTableEnabled instance variable is true. Internally this method invokes ProductInfo.validateDecisionTable()

           * which has the actual logic of validating decision table and will return the msg accordingly.

           * @param item  item contains actual uploaded file data and metadata.

           */

          public void validateDecisionTable(UploadedFile item){

              log.info("Entered into validateDecisionTable, Validating decision table : "+item.getName());

              ProductsInfo productInfo = (ProductsInfo) Component.getInstance("productsInfo");

              PageScopeUtil pageScopeUtil = PageScopeUtil.instance();

              String errMsg = productInfo.validateDecisionTable(item.getData());

              pageScopeUtil.setErrMsg(errMsg);

          }

          /**

           * This method is responsible for loading the existing supporting

           * documents from db on recategorizedocs.xhtml

           *

           * @param componentName

           * @throws Exception

           */

       

          public void loadSupportingDocumets(String componentName) throws Exception {

              log.info("Load Supporting Documents called for component:" + componentName);

              DocUploadManager docUploadManager = (DocUploadManager) Component.getInstance(componentName);

       

              // get supporting docs from database

              loadSupportingDocuments(docUploadManager.getUploadedSupportingDocuments());

          }

       

          /**

           *

           * This helper function does the following

           * 1.  break each page in each supporting doc into separate pdf doc

           * 2.  create separate images (one per page) for each pdf doc for use as thumb nail

           *

           * All these in formation is stored in this.files list

           * @param supportingDocList

           * @throws Exception

           */

          void loadSupportingDocuments(List<SupportingDocument> supportingDocList) throws Exception {

              files.clear();

              // iterate through each supporting doc and create an image for every page in the doc

              if (supportingDocList != null) {

                  for (SupportingDocument sd : supportingDocList) {

                      // separate the pdf into individual pages.  each page is a pdf doc

                      List<byte[]> pdfByteList = separatePDFPages(sd.getDocumentImage().getContent());

       

                      // get image for each page in the pdf

                      List<byte[]> imageBytesList = convertPDFToImagePages(sd.getDocumentImage().getContent(), true);

       

                      // add every page to this.files list

                      for (int i = 0; i < imageBytesList.size(); i++) {

                          byte[] pdfBytes = pdfByteList.get(i);

                          byte[] imageBytes = imageBytesList.get(i);

       

                          DocumentAndCategory pdfDoc = new DocumentAndCategory();

                          //pdfDoc.setDocumentCategory(sd.getDocumentCategory());

                          if (sd.getDocumentCategory() != null) pdfDoc.setDocumentCategory(sd.getDocumentCategory());

                          pdfDoc.setName(sd.getDocumentImage().getFileName());

                          pdfDoc.setPdfByte(pdfBytes);

                          pdfDoc.setLength(imageBytes.length);

                          pdfDoc.setData(imageBytes);

                          files.add(pdfDoc);

                      }

                  }

              }

          }

       

          /**

           * This method is responsible for removing a supporting

           * documents from this.files.  Change is not saved until user click update button

           *

           * @param docId

           * @throws Exception

           */

          public void removeSupportingDocument(int index) throws Exception {

              files.remove(index);

          }

       

          public long getTimeStamp() {

              return System.currentTimeMillis();

          }

       

          public ArrayList<DocumentAndCategory> getFiles() {

              return files;

          }

       

          public void setFiles(ArrayList<DocumentAndCategory> files) {

              this.files = files;

          }

       

          /**

           * use by recategorizeddocs.xhtml

           *

           * @return

           */

          public List<DocumentAndCategory> getSupportingDocs() {

              return files;

          }

       

          public int getUploadsAvailable() {

              return uploadsAvailable;

          }

       

          public void setUploadsAvailable(int uploadsAvailable) {

              this.uploadsAvailable = uploadsAvailable;

          }

       

          public boolean getAutoUpload() {

              return autoUpload;

          }

       

          public void setAutoUpload(boolean autoUpload) {

              this.autoUpload = autoUpload;

          }

       

          public boolean getUseFlash() {

              return useFlash;

          }

       

          public void setUseFlash(boolean useFlash) {

              this.useFlash = useFlash;

          }

       

       

          public static class DocumentAndCategory extends Document {

       

              private byte[] pdfData = null;

              private boolean markForDelete = false;

       

              /*        private SupportingDocumentCategory documentCategory;

       

              public SupportingDocumentCategory getDocumentCategory() {

                  return documentCategory;

              }

       

              public void setDocumentCategory(SupportingDocumentCategory documentCategory) {

                  this.documentCategory = documentCategory;

              }*/

       

              private String documentCategory;

       

              public DocumentAndCategory(SupportingDocument document) {

                  setPdfByte(document.getDocumentImage().getContent());

                  setData(document.getDocumentImage().getContent());

                  setDocumentCategory(document.getDocumentCategory());

              }

       

              public DocumentAndCategory() {

              }

       

              public String getDocumentCategory(){

                  return documentCategory;

              }

       

              public void setDocumentCategory(String documentCategoryParam) {

                  this.documentCategory = documentCategoryParam;

              }

       

              public void setPdfByte(byte[] pdf) {

                  this.pdfData = pdf;

              }

       

              public void setMarkForDelete(boolean b) {

                  markForDelete = b;

              }

       

              public boolean getMarkForDelete() {

                  return markForDelete;

              }

       

          }

       

          public Boolean checkDocumentsSignedByCoapplicant() {

              DocUploadManager docUploadManager = (DocUploadManager) Component.getInstance(DocUploadManagerBean.COMPONENT_NAME);

              return docUploadManager.checkDocumentsSignedByCoapplicant();

          }

       

          @RequestParameter private String appReqId;

       

          public String getAppReqId() {

              return appReqId;

          }

       

          public void setAppReqId(String appReqId) {

              this.appReqId = appReqId;

          }

       

          public void propagateAppRequest(){

              if(appReqId != null){

                  //This upload operation is being associated with an application/appRequest

                  //put the id into session so other things can use it if needed

                  //ie for page navigation after upload (check on co-applicant or not)

                  Contexts.getSessionContext().set("appReqId", new Long(appReqId));

              }

       

              //to support primary to upload his own document from home this action is required

              //because of joint workflow streamline changes

              if(customerLevelUpload != null && customerLevelUpload.equals("1")){

                  Long appReqId = (Long) Contexts.getSessionContext().get("appReqId");

                  if(appReqId != null){

                      Contexts.getSessionContext().set("isPrimaryContinuingAsJoint"+appReqId, false);

                  }

       

              }

          }

       

          @SuppressWarnings("serial")

          public static class PDFSecurityException extends Exception{

              public PDFSecurityException(){

       

              }

       

              public PDFSecurityException(Exception e){

                  super(e);

              }

       

              public PDFSecurityException(Throwable t){

                  super(t);

              }

       

              public PDFSecurityException(String msg, Exception e){

                  super(msg, e);

              }

          }

       

          public void driversLicenseUploadListener(FileUploadEvent event) throws Exception {

              if (event.getComponent().getValueExpression("inputField") == null) {

                  throw new IllegalArgumentException("Can't find attribute: inputField");

              }

              final InputField inputField = (InputField)event.getComponent()

                      .getValueExpression("inputField")

                      .getValue(FacesContext.getCurrentInstance().getELContext());

       

              final Customer customer = (Customer)ELEvaluator.eval(inputField.getField().getEntity().getEffectivePath());

       

              customer.clearDriverLicenseRawDocuments();

       

              documentUploadListener(event);

          }

       

          public void documentUploadListener(FileUploadEvent event) throws Exception {

              PageScopeUtil pageScopeUtil = PageScopeUtil.instance();

              pageScopeUtil.setErrMsg(null);//clear if previous request had errors, note cannot use event scope for the uploader as the upload is its own request

       

              if (event.getComponent().getValueExpression("inputField") == null) {

                  throw new IllegalArgumentException("Can't find attribute: inputField");

              }

              ELContext elContext = FacesContext.getCurrentInstance().getELContext();

              final InputField inputField = (InputField)event.getComponent()

                      .getValueExpression("inputField")

                      .getValue(elContext);

       

              final Customer customer = (Customer)ELEvaluator.eval(inputField.getField().getEntity().getEffectivePath());

       

              final UploadedFile UploadedFile = event.getUploadedFile();

              final String documentCategory = inputField.getDocumentCategory();

       

              if (isEmpty(documentCategory)) {

                  throw new IllegalArgumentException("documentCategory is null, check field configuration: " +

                          inputField.getFieldGroup().getPage().getInputPageType() + ":" +

                          inputField.getFieldGroup().getName() + ":" +

                          inputField.getField().getName());

              }

       

              final RawSupportingDocument rawDocument = createRawDocument(UploadedFile);

              rawDocument.setClient(userContext.getClient());

              rawDocument.setCustomer(customer);

              rawDocument.setCategory(documentCategory);

              customer.addRawSupportingDocument(rawDocument);

       

              // re-create document from raw documents (including new raw)

              if (!isEmpty(rawDocument.getDocumentImage().getContent())) {

                  log.info("Processing file '#0' (#1K)",

                          rawDocument.getDocumentImage().getFileName(), rawDocument.getDocumentImage().getContent().length / 1024);

                  customer.removeDocumentsByCategory(documentCategory);

                  final List<RawSupportingDocument> rawDocuments = customer.getRawDocumentsByCategory(documentCategory);

                  final List<DocumentAndCategory> pages = extractPages(rawDocuments);

                  final SupportingDocument document = createSupportingDoc(pages, documentCategory);

                  customer.addSupportingDocument(document);

                  document.setCustomer(customer);

                  document.setClient(userContext.getClient());

              }

          }

       

          private List<DocumentAndCategory> extractPages(List<RawSupportingDocument> rawDocuments) throws Exception {

              List<DocumentAndCategory> docPages = new ArrayList<DocUploadBean.DocumentAndCategory>();

              for (final RawSupportingDocument raw: rawDocuments) {

                  final DocumentImage docImage = raw.getDocumentImage();

                  if (docImage.isPdf()) {

                      docPages.addAll(extractPagesFromPdf(docImage.getContent(), docImage.getFileName()));

                  } else if (docImage.isTiff()) {

                      docPages.addAll(extractPagesFromTiff(docImage.getContent(), docImage.getFileName()));

                  } else {

                      docPages.add(extractPageFromImage(docImage.getContent(), docImage.getFileName()));

                  }

              }

              return docPages;

          }

      }

       

       

      Thanks,

      Manish