diff options
Diffstat (limited to 'src/main/java')
20 files changed, 984 insertions, 271 deletions
| diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java b/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java index 0987b2d..f9ab652 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java @@ -46,6 +46,7 @@ import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation;  import at.knowcenter.wag.egov.egiz.pdf.PDFSignatureCreation;
  import at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject;
  import at.knowcenter.wag.egov.egiz.pdf.PDFUtilities;
 +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction;
  import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
  import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder;
  import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 @@ -57,6 +58,7 @@ import at.knowcenter.wag.egov.egiz.sig.SignatureResponse;  import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition;
  import at.knowcenter.wag.egov.egiz.sig.SignatureTypes;
  import at.knowcenter.wag.egov.egiz.tools.Normalizer;
 +import at.knowcenter.wag.exactparser.ParseDocument;
  import at.knowcenter.wag.exactparser.parsing.PDFUtils;
  import at.knowcenter.wag.exactparser.parsing.results.HeaderParseResult;
 @@ -152,7 +154,8 @@ public abstract class PdfAS     * is not 1.4.
     * 
     * <p>
 -   * If strict mode is deactivated, this does simply nothing.
 +   * Furthermore (independently of strict mode) the PDF is checked for
 +   * parsability.
     * </p>
     * 
     * @param pdf
 @@ -168,6 +171,15 @@ public abstract class PdfAS          throw new PDFDocumentException(201, "StrictMode: The pdf version is not 1.4 or lower.");
        }
      }
 +    try
 +    {
 +      ParseDocument.parseDocument(pdf);
 +    }
 +    catch (Exception e)
 +    {
 +      logger_.debug("Error while parsing Document.", e);
 +      throw new PDFDocumentException(201, e);
 +    }
    }
    /**
 @@ -232,7 +244,7 @@ public abstract class PdfAS     * @throws SignatureException
     *           F.e.
     * @throws SignatureTypesException
 -   * @throws NormalizeException 
 +   * @throws NormalizeException
     */
    public static List extractSignatureHoldersTextual(String raw_text,
        boolean old_style) throws PDFDocumentException, SignatureException, SignatureTypesException, NormalizeException
 @@ -267,7 +279,7 @@ public abstract class PdfAS     *         found.
     * @throws SignatureException
     * @throws SignatureTypesException
 -   * @throws NormalizeException 
 +   * @throws NormalizeException
     */
    public static SignatureHolder extractSignatureHolderTextual(String raw_text,
        boolean old_style) throws SignatureException, SignatureTypesException, NormalizeException
 @@ -343,7 +355,8 @@ public abstract class PdfAS          end_index = cur_key.getStartIndex();
        }
 -      // this normalization is required to get rid of possible trailing newlines.
 +      // this normalization is required to get rid of possible trailing
 +      // newlines.
        String normalized_text = normalizeText(signed_text);
        SignatureHolder holder = new TextualSignatureHolder(normalized_text, signatureObject_);
        return holder;
 @@ -368,8 +381,6 @@ public abstract class PdfAS    public static List findBlockInText(String text,
        SignatureTypeDefinition sig_type_def, boolean old_style)
    {
 -	 // FIXME[tknall]: AbsoluteTextSignature.java, method findEndOfValue(...) does not work properly for landscape documents because start_index of FoundKeys are not set correctly.
 -	  // Hint: Captions and values of landscape documents are separated with " \n" and not only with " ".
      Vector keys = sig_type_def.getRevertSortedKeys();
      Vector captions = sig_type_def.getRevertSortedCaptions();
 @@ -389,11 +400,12 @@ public abstract class PdfAS        String caption = (String) captions.get(key_idx);
 -      //int found_index = text.lastIndexOf(caption);
 -// we're searching for captions that start at the beginning of the line.
 -      int found_index = text.lastIndexOf("\n" + caption) + 1; // the +1 compensates the \n
 -      
 -      
 +      // int found_index = text.lastIndexOf(caption);
 +      // we're searching for captions that start at the beginning of the line.
 +      int found_index = text.lastIndexOf("\n" + caption) + 1; // the +1
 +      // compensates the
 +      // \n
 +
        if (key.equals(SignatureTypes.SIG_ID))
        {
          if (found_index < 0 || found_index >= last_index)
 @@ -453,7 +465,7 @@ public abstract class PdfAS        }
      });
    }
 -  
 +
    /**
     * Sorts the FoundKeys List ascendingly according to the start indices of the
     * found keys (the first found key in the list will have the lowest start
 @@ -475,7 +487,7 @@ public abstract class PdfAS          return fk0.start_index - fk1.start_index;
        }
      });
 -  }  
 +  }
    /**
     * Checks that the found keys are in correct order regarding SIG_ID as
 @@ -763,7 +775,7 @@ public abstract class PdfAS        String connector) throws NormalizeException, PDFDocumentException, SignatureException
    {
      String text_to_be_verified = signature_holder.getSignedText();
 -    
 +
      SignatureObject so_to_be_verified = signature_holder.getSignatureObject();
      if (text_to_be_verified == null)
 @@ -774,7 +786,7 @@ public abstract class PdfAS      {
        throw new SignatureException(311, "Document can not be verified because the length of the text to be verified is 0. (length = " + text_to_be_verified.length() + ")");
      }
 -    
 +
      if (so_to_be_verified == null)
      {
        throw new SignatureException(312, "Document can not be verified because no signature object are set.");
 @@ -816,8 +828,9 @@ public abstract class PdfAS        final String user_name, final String user_password) throws SignatureException, PDFDocumentException
    {
      logger_.info("User signed a document: " + user_name);
 -    
 -    if (text_to_sign == null) {
 +
 +    if (text_to_sign == null)
 +    {
        throw new SignatureException(301, "Signature can not be produced. Text is null.");
      }
      if (text_to_sign.length() <= 0)
 @@ -907,10 +920,10 @@ public abstract class PdfAS     */
    public static String extractNormalizedTextTextual(final byte[] pdf) throws PresentableException
    {
 -//    ByteArrayInputStream bais = new ByteArrayInputStream(pdf);
 -//    String raw_document_text = TextualSignature.extractTextTextual(bais);
 -//
 -//    String document_text = normalizeText(raw_document_text);
 +    // ByteArrayInputStream bais = new ByteArrayInputStream(pdf);
 +    // String raw_document_text = TextualSignature.extractTextTextual(bais);
 +    //
 +    // String document_text = normalizeText(raw_document_text);
      return extractNormalizedTextTextual(pdf, pdf.length);
    }
 @@ -927,7 +940,8 @@ public abstract class PdfAS     * @throws PresentableException
     *           F.e.
     */
 -  public static String extractNormalizedTextTextual(final byte[] pdf, final int length) throws PresentableException
 +  public static String extractNormalizedTextTextual(final byte[] pdf,
 +      final int length) throws PresentableException
    {
      ByteArrayInputStream bais = new ByteArrayInputStream(pdf, 0, length);
      String raw_document_text = TextualSignature.extractTextTextual(bais);
 @@ -975,6 +989,68 @@ public abstract class PdfAS    }
    /**
 +   * Evalutates absolute positioning and prepares the PositioningInstruction for
 +   * placing the table.
 +   * 
 +   * @param pos
 +   *          The absolute positioning parameter. If null it is sought in the
 +   *          profile definition.
 +   * @param signature_type
 +   *          The profile definition of the table to be written.
 +   * @param pdf
 +   *          The pdf.
 +   * @param pdf_table
 +   *          The pdf table to be written.
 +   * @return Returns the PositioningInformation.
 +   * @throws PDFDocumentException
 +   *           F.e.
 +   * @throws SettingsException
 +   *           F.e.
 +   */
 +  public static PositioningInstruction determineTablePositioning(TablePos pos,
 +      String signature_type, byte[] pdf, PdfPTable pdf_table) throws PDFDocumentException, SettingsException
 +  {
 +    if (pos == null)
 +    {
 +      String pos_string = SettingsReader.getInstance().getSetting(SignatureTypes.SIG_OBJ + signature_type + ".pos", null);
 +      if (pos_string != null)
 +      {
 +        pos = PdfAS.parsePositionFromPosString(pos_string);
 +      }
 +    }
 +
 +    if (pos == null)
 +    {
 +      // The automatic algorithm.
 +      return PdfAS.adjustTableAndCalculatePosition(pdf, pdf_table);
 +    }
 +
 +    if (pos.page == -2)
 +    {
 +      // The automatic algorithm regarding the footer.
 +      return PdfAS.adjustTableAndCalculatePositionRegardingFooter(pdf, pdf_table, pos.footer_line);
 +    }
 +
 +    boolean make_new_page = false;
 +    int page = pos.page;
 +
 +    if (pos.page == -1)
 +    {
 +      // Absolute positioning on a new page.
 +      make_new_page = true;
 +      PdfReader reader = PdfAS.readInPdfDocument(pdf);
 +      page = reader.getNumberOfPages() + 1;
 +      reader = null;
 +    }
 +
 +    pdf_table.setTotalWidth(pos.width);
 +    pdf_table.setLockedWidth(true);
 +
 +    return new PositioningInstruction(make_new_page, page, pos.pos_x, pos.pos_y);
 +
 +  }
 +
 +  /**
     * Sets the width of the table according to the layout of the document and
     * calculates the y position where the PDFPTable should be placed.
     * 
 @@ -986,36 +1062,88 @@ public abstract class PdfAS     * @throws PDFDocumentException
     *           F.e.
     */
 -  public static TablePos adjustTableAndCalculatePosition(final byte[] pdf,
 -      PdfPTable pdf_table) throws PDFDocumentException
 +  public static PositioningInstruction adjustTableAndCalculatePosition(
 +      final byte[] pdf, PdfPTable pdf_table) throws PDFDocumentException
    {
 -    TablePos pos = new TablePos();
 +    boolean make_new_page = false;
      PdfReader reader = readInPdfDocument(pdf);
 -    Rectangle psize = reader.getPageSizeWithRotation(reader.getNumberOfPages());
 +    int page = reader.getNumberOfPages();
 +    Rectangle psize = reader.getPageSizeWithRotation(page);
      float page_width = psize.width();
      float page_height = psize.height();
 -    pos.width = page_width - SIGNATURE_BORDER;
 -    pdf_table.setTotalWidth(pos.width);
 +    final float width = page_width - SIGNATURE_BORDER;
 +    pdf_table.setTotalWidth(width);
 +    pdf_table.setLockedWidth(true);
 +
 +    final float pos_x = SIGNATURE_BORDER / 2;
 +
 +    final float table_height = pdf_table.getTotalHeight();
 +    final float page_length = PDFUtilities.calculateLastPageLength(pdf, page_height);
 +    float pos_y = page_height - page_length - SIGNATURE_MARGIN;
 +
 +    if (pos_y <= table_height)
 +    {
 +      make_new_page = true;
 +      page++;
 +
 +      pos_y = page_height - SIGNATURE_BORDER / 2;
 +    }
 +
 +    return new PositioningInstruction(make_new_page, page, pos_x, pos_y);
 +  }
 +
 +  /**
 +   * Sets the width of the table according to the layout of the document and
 +   * calculates the y position where the PDFPTable should be placed.
 +   * 
 +   * <p>
 +   * This algorithm tries to position the table between the end of the text and
 +   * the footer line.
 +   * </p>
 +   * 
 +   * @param pdf
 +   *          The PDF document.
 +   * @param pdf_table
 +   *          The PDFPTable to be placed.
 +   * @return Returns the position where the PDFPTable should be placed.
 +   * @throws PDFDocumentException
 +   *           F.e.
 +   */
 +  public static PositioningInstruction adjustTableAndCalculatePositionRegardingFooter(
 +      final byte[] pdf, PdfPTable pdf_table, float footer_line) throws PDFDocumentException
 +  {
 +    boolean make_new_page = false;
 +
 +    PdfReader reader = readInPdfDocument(pdf);
 +
 +    int page = reader.getNumberOfPages();
 +    Rectangle psize = reader.getPageSizeWithRotation(page);
 +    float page_width = psize.width();
 +    float page_height = psize.height();
 +
 +    final float width = page_width - SIGNATURE_BORDER;
 +    pdf_table.setTotalWidth(width);
      pdf_table.setLockedWidth(true);
 -    pos.pos_x = SIGNATURE_BORDER / 2;
 +    final float pos_x = SIGNATURE_BORDER / 2;
 +
 +    final float table_height = pdf_table.getTotalHeight();
 -    float table_height = pdf_table.getTotalHeight();
 -    float page_length = PDFUtilities.calculateLastPageLength(pdf);
 -    pos.pos_y = page_height - page_length - SIGNATURE_MARGIN;
 +    final float page_length = PDFUtilities.calculateLastPageLength(pdf, page_height - footer_line);
 +    float pos_y = page_height - page_length - SIGNATURE_MARGIN;
 -    pos.page = reader.getNumberOfPages();
 -    if (pos.pos_y <= table_height)
 +    if (pos_y - footer_line <= table_height)
      {
 -      pos.page = -1;
 -      // negative means to add a new page
 -      pos.pos_y = page_height - SIGNATURE_BORDER / 2;
 +      make_new_page = true;
 +      page++;
 +
 +      pos_y = page_height - SIGNATURE_BORDER / 2;
      }
 -    return pos;
 +    return new PositioningInstruction(make_new_page, page, pos_x, pos_y);
    }
    /**
 @@ -1055,27 +1183,46 @@ public abstract class PdfAS    public static TablePos parsePositionFromPosString(String pos_string) throws PDFDocumentException
    {
      String[] strs = pos_string.split(";");
 -    if (strs.length != 4)
 -    {
 -      throw new PDFDocumentException(224, "Pos string (=" + pos_string + ") is invalid.");
 -    }
      try
      {
        TablePos pos = new TablePos();
        pos.page = Integer.parseInt(strs[0]);
 -      pos.pos_x = Float.parseFloat(strs[1]);
 -      pos.pos_y = Float.parseFloat(strs[2]);
 -      pos.width = Float.parseFloat(strs[3]);
 -      if (pos.page < 1 && pos.page != -1)
 +      if (pos.page < 1 && pos.page != -1 && pos.page != -2)
        {
 -        throw new PDFDocumentException(225, "pos.page (=" + pos.page + ") must not be lower than -1 and must not be 0.");
 +        throw new PDFDocumentException(225, "Page (=" + pos.page + ") must not be lower than -2 and must not be 0.");
        }
 -      if (pos.width <= 0.0f)
 +      if (pos.page == -2)
        {
 -        throw new PDFDocumentException(226, "pos.width (=" + pos.width + ") must not be lower or equal 0.");
 +        if (strs.length != 2)
 +        {
 +          throw new PDFDocumentException(224, "Pos string (=" + pos_string + ") is invalid.");
 +        }
 +
 +        pos.footer_line = Float.parseFloat(strs[1]);
 +      }
 +      else
 +      {
 +        if (strs.length != 4)
 +        {
 +          throw new PDFDocumentException(224, "Pos string (=" + pos_string + ") is invalid.");
 +        }
 +
 +        pos.pos_x = Float.parseFloat(strs[1]);
 +        pos.pos_y = Float.parseFloat(strs[2]);
 +        pos.width = Float.parseFloat(strs[3]);
 +
 +        if (pos.page < 1 && pos.page != -1)
 +        {
 +          throw new PDFDocumentException(225, "pos.page (=" + pos.page + ") must not be lower than -1 and must not be 0.");
 +        }
 +
 +        if (pos.width <= 0.0f)
 +        {
 +          throw new PDFDocumentException(226, "pos.width (=" + pos.width + ") must not be lower or equal 0.");
 +        }
        }
        return pos;
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java b/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java index 7f5242b..bcfb6b4 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java @@ -753,21 +753,19 @@ public abstract class Main        writer.println("      " + type + " ... " + (type.equals(default_type) ? "(default) " : "") + type_descr);
      }
 -    writer.println("    " + PARAMETER_USER_NAME + " <user_name> ... the user name");
 -    writer.println("    " + PARAMETER_USER_PASSWORD + " <password> ... the user password");
 +    writer.println("    " + PARAMETER_USER_NAME + " <user_name> ... [optional] the user name");
 +    writer.println("    " + PARAMETER_USER_PASSWORD + " <password> ... [optional] the user password");
 -    writer.println("    " + PARAMETER_POS + " <position> ... [optional] the absolute position of the signature block");
 -    writer.println("      position has the format <pagenr>;<x>;<y>;<width>");
 -    writer.println("      ... e.g. -pos=1;20.0;400.0;500.0");
 +    writer.println("    " + PARAMETER_POS + " <position> ... [optional] the position of the signature block");
 +    writer.println("      position has the format <pagenr>;<x>;<y>;<width> or -2;<footer_line>");
      writer.println("  OPTIONS for verification:");
      writer.println("    " + PARAMETER_VERIFY_WHICH + " <number> ... [optional] zero based number of the signature");
      writer.println("      to be verified. If omitted, all signatures are verified.");
      writer.println("  Example usage:");
 -    writer.println("    pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_SIGN + " " + PARAMETER_CONNECTOR + " moa " + PARAMETER_USER_NAME + " name " + PARAMETER_USER_PASSWORD + " pwd some_document.pdf");
 +    writer.println("    pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_SIGN + " " + PARAMETER_CONNECTOR + " moa some_document.pdf");
      writer.println("    pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_VERIFY + " some_document.pdf_out.pdf");
 -
    }
    /**
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java index dd7a742..26f46e8 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java @@ -107,7 +107,8 @@ public class VerificationFilter      }
      catch (Exception e)
      {
 -      throw new PDFDocumentException(201);
 +      logger_.debug("Error while parsing Document.", e);
 +      throw new PDFDocumentException(201, e);
      }
  //    for (int i = 0; i < blocks.size(); i++)
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java index d28ac3b..6f167c8 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java @@ -22,11 +22,8 @@ import java.util.ArrayList;  import java.util.Iterator;
  import java.util.List;
 -import com.lowagie.text.pdf.PdfPTable;
 -
  import at.knowcenter.wag.egov.egiz.PdfAS;
  import at.knowcenter.wag.egov.egiz.PdfASID;
 -import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
  import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
  import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
  import at.knowcenter.wag.egov.egiz.framework.SignResult;
 @@ -34,6 +31,7 @@ import at.knowcenter.wag.egov.egiz.framework.Signator;  import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
  import at.knowcenter.wag.egov.egiz.pdf.BinarySignature;
  import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation;
 +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction;
  import at.knowcenter.wag.egov.egiz.pdf.ReplaceInfo;
  import at.knowcenter.wag.egov.egiz.pdf.StringInfo;
  import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 @@ -42,6 +40,8 @@ import at.knowcenter.wag.egov.egiz.sig.SignatureObject;  import at.knowcenter.wag.egov.egiz.sig.SignatureTypes;
  import at.knowcenter.wag.exactparser.ByteArrayUtils;
 +import com.lowagie.text.pdf.PdfPTable;
 +
  /**
   * Signs the document binary.
   * 
 @@ -90,25 +90,7 @@ public class BinarySignator_1_0_0 implements Signator        PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(signature_object);
 -      if (pos == null)
 -      {
 -        String pos_string = SettingsReader.getInstance().getSetting(SignatureTypes.SIG_OBJ + signature_type + ".pos", null);
 -        if (pos_string != null)
 -        {
 -          pos = PdfAS.parsePositionFromPosString(pos_string);
 -          pdf_table.setTotalWidth(pos.width);
 -          pdf_table.setLockedWidth(true);
 -        }
 -        else
 -        {
 -          pos = PdfAS.adjustTableAndCalculatePosition(pdf, pdf_table);
 -        }
 -      }
 -      else
 -      {
 -        pdf_table.setTotalWidth(pos.width);
 -        pdf_table.setLockedWidth(true);
 -      }
 +      PositioningInstruction pi = PdfAS.determineTablePositioning(pos, signature_type, pdf, pdf_table);
        List all_field_definitions = signature_object.getSignatureTypeDefinition().getFieldDefinitions();
        List variable_field_definitions = new ArrayList();
 @@ -124,7 +106,7 @@ public class BinarySignator_1_0_0 implements Signator            variable_field_definitions.add(sfd);
          }
        }
 -      IncrementalUpdateInformation iui = BinarySignature.writeIncrementalUpdate(pdf, pdf_table, pos, variable_field_definitions, all_field_definitions);
 +      IncrementalUpdateInformation iui = BinarySignature.writeIncrementalUpdate(pdf, pdf_table, pi, variable_field_definitions, all_field_definitions);
        String temp_string = iui.temp_ir_number + " " + iui.temp_ir_generation + " obj";
        byte[] temp_bytes = temp_string.getBytes("US-ASCII");
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java index 6e605ff..8cdcf63 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java @@ -17,19 +17,18 @@   */
  package at.knowcenter.wag.egov.egiz.framework.signators;
 -import com.lowagie.text.pdf.PdfPTable;
 -
  import at.knowcenter.wag.egov.egiz.PdfAS;
  import at.knowcenter.wag.egov.egiz.PdfASID;
 -import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
  import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
  import at.knowcenter.wag.egov.egiz.framework.SignResult;
  import at.knowcenter.wag.egov.egiz.framework.Signator;
  import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
  import at.knowcenter.wag.egov.egiz.pdf.BinarySignature;
  import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation;
 +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction;
  import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 -import at.knowcenter.wag.egov.egiz.sig.SignatureTypes;
 +
 +import com.lowagie.text.pdf.PdfPTable;
  /**
   * Signs a document textually.
 @@ -93,27 +92,9 @@ public class TextualSignator_1_0_0 implements Signator      PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(iui.signed_signature_object);
 -    if (iui.pos == null)
 -    {
 -      String pos_string = SettingsReader.getInstance().getSetting(SignatureTypes.SIG_OBJ + iui.signature_type + ".pos", null);
 -      if (pos_string != null)
 -      {
 -        iui.pos = PdfAS.parsePositionFromPosString(pos_string);
 -        pdf_table.setTotalWidth(iui.pos.width);
 -        pdf_table.setLockedWidth(true);
 -      }
 -      else
 -      {
 -        iui.pos = PdfAS.adjustTableAndCalculatePosition(iui.original_document, pdf_table);
 -      }
 -    }
 -    else
 -    {
 -      pdf_table.setTotalWidth(iui.pos.width);
 -      pdf_table.setLockedWidth(true);
 -    }
 +    PositioningInstruction pi = PdfAS.determineTablePositioning(iui.pos, iui.signature_type, iui.original_document, pdf_table);
 -    IncrementalUpdateInformation signed_iui = BinarySignature.writeIncrementalUpdate(iui.original_document, pdf_table, iui.pos, null, null);
 +    IncrementalUpdateInformation signed_iui = BinarySignature.writeIncrementalUpdate(iui.original_document, pdf_table, pi, null, null);
      SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, signed_iui.signed_pdf);
      return sign_result;
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java index b3c2e24..85673b5 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java @@ -151,69 +151,89 @@ public class AbsoluteTextSignature      SignatureTypes sig_types = SignatureTypes.getInstance();
      List signatureTypes_ = sig_types.getSignatureTypeDefinitions();
 -    List found_candidates = new ArrayList();
 +    List found_potential_candidates = new ArrayList();
      for (int i = 0; i < signatureTypes_.size(); i++)
      {
        SignatureTypeDefinition block_type = (SignatureTypeDefinition) signatureTypes_.get(i);
        List found_candidates_for_type = findPotentialSignaturesForProfile(text, block_type);
 -      found_candidates.addAll(found_candidates_for_type);
 +      found_potential_candidates.addAll(found_candidates_for_type);
      }
 -    if (found_candidates.isEmpty())
 +    if (found_potential_candidates.isEmpty())
      {
        logger.debug("no candidates found at all");
        return null;
      }
 +    List found_candidates = new ArrayList();
      logger.debug("checking block integrity");
 -    for (int i = 0; i < found_candidates.size(); i++)
 +    for (int i = 0; i < found_potential_candidates.size(); i++)
      {
 -      FoundBlock found_block = (FoundBlock) found_candidates.get(i);
 +      FoundBlock found_block = (FoundBlock) found_potential_candidates.get(i);
        String date_value = getDateValue(text, found_block);
        logger.debug("date_value = " + date_value);
 -      EGIZDate date = EGIZDate.parseFromString(date_value);
 +      try
 +      {
 +        EGIZDate date = EGIZDate.parseFromString(date_value);
 +
 +        logger.debug("found_block = " + date + " - " + found_block);
 -      logger.debug("found_block = " + date + " - " + found_block);
 +        checkBlockIntegrity(text, found_block);
 -      checkBlockIntegrity(text, found_block);
 +        found_candidates.add(found_block);
 +      }
 +      catch (Exception e)
 +      {
 +        logger.debug("Exception while checking the integrity of the found block " + found_block + ". Ignoring this block.", e);
 +      }
      }
      sortFoundBlocksByDate(text, found_candidates);
 -
 -    logger.debug("sorted blocks:");
 -    for (int i = 0; i < found_candidates.size(); i++)
 +    if (logger.isDebugEnabled())
      {
 -      FoundBlock found_block = (FoundBlock) found_candidates.get(i);
 +      logger.debug("sorted blocks:");
 +      for (int i = 0; i < found_candidates.size(); i++)
 +      {
 +        FoundBlock found_block = (FoundBlock) found_candidates.get(i);
 -      String date_value = getDateValue(text, found_block);
 -      EGIZDate date = EGIZDate.parseFromString(date_value);
 +        String date_value = getDateValue(text, found_block);
 +        EGIZDate date = EGIZDate.parseFromString(date_value);
 -      logger.debug("  #" + i + ": " + date + " - " + found_block);
 +        logger.debug("  #" + i + ": " + date + " - " + found_block);
 +      }
      }
      List latest_blocks = filterLastDateEqualBlocks(text, found_candidates);
 -    logger.debug("latest blocks:");
 -    for (int i = 0; i < latest_blocks.size(); i++)
 +    if (logger.isDebugEnabled())
      {
 -      FoundBlock found_block = (FoundBlock) latest_blocks.get(i);
 +      logger.debug("latest blocks:");
 +      for (int i = 0; i < latest_blocks.size(); i++)
 +      {
 +        FoundBlock found_block = (FoundBlock) latest_blocks.get(i);
 -      String date_value = getDateValue(text, found_block);
 -      EGIZDate date = EGIZDate.parseFromString(date_value);
 +        String date_value = getDateValue(text, found_block);
 +        EGIZDate date = EGIZDate.parseFromString(date_value);
 -      logger.debug("  #" + i + ": " + date + " - " + found_block);
 +        logger.debug("  #" + i + ": " + date + " - " + found_block);
 +      }
      }
 -    boolean semantic_equality = PdfAS.checkForSemanticEquality(latest_blocks);
 -    logger.debug("semantic_equality = " + semantic_equality);
 -    if (!semantic_equality)
 -    {
 -      throw new SignatureException(314, "The latest blocks weren't semantically equal.");
 -    }
 +    // The semantic equality check has been outdated by the
 +    // advanced choosing algorithm.
 +    // boolean semantic_equality =
 +    // PdfAS.checkForSemanticEquality(latest_blocks);
 +    // logger.debug("semantic_equality = " + semantic_equality);
 +    // if (!semantic_equality)
 +    // {
 +    // throw new SignatureException(314, "The latest blocks weren't semantically
 +    // equal.");
 +    // }
 +
 +    FoundBlock latest_block = chooseMostPossibleBlock(latest_blocks);
 -    FoundBlock latest_block = chooseMostPossibleSemanticallyEqualBlock(latest_blocks);
      logger.debug("latest block = " + latest_block);
      return latest_block;
    }
 @@ -269,7 +289,6 @@ public class AbsoluteTextSignature        }
      }
 -
      for (int lci = 0; lci < found_last_captions.size(); lci++)
      {
        int last_caption_index = ((Integer) found_last_captions.get(lci)).intValue();
 @@ -470,8 +489,6 @@ public class AbsoluteTextSignature     */
    public static int findEndOfValue(String text, int start_index)
    {
 -	 // FIXME[tknall]: this method does not work properly for landscape documents because <text> always starts with "\n". Look for errors in PdfAS.java, method findBlockInText(...) to set the start_index accordingly.
 -	  // Hint: Captions and values of landscape documents are separated with " \n" and not only with " ".
      int newline_index = text.indexOf('\n', start_index);
      if (newline_index < 0)
      {
 @@ -685,44 +702,213 @@ public class AbsoluteTextSignature    }
    /**
 -   * Chooses the most possible (best choice) block of the list of semantically
 -   * equal blocks.
 +   * Chooses the most possible (best choice) block of the list of blocks.
     * 
     * <p>
 -   * Thus blocks are considered semantically equal if their required keys are
 -   * semantically equal, semantically equal blocks may still differ in the
 -   * number of their non required fields. This may lead to multiple found blocks
 -   * of the same size in characters, but where some blocks' elements swallow
 -   * elements found by other blocks.
 +   * The strategy to find the most possible block is to choose the very one
 +   * block with the maximum number of captions. This block has extracted most
 +   * information from the text.
     * </p>
     * <p>
 -   * The strategy to avoid this is to choose the very one block with the maximum
 -   * number of captions. This block has extracted most information from the
 -   * text.
 +   * If there are still multiple blocks with the same number of cations, the
 +   * blocks are compared caption-wise. The block with all captions being longer
 +   * or equal to all other blocks' captions wins.
     * </p>
     * 
     * @param found_blocks
     *          The List of semantically equal blocks.
     * @return Returns the best choice FoundBlock.
 +   * @throws SignatureException
 +   */
 +  public static FoundBlock chooseMostPossibleBlock(List found_blocks) throws SignatureException
 +  {
 +    // int largest_block_index = 0;
 +    // FoundBlock largest_block = (FoundBlock) found_blocks.get(0);
 +    //
 +    // for (int i = 1; i < found_blocks.size(); i++)
 +    // {
 +    // FoundBlock current_block = (FoundBlock) found_blocks.get(i);
 +    //
 +    // if (current_block.found_keys.size() > largest_block.found_keys.size())
 +    // {
 +    // largest_block = current_block;
 +    // largest_block_index = i;
 +    // }
 +    // }
 +
 +    List vertically_largest = filterVerticallyLargestBlocks(found_blocks);
 +    if (logger.isDebugEnabled())
 +    {
 +      logger.debug("vertically largest blocks:");
 +      for (int i = 0; i < vertically_largest.size(); i++)
 +      {
 +        FoundBlock found_block = (FoundBlock) vertically_largest.get(i);
 +
 +        logger.debug("  #" + i + ": " + found_block);
 +      }
 +    }
 +
 +    List horizontally_largest = filterHorizontallyLargestBlocks(vertically_largest);
 +    if (logger.isDebugEnabled())
 +    {
 +      logger.debug("horizontally largest blocks:");
 +      for (int i = 0; i < horizontally_largest.size(); i++)
 +      {
 +        FoundBlock found_block = (FoundBlock) horizontally_largest.get(i);
 +
 +        logger.debug("  #" + i + ": " + found_block);
 +      }
 +    }
 +
 +    FoundBlock largest_block = (FoundBlock) horizontally_largest.get(0);
 +
 +    logger.debug("Chose largest block: " + largest_block);
 +    return largest_block;
 +  }
 +
 +  /**
 +   * Filters out all blocks but the vertically largest ones.
 +   * 
 +   * <p>
 +   * A vertically largest block has the most found keys.
 +   * </p>
 +   * 
 +   * @param found_blocks
 +   *          The List of FoundBlock objects to be filtered.
 +   * @return Returns the List of the vertically largest FoundBlock objects.
     */
 -  public static FoundBlock chooseMostPossibleSemanticallyEqualBlock(
 -      List found_blocks)
 +  public static List filterVerticallyLargestBlocks(List found_blocks)
    {
 -    int largest_block_index = 0;
 +    // determine the size of the largest block(s)
 +    int largest_size = Integer.MIN_VALUE;
 +    for (int i = 1; i < found_blocks.size(); i++)
 +    {
 +      FoundBlock fb = (FoundBlock) found_blocks.get(i);
 +      final int current_size = fb.found_keys.size();
 +      if (current_size > largest_size)
 +      {
 +        largest_size = current_size;
 +      }
 +    }
 +
 +    // keep all blocks that have the largest_size
 +    List largest_blocks = new ArrayList();
 +    for (int i = 0; i < found_blocks.size(); i++)
 +    {
 +      FoundBlock fb = (FoundBlock) found_blocks.get(i);
 +      if (fb.found_keys.size() < largest_size)
 +      {
 +        continue;
 +      }
 +      largest_blocks.add(fb);
 +    }
 +
 +    return largest_blocks;
 +  }
 +
 +  /**
 +   * Filters out all blocks but the horizonally largest ones.
 +   * 
 +   * <p>
 +   * A vertically largest block has the most found keys.
 +   * </p>
 +   * 
 +   * @param found_blocks
 +   *          The List of FoundBlock objects to be filtered. All of these
 +   *          FoundBlock objects must have the same number of found keys.
 +   * @return Returns the List of the horizontally largest FoundBlock objects.
 +   * @throws SignatureException
 +   */
 +  public static List filterHorizontallyLargestBlocks(List found_blocks) throws SignatureException
 +  {
 +    List horizontally_largest = new ArrayList();
      FoundBlock largest_block = (FoundBlock) found_blocks.get(0);
 +    horizontally_largest.add(largest_block);
      for (int i = 1; i < found_blocks.size(); i++)
      {
 -      FoundBlock current_block = (FoundBlock) found_blocks.get(i);
 +      FoundBlock fb = (FoundBlock) found_blocks.get(i);
 +
 +      if (isHorizontallyEqual(fb, largest_block))
 +      {
 +        horizontally_largest.add(fb);
 +        continue;
 +      }
 -      if (current_block.found_keys.size() > largest_block.found_keys.size())
 +      if (isHorizontallyLarger(fb, largest_block))
 +      {
 +        horizontally_largest = new ArrayList();
 +        largest_block = fb;
 +        horizontally_largest.add(largest_block);
 +      }
 +      else
        {
 -        largest_block = current_block;
 -        largest_block_index = i;
 +        if (!isHorizontallyLarger(largest_block, fb))
 +        {
 +          // The block is neither equal nor larger nor lower.
 +          // We cannot exactly determine which one to use.
 +          throw new SignatureException(315, "The blocks are neither larger nor lower nor equal. Cannot decide which one to pick. fb = " + fb + ", largest_block = " + largest_block);
 +        }
        }
 +
      }
 -    logger.debug("Chose largest block with index #" + largest_block_index + ": " + largest_block);
 -    return largest_block;
 +    return horizontally_largest;
    }
 +
 +  protected static boolean isHorizontallyEqual(FoundBlock fb0, FoundBlock fb1)
 +  {
 +    final int num_keys = fb0.found_keys.size();
 +    if (num_keys != fb1.found_keys.size())
 +    {
 +      throw new IllegalArgumentException("Cannot compare FoundBlock keys: fb0 doesn't have the same number of keys as fb1. " + fb0.found_keys.size() + " vs. " + fb1.found_keys.size());
 +    }
 +
 +    for (int i = 0; i < num_keys; i++)
 +    {
 +      FoundKey fk0 = (FoundKey) fb0.found_keys.get(i);
 +      FoundKey fk1 = (FoundKey) fb1.found_keys.get(i);
 +
 +      if (fk0.caption.length() != fk1.caption.length())
 +      {
 +        return false;
 +      }
 +    }
 +
 +    return true;
 +  }
 +
 +  protected static boolean isHorizontallyLarger(FoundBlock fb0, FoundBlock fb1)
 +  {
 +    final int num_keys = fb0.found_keys.size();
 +    if (num_keys != fb1.found_keys.size())
 +    {
 +      throw new IllegalArgumentException("Cannot compare FoundBlock keys: fb0 doesn't have the same number of keys as fb1. " + fb0.found_keys.size() + " vs. " + fb1.found_keys.size());
 +    }
 +
 +    boolean larger = false;
 +
 +    for (int i = 0; i < num_keys; i++)
 +    {
 +      FoundKey fk0 = (FoundKey) fb0.found_keys.get(i);
 +      FoundKey fk1 = (FoundKey) fb1.found_keys.get(i);
 +
 +      if (fk0.caption.length() == fk1.caption.length())
 +      {
 +        continue;
 +      }
 +
 +      if (fk0.caption.length() > fk1.caption.length())
 +      {
 +        larger = true;
 +        continue;
 +      }
 +
 +      // if (fk0.caption.length() < fk1.caption.length())
 +      return false;
 +    }
 +
 +    return larger;
 +  }
 +
  }
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java index c5acbc4..e10061c 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java @@ -667,17 +667,15 @@ public abstract class BinarySignature     *          The original document.
     * @param pdf_table
     *          The PdfPTable that contains the signature block.
 -   * @param pos
 -   *          The Position object giving the exact location where to place the
 -   *          table. if page is -1, a new page will be appended to the document.
 -   *          Then the table will be inserted on that new page using the
 -   *          coordinates.
 +   * @param pi
 +   *          The PositioningInstruction telling the algorithm where to place
 +   *          the signature block.
     * @return Returns the new document.
     * @throws PresentableException
     *           Forwarded exception.
     */
    public static IncrementalUpdateInformation writeIncrementalUpdate(
 -      byte[] original_document, PdfPTable pdf_table, TablePos pos,
 +      byte[] original_document, PdfPTable pdf_table, PositioningInstruction pi,
        List variable_field_definitions, List all_field_definitions) throws PresentableException
    {
      try
 @@ -697,30 +695,20 @@ public abstract class BinarySignature        // The stamper allows this by setting append = true
        PdfStamper stamper = new PdfStamper(reader, baos, '\0', true);
 -      int pdf_page_num = reader.getNumberOfPages();
 -
 -      // int signature_page = -1;
 -      //
 -      // if (pos_y >= 0)
 -      // {
 -      // signature_page = pdf_page_num;
 -      // }
 -      if (pos.page == -1)
 +      if (pi.isMakeNewPage())
        {
 -        pos.page = pdf_page_num + 1;
 +        int pdf_page_num = reader.getNumberOfPages();
          Rectangle psize = reader.getPageSizeWithRotation(pdf_page_num);
          Rectangle rect = new Rectangle(psize);
 -        stamper.insertPage(pos.page, rect);
 -
 -        // pos_y *= -1;
 +        stamper.insertPage(pdf_page_num + 1, rect);
        }
 -      if (pos.page < 1 || pos.page > stamper.getReader().getNumberOfPages())
 +      if (pi.getPage() < 1 || pi.getPage() > stamper.getReader().getNumberOfPages())
        {
 -        throw new PDFDocumentException(224, "The provided pos.page (=" + pos.page + ") is out of range.");
 +        throw new PDFDocumentException(224, "The provided page (=" + pi.getPage() + ") is out of range.");
        }
 -      PdfContentByte content = stamper.getOverContent(pos.page);
 +      PdfContentByte content = stamper.getOverContent(pi.getPage());
        // content = StampContent einer PageStamp.
        // System.out.println("table_width = " + pdf_table.getTotalWidth() + ",
 @@ -741,27 +729,27 @@ public abstract class BinarySignature        // pdf_table.writeSelectedRows(0, -1, SIGNATURE_BORDER / 2,
        // table_position, content);
 -      content.addTemplate(table_template, pos.pos_x, pos.pos_y - pdf_table.getTotalHeight());
 +      content.addTemplate(table_template, pi.getX(), pi.getY() - pdf_table.getTotalHeight());
        // For debugging print a 100x100 grid
 -//      {
 -//        Rectangle psize = reader.getPageSizeWithRotation(pos.page);
 -//        float page_width = psize.width();
 -//        float page_height = psize.height();
 -//        for (float x = 0; x < page_width; x += 100)
 -//        {
 -//          content.moveTo(x, 0);
 -//          content.lineTo(x, page_height);
 -//          content.stroke();
 -//        }
 -//        for (float y = 0; y < page_height; y += 100)
 -//        {
 -//          content.moveTo(0, y);
 -//          content.lineTo(page_width, y);
 -//          content.stroke();
 -//        }
 -//      }
 -      
 +      // {
 +      // Rectangle psize = reader.getPageSizeWithRotation(pos.page);
 +      // float page_width = psize.width();
 +      // float page_height = psize.height();
 +      // for (float x = 0; x < page_width; x += 100)
 +      // {
 +      // content.moveTo(x, 0);
 +      // content.lineTo(x, page_height);
 +      // content.stroke();
 +      // }
 +      // for (float y = 0; y < page_height; y += 100)
 +      // {
 +      // content.moveTo(0, y);
 +      // content.lineTo(page_width, y);
 +      // content.stroke();
 +      // }
 +      // }
 +
        // content.setLineWidth(10.0f);
        // content.moveTo(0, 0);
        // content.lineTo(100, 100);
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java index c98aee8..c1d6681 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java @@ -66,14 +66,23 @@ public class PDFPage extends PDFTextStripper    protected float max_image_ypos = Float.NEGATIVE_INFINITY;
    /**
 -   * The empty constructor.
 +   * The y coordinate of the footer line. PDF elements below this footer line will not be regarded.
 +   */
 +  protected float footer_line = 0.0f;
 +  
 +  /**
 +   * Constructor.
 +   * 
 +   * @param footer_line The y coordinate of the footer line. PDF elements below this footer line will not be regarded.
     * 
     * @throws IOException
     */
 -  public PDFPage() throws IOException
 +  public PDFPage(float footer_line) throws IOException
    {
      super();
 +    this.footer_line = footer_line;
 +    
      OperatorProcessor newInvoke = new MyInvoke();
      newInvoke.setContext(this);
      operators.put("Do", newInvoke);
 @@ -341,17 +350,24 @@ public class PDFPage extends PDFTextStripper     */
    protected void showCharacter(TextPosition text)
    {
 -    float current_y = text.getY();
 -    String character = text.getCharacter();
 +    final float current_y = text.getY();
 +    final String character = text.getCharacter();
 +    
 +//    if (current_y > this.footer_line)
 +//    {
 +//      logger_.debug("character is below footer_line. footer_line = " + this.footer_line + ", text.character=" + character + ", y=" + current_y);
 +//      return;
 +//    }
 +    
      // store ypos of the char if it is not empty
      if (!character.equals(" ") && current_y > this.max_character_ypos)
      {
        this.max_character_ypos = current_y;
 -      //logger_.debug("text.character=" + character + ", y=" + current_y);
 +      logger_.debug("text.character=" + character + ", y=" + current_y);
        // System.err.println(character + "|" + current_y);
      }
 -    // logger_.debug("text.character=" + character + ", y=" + current_y);
 +    logger_.debug("text.character=" + character + ", y=" + current_y);
      // System.err.println(character + "|" + current_y);
    }
 @@ -454,6 +470,12 @@ public class PDFPage extends PDFTextStripper          logger_.debug("actual_lowest_point = " + actual_lowest_point);
 +        if (actual_lowest_point > PDFPage.this.footer_line)
 +        {
 +          logger_.debug("image is below footer_line. footer_line = " + PDFPage.this.footer_line);
 +          return;
 +        }
 +
          if (actual_lowest_point > PDFPage.this.max_image_ypos)
          {
            PDFPage.this.max_image_ypos = actual_lowest_point;
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java index 8fa3b35..05854dd 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java @@ -38,7 +38,7 @@ import com.lowagie.text.DocumentException;   */
  public abstract class PDFUtilities
  {
 -  public static float calculateLastPageLength(final byte[] pdf) throws PDFDocumentException
 +  public static float calculateLastPageLength(final byte[] pdf, float footer_line) throws PDFDocumentException
    {
      try
      {
 @@ -53,7 +53,7 @@ public abstract class PDFUtilities        parser.parse();
        PDDocument pdfDocument_ = parser.getPDDocument();
 -      float last_page_length = calculateLastPageLength(pdfDocument_);
 +      float last_page_length = calculateLastPageLength(pdfDocument_, footer_line);
        pdfDocument_.close();
        return last_page_length;
 @@ -68,20 +68,20 @@ public abstract class PDFUtilities      }
    }
 -  public static float calculateLastPageLength(PDDocument document) throws IOException
 +  public static float calculateLastPageLength(PDDocument document, float footer_line) throws IOException
    {
      int last_page_id = document.getNumberOfPages();
      List allPages = document.getDocumentCatalog().getAllPages();
      PDPage last_page = (PDPage) allPages.get(last_page_id - 1);
 -    return calculatePageLength(last_page);
 +    return calculatePageLength(last_page, footer_line);
    }
 -  public static float calculatePageLength(PDPage page) throws IOException
 +  public static float calculatePageLength(PDPage page, float footer_line) throws IOException
    {
      // logger_.debug("Last Page id:" + last_page_id);
      // PDPage last_page = (PDPage) allPages.get(0);
 -    PDFPage my_page = new PDFPage();
 +    PDFPage my_page = new PDFPage(footer_line);
      my_page.processStream(page, page.findResources(), page.getContents().getStream());
      return my_page.getMaxPageLength();
    }
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PositioningInstruction.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PositioningInstruction.java new file mode 100644 index 0000000..c04177b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PositioningInstruction.java @@ -0,0 +1,131 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id:  $
 + */
 +package at.knowcenter.wag.egov.egiz.pdf;
 +
 +/**
 + * The positioning instruction holds information of where to place the signature
 + * block.
 + * 
 + * <p>
 + * This instruction is given to the PDF writer in order to place the signature.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class PositioningInstruction
 +{
 +
 +  /**
 +   * Tells, if a new plain page should be appended.
 +   * 
 +   * <p>
 +   * This command is executed before the signature block is positioned according
 +   * to page, x and y.
 +   * </p>
 +   */
 +  protected boolean make_new_page = false;
 +
 +  /**
 +   * The number of the page on which the signature block is to be placed. If
 +   * specified to make a new page, the number of this newly created page can be
 +   * used here as well.
 +   */
 +  protected int page = 0;
 +
 +  /**
 +   * The x coordinate where the upper left corner of the signature block should
 +   * be placed.
 +   */
 +  protected float x = 0.0f;
 +
 +  /**
 +   * The y coordinate where the upper left corner of the signature block should
 +   * be placed.
 +   */
 +  protected float y = 0.0f;
 +
 +  /**
 +   * 
 +   * @param make_new_page
 +   *          Tells, if a new plain page should be appended. This command is
 +   *          executed before the signature block is positioned according to
 +   *          page, x and y.
 +   * @param page
 +   *          The number of the page on which the signature block is to be
 +   *          placed. If specified to make a new page, the number of this newly
 +   *          created page can be used here as well.
 +   * @param x
 +   *          The x coordinate where the upper left corner of the signature
 +   *          block should be placed.
 +   * @param y
 +   *          The y coordinate where the upper left corner of the signature
 +   *          block should be placed.
 +   */
 +  public PositioningInstruction(boolean make_new_page, int page, float x, float y)
 +  {
 +    this.make_new_page = make_new_page;
 +    this.page = page;
 +    this.x = x;
 +    this.y = y;
 +  }
 +
 +  /**
 +   * Tells, if a new plain page should be appended to the document.
 +   * 
 +   * @return Returns true, if a new plain page should be appended.
 +   */
 +  public boolean isMakeNewPage()
 +  {
 +    return this.make_new_page;
 +  }
 +
 +  /**
 +   * Returns the page on which the signature is to be printed.
 +   * 
 +   * @return Returns the page on which the signature is to be printed.
 +   */
 +  public int getPage()
 +  {
 +    return this.page;
 +  }
 +
 +  /**
 +   * Returns the x coordinate where the upper left corner of the signature block
 +   * should be placed.
 +   * 
 +   * @return Returns the x coordinate where the upper left corner of the
 +   *         signature block should be placed.
 +   */
 +  public float getX()
 +  {
 +    return this.x;
 +  }
 +
 +  /**
 +   * Returns the y coordinate where the upper left corner of the signature block
 +   * should be placed.
 +   * 
 +   * @return Returns the y coordinate where the upper left corner of the
 +   *         signature block should be placed.
 +   */
 +  public float getY()
 +  {
 +    return this.y;
 +  }
 +
 +}
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java index ba55cdf..6cfdded 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java @@ -35,6 +35,22 @@ public class TablePos implements Serializable    /**
     * The page on which the block should be displayed.
 +   * 
 +   * <p>
 +   * A value greater than or equal 1 means to absolutely position the signature
 +   * on that page.
 +   * </p>
 +   * <p>
 +   * A value of -1 means to append a new page to the document and absolutely
 +   * position the signature on the new page.
 +   * </p>
 +   * <p>
 +   * A value of -2 means to determine the length of the last page as without
 +   * absolute positioning, but ignore all text below a certain footer line. If
 +   * there is enough space between the end of the text and this footer line, the
 +   * signature should be positioned automatically in there. Otherwise it should
 +   * be placed on a new page.
 +   * </p>
     */
    public int page = 0;
 @@ -53,4 +69,8 @@ public class TablePos implements Serializable     */
    public float width = 0.0f;
 +  /**
 +   * The top y position of the footer line.
 +   */
 +  public float footer_line = 0.0f;
  }
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java index 13e0b65..65c79a9 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java @@ -17,6 +17,8 @@   */
  package at.knowcenter.wag.egov.egiz.sig;
 +import java.util.Properties;
 +
  import at.knowcenter.wag.egov.egiz.exceptions.SignatureException;
  /**
 @@ -74,27 +76,25 @@ public interface LocalConnector extends Connector    /**
     * Analyzes the sign response string.
     * 
 -   * @param response_string
 -   *          The response string from the local service.
     * @param signature_type
     *          The type of the signature.
     * @return Returns the SignatureObject of the sign request.
     * @throws SignatureException
     *           F.e.
     */
 -  public SignatureObject analyzeSignResponse(String response_string,
 +  // TODO hotfix
 +  public SignatureObject analyzeSignResponse(Properties response_properties,
        String signature_type) throws SignatureException;
    /**
     * Analyzes the verify response string.
     * 
 -   * @param response_string
 -   *          The response string from the local service.
     * @return Returns the SignatureResponse of the verify request.
     * @throws SignatureException
     *           F.e.
     */
 -  public SignatureResponse analyzeVerifyResponse(String response_string) throws SignatureException;
 +  // TODO hotfix
 +  public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws SignatureException;
    /**
     * Returns the sign URL of the local service.
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java index 9a7a036..ae50c5e 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java @@ -31,6 +31,7 @@ import java.util.Hashtable;  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
 +import java.util.Properties;
  import java.util.Set;
  import java.util.Vector;
 @@ -41,13 +42,14 @@ import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger;  import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
  import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException;
  import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException;
 +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException;
  import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
  import at.knowcenter.wag.egov.egiz.exceptions.SignatureException;
  import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException;
 -import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
  import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException;
  import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIFactory;
  import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
  import at.knowcenter.wag.egov.egiz.table.Entry;
  import at.knowcenter.wag.egov.egiz.table.Style;
  import at.knowcenter.wag.egov.egiz.table.Table;
 @@ -181,7 +183,7 @@ public class SignatureObject implements Serializable     * </p>
     */
    protected String raw_signature_response = null;
 -  
 +
    /**
     * Filters the issuer name in order to find matches.
     * @author tknall
 @@ -199,8 +201,6 @@ public class SignatureObject implements Serializable  		}
  	};
 -  
 -
    /**
     * The empty constructor. It initilize the normlizer, load the settings and
     * set the default styles.
 @@ -270,7 +270,6 @@ public class SignatureObject implements Serializable      defaultImageStyle_.setPadding(3);
      defaultImageStyle_.setHAlign(Style.CENTER);
      defaultImageStyle_.setVAlign(Style.MIDDLE);
 -//    defaultImageStyle_.setBgColor(new Color(255, 255, 255));
      defaultImageStyle_.setBgColor(null);
      defaultCaptionStyle_.setHAlign(Style.CENTER);
 @@ -737,20 +736,42 @@ public class SignatureObject implements Serializable      setSigValue(SignatureTypes.SIG_ID, sigIds);
    }
 -  /**
 -   * Set the signation id's build by a BKU signated SignatureObject.
 -   * 
 -   * @param sigIds
 -   *          The sination id's are defined into five parts, that have the same
 -   *          base as prefix. Therefore the ids's are reduced by the base prefix
 -   *          and stored in the SignatureObject.
 -   */
 -  public void setSignationIDs(String[] sigIds)
 +  // /**
 +  // * Set the signation id's build by a BKU signated SignatureObject.
 +  // *
 +  // * @param sigIds
 +  // * The sination id's are defined into five parts, that have the same
 +  // * base as prefix. Therefore the ids's are reduced by the base prefix
 +  // * and stored in the SignatureObject.
 +  // */
 +  // public void setSignationIDs(String[] sigIds)
 +  // {
 +  // String join = "";
 +  // String base = null;
 +  // for (int arr_idx = 0; arr_idx < sigIds.length; arr_idx++)
 +  // {
 +  // String id = sigIds[arr_idx];
 +  // if (logger_.isDebugEnabled())
 +  // {
 +  // logger_.debug("Set BKU id:" + id);
 +  // }
 +  // int id_idx = id.lastIndexOf("-");
 +  // if (arr_idx == 0)
 +  // {
 +  // base = id.substring(0, id_idx);
 +  // }
 +  // String cur_id = id.substring(id_idx + 1);
 +  // join += "-" + cur_id;
 +  // }
 +  // setSignationIDs(base + "@" + join.substring(1));
 +  // }
 +
 +  // TODO hotfix
 +  public static String formatSigIds(Properties response_properties,
 +      String[] sigIds) throws SignatureException
    {
 -    
 -	 // FIXME[tknall]: implement workaround resp. failsafe behaviour for ids like "Signature-123456789"
 -	  
 -	  String join = "";
 +    // ids algorithm:
 +    String join = "";
      String base = null;
      for (int arr_idx = 0; arr_idx < sigIds.length; arr_idx++)
      {
 @@ -767,7 +788,47 @@ public class SignatureObject implements Serializable        String cur_id = id.substring(id_idx + 1);
        join += "-" + cur_id;
      }
 -    setSignationIDs(base + "@" + join.substring(1));
 +    // setSignationIDs(base + "@" + join.substring(1));
 +    String ids = base + "@" + join.substring(1);
 +    // :ids algorithm
 +
 +    String productName = response_properties.getProperty("productName");
 +    logger_.debug("productName = " + productName);
 +    if (!productName.equals("trustDeskbasic"))
 +    {
 +      final String msg = "The BKU environment " + productName + " is not trustDeskbasic and therefore the productVersion cannot be decided.";
 +      logger_.error(msg);
 +      throw new SignatureException(0, msg);
 +    }
 +
 +    String productVersion = response_properties.getProperty("productVersion");
 +    logger_.debug("productVersion = " + productVersion);
 +    boolean new_etsi = decideNewEtsiByBKUVersion(productVersion);
 +    logger_.debug("verwende neue etsi properties = " + new_etsi);
 +
 +    String etsi_prefix = "";
 +    if (new_etsi)
 +    {
 +      // TODO hotfix
 +      etsi_prefix = "etsi-bka-1.0@";
 +    }
 +
 +    String final_ids = etsi_prefix + ids;
 +    logger_.debug("final_ids = " + final_ids);
 +
 +    return final_ids;
 +  }
 +
 +  // TODO hotfix
 +  public static boolean decideNewEtsiByBKUVersion(String productVersion)
 +  {
 +    boolean new_etsi = true;
 +    // TODO make better
 +    if (productVersion.startsWith("2.5") || productVersion.startsWith("2.4") || productVersion.startsWith("2.3") || productVersion.startsWith("2.2") || productVersion.startsWith("2.1") || productVersion.startsWith("1") || productVersion.startsWith("0"))
 +    {
 +      new_etsi = false;
 +    }
 +    return new_etsi;
    }
    /**
 @@ -837,9 +898,51 @@ public class SignatureObject implements Serializable     * 
     * @return the id array
     */
 -  public String[] getSignationIds()
 +  // TODO hotifx
 +  public String getSignationIds()
    {
      String sig_ids = getSigValue(SignatureTypes.SIG_ID);
 +    return sig_ids;
 +
 +    // if (sig_ids == null || sig_ids.length() == 0)
 +    // {
 +    // return null;
 +    // }
 +    //
 +    // // int index = sig_ids.indexOf(PdfAS.IDS);
 +    // // if (index < 0)
 +    // // {
 +    // // return null;
 +    // // }
 +    // // sig_ids = sig_ids.substring(index + PdfAS.IDS.length());
 +    // //
 +    // // if (sig_ids == null || sig_ids.length() == 0)
 +    // // {
 +    // // return null;
 +    // // }
 +    //
 +    // String[] ids_str = sig_ids.split("@");
 +    // String base = ids_str[0];
 +    // String[] ids = ids_str[1].split("-");
 +    // String[] real_ids = new String[5];
 +    // real_ids[0] = base + "-" + ids[0];
 +    // real_ids[1] = "0-" + base + "-" + ids[1];
 +    // real_ids[2] = "0-" + base + "-" + ids[2];
 +    // real_ids[3] = "0-" + base + "-" + ids[3];
 +    // real_ids[4] = "0-" + base + "-" + ids[4];
 +    // if (logger_.isDebugEnabled())
 +    // {
 +    // for (int id_idx = 0; id_idx < real_ids.length; id_idx++)
 +    // {
 +    // logger_.debug("Set BKU id:" + real_ids[id_idx]);
 +    // }
 +    // }
 +    // return real_ids;
 +  }
 +
 +  // TODO hotfix
 +  public static String[] parseSigIds(String sig_ids)
 +  {
      if (sig_ids == null || sig_ids.length() == 0)
      {
        return null;
 @@ -858,21 +961,33 @@ public class SignatureObject implements Serializable      // }
      String[] ids_str = sig_ids.split("@");
 +
 +    String etsi_string = null;
 +    if (ids_str.length == 3)
 +    {
 +      etsi_string = ids_str[0];
 +      String[] rest_ids = new String[] { ids_str[1], ids_str[2] };
 +      ids_str = rest_ids;
 +    }
 +
      String base = ids_str[0];
      String[] ids = ids_str[1].split("-");
 -    String[] real_ids = new String[5];
 +    String[] real_ids = new String[6]; // the last one contains the etsi string
      real_ids[0] = base + "-" + ids[0];
      real_ids[1] = "0-" + base + "-" + ids[1];
      real_ids[2] = "0-" + base + "-" + ids[2];
      real_ids[3] = "0-" + base + "-" + ids[3];
      real_ids[4] = "0-" + base + "-" + ids[4];
 +    real_ids[5] = etsi_string;
 +    
      if (logger_.isDebugEnabled())
      {
        for (int id_idx = 0; id_idx < real_ids.length; id_idx++)
        {
 -        logger_.debug("Set BKU id:" + real_ids[id_idx]);
 +        logger_.debug("real_ids[" + id_idx + "] = " + real_ids[id_idx]);
        }
      }
 +
      return real_ids;
    }
 @@ -1364,6 +1479,12 @@ public class SignatureObject implements Serializable      }
      SignatureTypes sig_types = SignatureTypes.getInstance();
      signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_);
 +    if (signatureDefinition_ == null)
 +    {
 +      final String msg = "The SignatureObject's sigType '" + sigType_ + "' wasn't found in the configuration file's specified signature profiles. This usually happens if the sig_obj.type.default object has been turned off or is misspelled.";
 +      logger_.error(msg);
 +      throw new SignatureTypesException(msg);
 +    }
      Map key_cap_map = signatureDefinition_.getKeyCaptionMap();
      if (key_cap_map != null)
      {
 @@ -1409,10 +1530,10 @@ public class SignatureObject implements Serializable            }
          }
          // value = new String(CodingHelper.encodeUTF8(value));
 -//        if (logger_.isDebugEnabled())
 -//        {
 -//          logger_.debug("key:" + key + " value:" + value);
 -//        }
 +        // if (logger_.isDebugEnabled())
 +        // {
 +        // logger_.debug("key:" + key + " value:" + value);
 +        // }
          setSigValue(key, value);
        }
      }
 @@ -1534,6 +1655,4 @@ public class SignatureObject implements Serializable      return strg;
    }
 -  
 -  
  }
\ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java index 3b672f1..6327a11 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java @@ -18,6 +18,7 @@  package at.knowcenter.wag.egov.egiz.sig.connectors;
  import java.io.UnsupportedEncodingException;
 +import java.util.Properties;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
 @@ -116,9 +117,9 @@ public class BKUConnector implements LocalConnector      String request_string = prepareSignRequest(userName, signText, sigType);
      String sign_url = getSignURL(sigType);
 -    String response_string = sendRequest(sign_url, request_string);
 +    Properties response_properties = sendRequest(sign_url, request_string);
 -    return analyzeSignResponse(response_string, sigType);
 +    return analyzeSignResponse(response_properties, sigType);
    }
    /**
 @@ -140,9 +141,9 @@ public class BKUConnector implements LocalConnector      String request_string = prepareVerifyRequest(normalizedText, sigObject);
      String verify_url = getVerifyURL(sigObject.getSignationType());
 -    String response_string = sendRequest(verify_url, request_string);
 +    Properties response_properties = sendRequest(verify_url, request_string);
 -    return analyzeVerifyResponse(response_string);
 +    return analyzeVerifyResponse(response_properties);
    }
    /**
 @@ -162,8 +163,10 @@ public class BKUConnector implements LocalConnector     * @see CodingHelper
     * @see X509Cert
     */
 -  private void parseCreateXMLResponse(String xmlResponse, SignatureObject sigObj) throws SignatureException
 +  private void parseCreateXMLResponse(Properties response_properties, SignatureObject sigObj) throws SignatureException
    {
 +    String xmlResponse = response_properties.getProperty("response_string");
 +    
      Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>");
      Pattern sig_val_p_e = Pattern.compile("</[\\w]*:?SignatureValue>");
      Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>");
 @@ -266,7 +269,11 @@ public class BKUConnector implements LocalConnector      ids[2] = extractId(xmlResponse, "signed-data-object-");
      ids[3] = extractId(xmlResponse, "etsi-data-reference-");
      ids[4] = extractId(xmlResponse, "etsi-data-object-");
 -    sigObj.setSignationIDs(ids);
 +    
 +    //TODO hotfix
 +    String final_ids =SignatureObject.formatSigIds(response_properties, ids);
 +    //sigObj.setSignationIDs(ids);
 +    sigObj.setSignationIDs(final_ids);
    }
    /**
 @@ -283,6 +290,13 @@ public class BKUConnector implements LocalConnector      String id = null;
      int start_idx = text.indexOf(name) + name.length();
      int end_idx = text.indexOf("\"", start_idx);
 +    
 +    // TODO hotfix!
 +    final int quot_end_idx = end_idx; 
 +    final int squot_end_idx = text.indexOf("'", start_idx);
 +    end_idx = Math.min(quot_end_idx, squot_end_idx);
 +    // TODO hotfix end!
 +    
      id = text.substring(start_idx, end_idx);
      if (logger_.isDebugEnabled())
      {
 @@ -324,6 +338,21 @@ public class BKUConnector implements LocalConnector      String verify_template = getVerifyTemplateFileName(sigObject.getSignationType());
      String sig_prop_filename = getSigPropFileName(sigObject.getSignationType());
 +    String ids_string = sigObject.getSignationIds();
 +    logger_.debug("ids_string = " + ids_string);
 +    String[] ids = SignatureObject.parseSigIds(ids_string);
 +
 +    // TODO hotfix
 +    final boolean neue_bku = ids[5] != null;
 +    logger_.debug("ids[5] = " + ids[5]);
 +    logger_.debug("neue_bku = " + neue_bku);
 +    if (neue_bku)
 +    {
 +      verify_template   = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2"); //"./templates/BKUVerifyTemplateB64_neueBKU.xml";
 +      sig_prop_filename = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2.SP"); //"./templates/BKUVerifyTemplateSP_neueBKU.xml";
 +    }
 +    
 +
      String ver_temp_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template));
      String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_filename));
      if (logger_.isDebugEnabled())
 @@ -345,8 +374,7 @@ public class BKUConnector implements LocalConnector        cert_alg = settings_.getValueFromKey("cert.alg.rsa");
      }
 -    String[] ids = sigObject.getSignationIds();
 -    sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate());
 +     sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate());
      String issuer_name = sigObject.getSignationIssuer();
      // The issuer is already unicode, so it mustn't be encoded again.
 @@ -362,6 +390,26 @@ public class BKUConnector implements LocalConnector      ver_temp_str = ver_temp_str.replaceFirst("CertAlgReplace", cert_alg);
      ver_temp_str = ver_temp_str.replaceFirst("TemplateQualifyingPropertiesReplace", sig_prop_str);
      byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"));
 +    
 +    // TODO hotfix
 +    if (neue_bku)
 +    {
 +      final String ETSI_SIGNED_PROPERTIES_START_TAG = "<etsi:SignedProperties"; // xml name spaces follow, so this is not a complete tag...
 +      final String ETSI_SIGNED_PROPERTIES_END_TAG = "</etsi:SignedProperties>";
 +      
 +      final int hash_start = sig_prop_str.indexOf(ETSI_SIGNED_PROPERTIES_START_TAG);
 +      assert hash_start >= 0;
 +      final int hash_end = sig_prop_str.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length();
 +      assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0;
 +      assert hash_end > hash_start;
 +      
 +      final String string_to_be_hashed =  sig_prop_str.substring(hash_start, hash_end);
 +      logger_.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed);
 +      
 +      final byte [] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8");
 +      sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed);
 +    }
 +    
      String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code);
      ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash);
      if (logger_.isDebugEnabled())
 @@ -445,7 +493,7 @@ public class BKUConnector implements LocalConnector      Pattern cert_qualified_p = Pattern.compile("<sl:QualifiedCertificate/>");
      Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse);
      // [tknall] stop qualified certificate
 -    
 +
      Pattern code_p_s = Pattern.compile("<sl:Code>");
      Pattern code_p_e = Pattern.compile("</sl:Code>");
      Pattern info_p_s = Pattern.compile("<sl:Info>");
 @@ -472,7 +520,7 @@ public class BKUConnector implements LocalConnector      Matcher cert_m_e = cert_p_e.matcher(xmlResponse);
      SignatureResponse sig_res = new SignatureResponse();
 -    
 +
      // [tknall] start qualified certificate
      sig_res.setQualifiedCertificate(cert_qualified_m.find());
      // [tknall] stop qualified certificate
 @@ -613,7 +661,7 @@ public class BKUConnector implements LocalConnector      verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str);
      if (logger_.isDebugEnabled())
      {
 -      //logger_.debug(verify_request + "_request.xml : " + verify_req_str);
 +      logger_.debug("verify_req_str.xml : " + verify_req_str);
      }
      return verify_req_str;
 @@ -630,12 +678,12 @@ public class BKUConnector implements LocalConnector     * @throws SignatureException
     *           F.e.
     */
 -  protected String sendRequest(String url, String request_string) throws SignatureException
 +  protected Properties sendRequest(String url, String request_string) throws SignatureException
    {
      try
      {
 -      String response_string = BKUPostConnection.doPostRequest(url, request_string);
 -      return response_string;
 +      Properties response_properties = BKUPostConnection.doPostRequest(url, request_string);
 +      return response_properties;
      }
      catch (Exception e)
      {
 @@ -644,11 +692,14 @@ public class BKUConnector implements LocalConnector      }
    }
 -  public SignatureObject analyzeSignResponse(String response_string,
 +  public SignatureObject analyzeSignResponse(Properties response_properties,
        String sigType) throws SignatureException
    {
      //String sign_request_filename = getSignRequestTemplateFileName(sigType);
 +    // TODO hotfix
 +    String response_string = response_properties.getProperty("response_string");
 +    
      SignatureObject sig_obj = new SignatureObject();
      sig_obj.setRawSignatureResponse(response_string);
      try
 @@ -699,17 +750,19 @@ public class BKUConnector implements LocalConnector        {
          if (logger_.isDebugEnabled())
          {
 -          //logger_.debug(sign_request_filename + "_response.xml : " + response_string);
 +          logger_.debug("signature_response_string: " + response_string);
          }
 -        parseCreateXMLResponse(response_string, sig_obj);
 +        parseCreateXMLResponse(response_properties, sig_obj);
        }
      }
      sig_obj.setSigResponse(response_string);
      return sig_obj;
    }
 -  public SignatureResponse analyzeVerifyResponse(String response_string) throws SignatureException
 +  public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws SignatureException
    {
 +    String response_string = response_properties.getProperty("response_string");
 +    
      if (!response_string.equals(""))
      {
        Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>");
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java index 773b248..1ddef5f 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java @@ -18,7 +18,11 @@  package at.knowcenter.wag.egov.egiz.sig.connectors;
  import java.io.IOException;
 +import java.util.Properties;
 +import java.util.regex.Matcher;
 +import java.util.regex.Pattern;
 +import org.apache.commons.httpclient.Header;
  import org.apache.commons.httpclient.HttpClient;
  import org.apache.commons.httpclient.HttpException;
  import org.apache.commons.httpclient.NameValuePair;
 @@ -52,7 +56,7 @@ public abstract class BKUPostConnection     * @throws HttpException
     *           ErrorCode:320
     */
 -  public static String doPostRequest(String url, String request) throws HttpException, IOException
 +  public static Properties doPostRequest(String url, String request) throws HttpException, IOException
    {
      PostMethod post_method = new PostMethod(url);
 @@ -81,6 +85,23 @@ public abstract class BKUPostConnection      int method_response = http_client.executeMethod(post_method);
      logger_.debug("method_response = " + method_response);
 +    Properties response_properties = new Properties();
 +    
 +    if (logger_.isDebugEnabled())
 +    {
 +      Header[] response_headers = post_method.getResponseHeaders();
 +      logger_.debug("#" + response_headers.length + " headers in response:");
 +      for (int i = 0; i < response_headers.length; i++)
 +      {
 +        logger_.debug("  response_header[" + i + "]: name = " + response_headers[i].getName() + ", value = " + response_headers[i].getValue());
 +      }
 +    }
 +    
 +    Header server_header = post_method.getResponseHeader("Server");
 +    logger_.debug("server_header: name = " + server_header.getName() + ", value = " + server_header.getValue());
 +    parseBKUVersion(server_header.getValue(), response_properties);
 +
 +
      byte[] response_body = post_method.getResponseBody();
      String response_string = new String(response_body, "UTF-8");
 @@ -89,7 +110,36 @@ public abstract class BKUPostConnection      // response.
      // String response_string = post.getResponseBodyAsString();
 -    return response_string;
 +    response_properties.setProperty("response_string", response_string);
 +    
 +    return response_properties;
    }
 +  // TODO hotfix
 +  public static void parseBKUVersion(String header_value, Properties properties)
 +  {
 +    Pattern pattern = Pattern.compile("^citizen-card-environment/(\\d+\\.\\d+) (.+)/(\\d+\\.\\d+\\.\\d+)$");
 +    Matcher m = pattern.matcher(header_value);
 +    
 +    m.matches();
 +    
 +    logger_.debug("group count = " + m.groupCount());
 +    
 +    for (int i = 0; i <= m.groupCount(); i++)
 +    {
 +      logger_.debug("  group[" + i + "] = " + m.group(i));
 +    }
 +    
 +    final String cceVersion = m.group(1);
 +    final String productName = m.group(2);
 +    final String productVersion = m.group(3);
 +    
 +    logger_.debug("cceVersion = " + cceVersion);
 +    logger_.debug("productName = " + productName);
 +    logger_.debug("productVersion = " + productVersion);
 +    
 +    properties.setProperty("cceVersion", cceVersion);
 +    properties.setProperty("productName", productName);
 +    properties.setProperty("productVersion", productVersion);
 +  }
  }
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java index 847bbcf..52846f5 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java @@ -18,7 +18,9 @@  package at.knowcenter.wag.egov.egiz.web;
  import java.io.IOException;
 +import java.util.Enumeration;
  import java.util.List;
 +import java.util.Properties;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
 @@ -34,6 +36,7 @@ import org.apache.log4j.Logger;  import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger;
  import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.BKUPostConnection;
  /**
   * Servlet that responds to the data post requests of the local service (e.g.
 @@ -143,7 +146,23 @@ public class AsynchronousDataResponder extends HttpServlet      }
 -    si.response_string[si.current_operation] = resp_string; //request.getParameter("XMLResponse");
 +    // TODO hotfix
 +    if (logger_.isDebugEnabled())
 +    {
 +      Enumeration header_names = request.getHeaderNames();
 +      while (header_names.hasMoreElements())
 +      {
 +        String header_name = (String)header_names.nextElement();
 +        String header_value = request.getHeader(header_name);
 +        logger_.debug("header: name = " + header_name + ", value = " +header_value);
 +      }
 +    }
 +    String user_agent = request.getHeader("User-Agent");
 +    logger_.debug("User-Agent header = " + user_agent);
 +    Properties response_properties = new Properties();
 +    BKUPostConnection.parseBKUVersion(user_agent, response_properties);
 +    response_properties.setProperty("response_string", resp_string);
 +    si.response_properties[si.current_operation] = response_properties; //request.getParameter("XMLResponse");
      //logger_.debug("AsyncDataResponder: si.response_string[si.current_operation] = " + si.response_string[si.current_operation]);
      si.current_operation++;
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java index b79dd87..031b03c 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java @@ -147,9 +147,9 @@ public class AsynchronousRedirectResponder extends HttpServlet        {
          List results = new ArrayList();
 -        for (int i = 0; i < si.response_string.length; i++)
 +        for (int i = 0; i < si.response_properties.length; i++)
          {
 -          SignatureResponse sig_resp = local_conn.analyzeVerifyResponse(si.response_string[i]);
 +          SignatureResponse sig_resp = local_conn.analyzeVerifyResponse(si.response_properties[i]);
            results.add(sig_resp);
          }
 @@ -176,7 +176,7 @@ public class AsynchronousRedirectResponder extends HttpServlet          // has already been computed - don't recompute it.
          if (si.sign_result == null)
          {
 -          si.iui.signed_signature_object = local_conn.analyzeSignResponse(si.response_string[0], si.type);
 +          si.iui.signed_signature_object = local_conn.analyzeSignResponse(si.response_properties[0], si.type);
            PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode);
            Signator signator = SignatorFactory.createSignator(algorithm);
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java index 50bea41..95f72ef 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java @@ -21,6 +21,7 @@ import java.io.IOException;  import java.net.URL;
  import java.util.ArrayList;
  import java.util.List;
 +import java.util.Properties;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
 @@ -82,8 +83,8 @@ public abstract class LocalRequestHelper      si.requests = new LocalRequest[1];
      si.requests[0] = new LocalRequest(local_conn.getSignURL(si.type), request_string);
      si.current_operation = 0;
 -    si.response_string = new String[1];
 -    si.response_string[0] = null;
 +    si.response_properties = new Properties[1];
 +    si.response_properties[0] = null;
      // SessionTable.put(si);
      request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, si);
 @@ -113,7 +114,7 @@ public abstract class LocalRequestHelper        HttpServletResponse response) throws SignatureException, NormalizeException, IOException, ConnectorFactoryException
    {
      si.requests = new LocalRequest[holders_to_verify.size()];
 -    si.response_string = new String[si.requests.length];
 +    si.response_properties = new Properties[si.requests.length];
      si.current_operation = 0;
      si.finished = false;
 @@ -134,7 +135,7 @@ public abstract class LocalRequestHelper        LocalRequest local_request = new LocalRequest(local_conn.getVerifyURL(holder.getSignatureObject().getSignationType()), request_string);
        si.requests[i] = local_request;
 -      si.response_string[i] = null;
 +      si.response_properties[i] = null;
      }
      // ByteArrayOutputStream baos = new ByteArrayOutputStream();
 diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java index f3c34d3..52a51a3 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java @@ -19,6 +19,7 @@ package at.knowcenter.wag.egov.egiz.web;  import java.io.Serializable;
  import java.util.List;
 +import java.util.Properties;
  import at.knowcenter.wag.egov.egiz.framework.SignResult;
  import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation;
 @@ -91,7 +92,7 @@ public class SessionInformation implements Serializable    /**
     * An array of response strings of the local requests.
     */
 -  public String[] response_string = null;
 +  public Properties[] response_properties = null;
    /**
     * Tells, if the current local request has been finished.
 diff --git a/src/main/java/com/lowagie/text/pdf/PdfDictionary.java b/src/main/java/com/lowagie/text/pdf/PdfDictionary.java index f7310e4..acf84d5 100644 --- a/src/main/java/com/lowagie/text/pdf/PdfDictionary.java +++ b/src/main/java/com/lowagie/text/pdf/PdfDictionary.java @@ -105,11 +105,20 @@ public class PdfDictionary extends PdfObject {  /** This is the hashmap that contains all the values and keys of the dictionary */
      protected HashMap hashMap;
 +    
 +    // EGIZ various modifications
      /**
       * This list preserves the order of the elements.
 +     * 
 +     * <p>
 +     * If an element to be added to the list already exists in the list,
 +     * it sould not be added as the contents of this new element
 +     * overwrites the contents of the old element in the hash map.
 +     * </p>
       */
      protected List list;
 +    
      // constructors
  /**
 @@ -175,8 +184,13 @@ public class PdfDictionary extends PdfObject {   */
      public void put(PdfName key, PdfObject value) {
 +        if (!hashMap.containsKey(key))
 +        {
 +          // If the key is new, add it to the ordered list.
 +          // If not, it already has a position in the list.
 +          list.add(key);
 +        }
          hashMap.put(key, value);
 -        list.add(key);
      }
  /**
 | 
