You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by gb...@apache.org on 2013/03/06 17:46:37 UTC

svn commit: r1453416 [10/16] - in /pdfbox/trunk/preflight: ./ src/main/java/org/apache/pdfbox/preflight/ src/main/java/org/apache/pdfbox/preflight/action/ src/main/java/org/apache/pdfbox/preflight/annotation/ src/main/java/org/apache/pdfbox/preflight/a...

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/ICCProfileWrapper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/ICCProfileWrapper.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/ICCProfileWrapper.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/ICCProfileWrapper.java Wed Mar  6 16:46:35 2013
@@ -40,109 +40,128 @@ import org.apache.pdfbox.preflight.excep
 import org.apache.pdfbox.preflight.utils.COSUtils;
 
 /**
- * This class embeds an instance of java.awt.color.ICC_Profile which represent
- * the ICCProfile defined by the DestOutputItents key of the OutputIntents of
- * the PDF.
+ * This class embeds an instance of java.awt.color.ICC_Profile which represent the ICCProfile defined by the
+ * DestOutputItents key of the OutputIntents of the PDF.
  */
-public class ICCProfileWrapper {
-  /**
-   * The ICCProfile extracted from DestOutputItents
-   */
-  private final ICC_Profile profile;
-
-  /**
-   * The ICC ColorSpace created using the ICCProfile
-   */
-  private final ICC_ColorSpace colorSpace;
-
-  public ICCProfileWrapper(final ICC_Profile _profile) {
-    this.profile = _profile;
-    this.colorSpace = new ICC_ColorSpace(_profile);
-  }
-
-  /**
-   * Call the ICC_ColorSpace.getType method and return the value.
-   * 
-   * @return
-   */
-  public int getColorSpaceType() {
-    return colorSpace.getType();
-  }
-
-  /**
-   * @return the profile
-   */
-  public ICC_Profile getProfile() {
-    return profile;
-  }
-
-  /**
-   * Return true if the ColourSpace is RGB
-   * 
-   * @return
-   */
-  public boolean isRGBColorSpace() {
-    return ICC_ColorSpace.TYPE_RGB == colorSpace.getType();
-  }
-
-  /**
-   * Return true if the ColourSpace is CMYK
-   * 
-   * @return
-   */
-  public boolean isCMYKColorSpace() {
-    return ICC_ColorSpace.TYPE_CMYK == colorSpace.getType();
-  }
-
-  /**
-   * Return true if the ColourSpace is Gray scale
-   * 
-   * @return
-   */
-  public boolean isGrayColorSpace() {
-    return ICC_ColorSpace.TYPE_GRAY == colorSpace.getType();
-  }
-
-	/**
-	 * This method read all outputIntent dictionary until on of them have a destOutputProfile stream.
-	 * This stream is parsed and is used to create a IccProfileWrapper.
-	 *  
-	 * @param context
-	 * @return an instance of ICCProfileWrapper or null if there are no DestOutputProfile
-	 * @throws ValidationException if an IOException occurs during the DestOutputProfile parsing 
-	 */
-	private static ICCProfileWrapper searchFirstICCProfile(PreflightContext context) throws ValidationException {
-		PreflightDocument document = context.getDocument();
-		PDDocumentCatalog catalog = document.getDocumentCatalog();
-		COSBase cBase = catalog.getCOSDictionary().getItem(COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OUTPUT_INTENTS));
-		COSArray outputIntents = COSUtils.getAsArray(cBase, document.getDocument());
-
-		for (int i = 0; outputIntents != null && i < outputIntents.size(); ++i) {
-			COSDictionary outputIntentDict = COSUtils.getAsDictionary(outputIntents.get(i), document.getDocument());
-			COSBase destOutputProfile = outputIntentDict.getItem(OUTPUT_INTENT_DICTIONARY_KEY_DEST_OUTPUT_PROFILE);
-			if (destOutputProfile != null) {
-				try {
-					PDStream stream = PDStream.createFromCOS(COSUtils.getAsStream(destOutputProfile, document.getDocument()));
-					if (stream != null) {
-						ICC_Profile iccp = ICC_Profile.getInstance(stream.getByteArray());
-						return new ICCProfileWrapper(iccp);
-					}
-				} catch (IllegalArgumentException e) {
-					throw new ValidationException("DestOutputProfile isn't a ICCProfile", e);
-				} catch (IOException e) {
-					throw new ValidationException("Unable to parse the ICCProfile", e);
-				}
-			}
-		}
-		return null;
-	}
-	
-	public static ICCProfileWrapper getOrSearchICCProfile(PreflightContext context) throws ValidationException {
-		ICCProfileWrapper profileWrapper = context.getIccProfileWrapper();
-		if (profileWrapper == null && !context.isIccProfileAlreadySearched()) {
-			profileWrapper = searchFirstICCProfile(context);
-			context.setIccProfileAlreadySearched(true);
-		}
-		return profileWrapper;
-	}
+public class ICCProfileWrapper
+{
+    /**
+     * The ICCProfile extracted from DestOutputItents
+     */
+    private final ICC_Profile profile;
+
+    /**
+     * The ICC ColorSpace created using the ICCProfile
+     */
+    private final ICC_ColorSpace colorSpace;
+
+    public ICCProfileWrapper(final ICC_Profile _profile)
+    {
+        this.profile = _profile;
+        this.colorSpace = new ICC_ColorSpace(_profile);
+    }
+
+    /**
+     * Call the ICC_ColorSpace.getType method and return the value.
+     * 
+     * @return
+     */
+    public int getColorSpaceType()
+    {
+        return colorSpace.getType();
+    }
+
+    /**
+     * @return the profile
+     */
+    public ICC_Profile getProfile()
+    {
+        return profile;
+    }
+
+    /**
+     * Return true if the ColourSpace is RGB
+     * 
+     * @return
+     */
+    public boolean isRGBColorSpace()
+    {
+        return ICC_ColorSpace.TYPE_RGB == colorSpace.getType();
+    }
+
+    /**
+     * Return true if the ColourSpace is CMYK
+     * 
+     * @return
+     */
+    public boolean isCMYKColorSpace()
+    {
+        return ICC_ColorSpace.TYPE_CMYK == colorSpace.getType();
+    }
+
+    /**
+     * Return true if the ColourSpace is Gray scale
+     * 
+     * @return
+     */
+    public boolean isGrayColorSpace()
+    {
+        return ICC_ColorSpace.TYPE_GRAY == colorSpace.getType();
+    }
+
+    /**
+     * This method read all outputIntent dictionary until on of them have a destOutputProfile stream. This stream is
+     * parsed and is used to create a IccProfileWrapper.
+     * 
+     * @param context
+     * @return an instance of ICCProfileWrapper or null if there are no DestOutputProfile
+     * @throws ValidationException
+     *             if an IOException occurs during the DestOutputProfile parsing
+     */
+    private static ICCProfileWrapper searchFirstICCProfile(PreflightContext context) throws ValidationException
+    {
+        PreflightDocument document = context.getDocument();
+        PDDocumentCatalog catalog = document.getDocumentCatalog();
+        COSBase cBase = catalog.getCOSDictionary().getItem(COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OUTPUT_INTENTS));
+        COSArray outputIntents = COSUtils.getAsArray(cBase, document.getDocument());
+
+        for (int i = 0; outputIntents != null && i < outputIntents.size(); ++i)
+        {
+            COSDictionary outputIntentDict = COSUtils.getAsDictionary(outputIntents.get(i), document.getDocument());
+            COSBase destOutputProfile = outputIntentDict.getItem(OUTPUT_INTENT_DICTIONARY_KEY_DEST_OUTPUT_PROFILE);
+            if (destOutputProfile != null)
+            {
+                try
+                {
+                    PDStream stream = PDStream.createFromCOS(COSUtils.getAsStream(destOutputProfile,
+                            document.getDocument()));
+                    if (stream != null)
+                    {
+                        ICC_Profile iccp = ICC_Profile.getInstance(stream.getByteArray());
+                        return new ICCProfileWrapper(iccp);
+                    }
+                }
+                catch (IllegalArgumentException e)
+                {
+                    throw new ValidationException("DestOutputProfile isn't a ICCProfile", e);
+                }
+                catch (IOException e)
+                {
+                    throw new ValidationException("Unable to parse the ICCProfile", e);
+                }
+            }
+        }
+        return null;
+    }
+
+    public static ICCProfileWrapper getOrSearchICCProfile(PreflightContext context) throws ValidationException
+    {
+        ICCProfileWrapper profileWrapper = context.getIccProfileWrapper();
+        if (profileWrapper == null && !context.isIccProfileAlreadySearched())
+        {
+            profileWrapper = searchFirstICCProfile(context);
+            context.setIccProfileAlreadySearched(true);
+        }
+        return profileWrapper;
+    }
 }

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/NoPatternColorSpaceHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/NoPatternColorSpaceHelper.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/NoPatternColorSpaceHelper.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/NoPatternColorSpaceHelper.java Wed Mar  6 16:46:35 2013
@@ -28,22 +28,24 @@ import org.apache.pdfbox.preflight.Prefl
 import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
 
 /**
- * This class defines restrictions on Pattern ColorSpace. It checks the
- * consistency of the Color space with the DestOutputIntent, if the color space
- * is a Pattern the validation will fail.
+ * This class defines restrictions on Pattern ColorSpace. It checks the consistency of the Color space with the
+ * DestOutputIntent, if the color space is a Pattern the validation will fail.
  */
-public class NoPatternColorSpaceHelper extends StandardColorSpaceHelper {
+public class NoPatternColorSpaceHelper extends StandardColorSpaceHelper
+{
 
-  
-  public NoPatternColorSpaceHelper(PreflightContext _context, PDColorSpace _cs) {
-		super(_context, _cs);
-	}
+    public NoPatternColorSpaceHelper(PreflightContext _context, PDColorSpace _cs)
+    {
+        super(_context, _cs);
+    }
 
-/**
-   * This method updates the given list with a ValidationError
-   * (ERROR_GRAPHIC_INVALID_PATTERN_COLOR_SPACE_FORBIDDEN) and returns false.
-   */
-  protected void processPatternColorSpace(PDColorSpace pdcs) {
-    context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_PATTERN_COLOR_SPACE_FORBIDDEN, "Pattern color space is forbidden"));
-  }
+    /**
+     * This method updates the given list with a ValidationError (ERROR_GRAPHIC_INVALID_PATTERN_COLOR_SPACE_FORBIDDEN)
+     * and returns false.
+     */
+    protected void processPatternColorSpace(PDColorSpace pdcs)
+    {
+        context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_PATTERN_COLOR_SPACE_FORBIDDEN,
+                "Pattern color space is forbidden"));
+    }
 }

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/StandardColorSpaceHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/StandardColorSpaceHelper.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/StandardColorSpaceHelper.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/graphic/StandardColorSpaceHelper.java Wed Mar  6 16:46:35 2013
@@ -21,7 +21,6 @@
 
 package org.apache.pdfbox.preflight.graphic;
 
-
 import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_GRAPHIC_INVALID_COLOR_SPACE;
 import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_GRAPHIC_INVALID_COLOR_SPACE_ALTERNATE;
 import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_GRAPHIC_INVALID_COLOR_SPACE_CMYK;
@@ -52,341 +51,406 @@ import org.apache.pdfbox.preflight.Valid
 import org.apache.pdfbox.preflight.exception.ValidationException;
 
 /**
- * This class doesn't define restrictions on ColorSpace. It checks only the
- * consistency of the Color space with the DestOutputIntent.
+ * This class doesn't define restrictions on ColorSpace. It checks only the consistency of the Color space with the
+ * DestOutputIntent.
  */
-public class StandardColorSpaceHelper implements ColorSpaceHelper {
-	/**
-	 * The context which contains useful information to process the
-	 * validation.
-	 */
-	protected PreflightContext context = null;
-	/**
-	 * The ICCProfile contained in the DestOutputIntent
-	 */
-	protected ICCProfileWrapper iccpw = null;
-	/**
-	 * High level object which represents the colors space to check.
-	 */
-	protected PDColorSpace pdcs = null;
-
-	protected StandardColorSpaceHelper(PreflightContext _context, PDColorSpace _cs) {
-		this.context = _context;
-		this.pdcs = _cs;
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see
-	 * net.awl.edoc.pdfa.validation.graphics.color.ColorSpaceHelper#validate(java
-	 * .util.List)
-	 */
-	public final void validate() throws ValidationException {
-		if ( pdcs == null ) {
-			throw new ValidationException("Unable to create a PDColorSpace with the value null");
-		}
-
-		this.iccpw = ICCProfileWrapper.getOrSearchICCProfile(context);
-		processAllColorSpace(pdcs);
-	}
-
-	/**
-	 * Method called by the validate method. According to the ColorSpace, a
-	 * specific ColorSpace method is called.
-	 * 
-	 * @param pdcs
-	 *          the color space object to check.
-	 * @param result
-	 *          the list of error to update if the validation fails.
-	 * @return true if the validation succeed, false otherwise.
-	 */
-	protected final void processAllColorSpace(PDColorSpace pdcs) {
-		ColorSpaces cs = ColorSpaces.valueOf(pdcs.getName());
-
-		switch (cs) {
-		case DeviceRGB:
-		case DeviceRGB_SHORT:
-			processRGBColorSpace(pdcs);
-			break;
-		case DeviceCMYK:
-		case DeviceCMYK_SHORT:
-			processCYMKColorSpace(pdcs);
-			break;
-		case CalRGB:
-		case CalGray:
-		case Lab:
-			processCalibratedColorSpace(pdcs);
-			break;
-		case DeviceGray:
-		case DeviceGray_SHORT:
-			processGrayColorSpace(pdcs);
-			break;
-		case ICCBased:
-			processICCBasedColorSpace(pdcs);
-			break;
-		case DeviceN:
-			processDeviceNColorSpace(pdcs);
-			break;
-		case Indexed:
-		case Indexed_SHORT: 
-			processIndexedColorSpace(pdcs);
-			break;
-		case Separation:
-			processSeparationColorSpace(pdcs);
-			break;
-		case Pattern:
-			processPatternColorSpace(pdcs);
-			break;
-		default:
-			context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_UNKNOWN_COLOR_SPACE, cs.getLabel() + " is unknown as ColorSpace"));
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is
-	 * DeviceRGB.
-	 * 
-	 */
-	protected void processRGBColorSpace(PDColorSpace pdcs) {
-		if (!processDefaultColorSpace(pdcs)) {
-			if (iccpw == null) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING, "DestOutputProfile is missing"));
-			} else if (!iccpw.isRGBColorSpace()) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_RGB, "DestOutputProfile isn't RGB ColorSpace"));
-			}
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is
-	 * DeviceCYMK.
-	 * 
-	 */
-	protected void processCYMKColorSpace(PDColorSpace pdcs) {
-		if (!processDefaultColorSpace(pdcs)) {
-			if (iccpw == null) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING, "DestOutputProfile is missing"));
-			} else if (!iccpw.isCMYKColorSpace()) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_CMYK, "DestOutputProfile isn't CMYK ColorSpace"));
-			}
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is a
-	 * Pattern.
-	 */
-	protected void processPatternColorSpace(PDColorSpace pdcs) {
-		if (iccpw == null) {
-			context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING, "DestOutputProfile is missing"));
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is
-	 * DeviceGray.
-	 * 
-	 */
-	protected void processGrayColorSpace(PDColorSpace pdcs) {
-		if (!processDefaultColorSpace(pdcs) && iccpw == null) {
-			context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING, "DestOutputProfile is missing"));
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is a
-	 * Clibrated Color (CalGary, CalRGB, Lab).
-	 * 
-	 */
-	protected void processCalibratedColorSpace(PDColorSpace pdcs) {
-		// ---- OutputIntent isn't mandatory
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is a
-	 * ICCBased color space. Because this kind of ColorSpace can have alternate
-	 * color space, the processAllColorSpace is called to check this alternate
-	 * color space. (Pattern is forbidden as Alternate Color Space)
-	 * 
-	 * @param pdcs
-	 *          the color space object to check.
-	 */
-	protected void processICCBasedColorSpace(PDColorSpace pdcs) {
-		PDICCBased iccBased = (PDICCBased) pdcs;
-		try {
-			ICC_Profile iccp = ICC_Profile.getInstance(iccBased.getPDStream().getByteArray());
-			if (iccp == null) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_ICCBASED, "Unable to read ICCBase color space "));
-				return ;
-			}
-			List<PDColorSpace> altCs = iccBased.getAlternateColorSpaces();
-			for (PDColorSpace altpdcs : altCs) {
-				if (altpdcs != null) {
-
-					ColorSpaces altCsId = ColorSpaces.valueOf(altpdcs.getName());
-					if (altCsId == ColorSpaces.Pattern) {
-						context.addValidationError(new ValidationError(
-								ERROR_GRAPHIC_INVALID_PATTERN_COLOR_SPACE_FORBIDDEN, "Pattern is forbidden as AlternateColorSpace of a ICCBased"));
-						return;
-					}
-
-					/*
-					 * According to the ISO-19005-1:2005
-					 * 
-					 * A conforming reader shall render ICCBased colour spaces as specified 
-					 * by the ICC specification, and shall not use the Alternate colour space 
-					 * specified in an ICC profile stream dictionary
-					 * 
-					 * We don't check the alternate ColorSpaces
-					 */
-				}
-			}
-		} catch (IOException e) {
-			context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE, "Unable to read ICCBase color space : " + e.getMessage()));
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is
-	 * DeviceN. Because this kind of ColorSpace can have alternate color space,
-	 * the processAllColorSpace is called to check this alternate color space.
-	 * (There are no restrictions on the Alternate Color space)
-	 * 
-	 * @param pdcs
-	 *          the color space object to check.
-	 */
-	protected void processDeviceNColorSpace(PDColorSpace pdcs) {
-		PDDeviceN deviceN = (PDDeviceN) pdcs;
-		try {
-			if (iccpw == null) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING, "DestOutputProfile is missing"));
-				return;
-			}
-
-			PDColorSpace altColor = deviceN.getAlternateColorSpace();
-			if (altColor != null) {
-				processAllColorSpace(altColor);
-			}
-
-			int numberOfColorants = 0;
-			PDDeviceNAttributes attr = deviceN.getAttributes();
-			if ( attr != null ) {
-				Map colorants = attr.getColorants();
-				if (colorants != null) {
-					numberOfColorants = colorants.size();
-					for (Object col : colorants.values()) {
-						if (col != null) {
-							processAllColorSpace((PDColorSpace) col);
-						}
-					}
-				}
-			}
-			int numberOfComponents = deviceN.getNumberOfComponents();
-			if (numberOfColorants > MAX_DEVICE_N_LIMIT || numberOfComponents > MAX_DEVICE_N_LIMIT ) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_TOO_MANY_COMPONENTS_DEVICEN, "DeviceN has too many tint components or colorants"));  
-			}
-		} catch (IOException e) {
-			context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE, "Unable to read DeviceN color space : " + e.getMessage()));
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is
-	 * Indexed. Because this kind of ColorSpace can have a Base color space, the
-	 * processAllColorSpace is called to check this base color space. (Indexed and
-	 * Pattern can't be a Base color space)
-	 * 
-	 * @param pdcs
-	 *          the color space object to check.
-	 */
-	protected void processIndexedColorSpace(PDColorSpace pdcs) {
-		PDIndexed indexed = (PDIndexed) pdcs;
-		try {
-			PDColorSpace based = indexed.getBaseColorSpace();
-			ColorSpaces cs = ColorSpaces.valueOf(based.getName());
-			if (cs == ColorSpaces.Indexed || cs == ColorSpaces.Indexed_SHORT) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_INDEXED,"Indexed color space can't be used as Base color space"));
-				return;
-			}
-			if (cs == ColorSpaces.Pattern) {
-				context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_INDEXED,"Pattern color space can't be used as Base color space"));
-				return ;
-			}
-			processAllColorSpace(based);
-		} catch (IOException e) {
-			context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE, "Unable to read Indexed color space : " + e.getMessage()));
-		}
-	}
-
-	/**
-	 * Method called by the processAllColorSpace if the ColorSpace to check is
-	 * Separation. Because this kind of ColorSpace can have an alternate color
-	 * space, the processAllColorSpace is called to check this alternate color
-	 * space. (Indexed, Separation, DeviceN and Pattern can't be a Base color
-	 * space)
-	 * 
-	 * @param pdcs
-	 *          the color space object to check.
-	 */
-	protected void processSeparationColorSpace(PDColorSpace pdcs) {
-		PDSeparation separation = (PDSeparation) pdcs;
-		try {
-
-			PDColorSpace altCol = separation.getAlternateColorSpace();
-			if (altCol != null) {
-				ColorSpaces acs = ColorSpaces.valueOf(altCol.getName());
-				switch (acs) {
-				case Separation:
-				case DeviceN:
-				case Pattern:
-				case Indexed:
-				case Indexed_SHORT:
-					context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_ALTERNATE, acs.getLabel() + " color space can't be used as alternate color space"));
-					break;
-				default:
-					processAllColorSpace(altCol);
-				}
-			}
-		} catch (IOException e) {
-			context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE, "Unable to read Separation color space : " + e.getMessage()));
-		}
-	}
-
-	/**
-	 * Look up in the closest PDResources objects if there are a default ColorSpace.
-	 * If there are, check that is a authorized ColorSpace.
-	 * @param pdcs
-	 * @return true if the default colorspace is a right one, false otherwise.
-	 */
-	protected boolean processDefaultColorSpace(PDColorSpace pdcs) {
-		boolean result = false;
-
-		// get default color space
-		PreflightPath vPath = context.getValidationPath();
-		PDResources resources = vPath.getClosestPathElement(PDResources.class);
-		if (resources != null && resources.getColorSpaces() != null) {
-			PDColorSpace defaultCS = null;
-
-			Map<String, PDColorSpace> colorsSpaces = resources.getColorSpaces();
-			if (pdcs.getName().equals(ColorSpaces.DeviceCMYK.getLabel())) {
-				defaultCS = colorsSpaces.get("DefaultCMYK");
-			} else if (pdcs.getName().equals(ColorSpaces.DeviceRGB.getLabel())) {
-				defaultCS = colorsSpaces.get("DefaultRGB");
-			} else if (pdcs.getName().equals(ColorSpaces.DeviceGray.getLabel())) {
-				defaultCS = colorsSpaces.get("DefaultGray");
-			}
-
-			if (defaultCS != null) {
-				// defaultCS is valid if the number of errors hasn't changed
-				int nbOfErrors = context.getDocument().getResult().getErrorsList().size();
-				processAllColorSpace(defaultCS);
-				int newNbOfErrors = context.getDocument().getResult().getErrorsList().size();
-				result = (nbOfErrors == newNbOfErrors);
-			}
-
-		}
-
-		return result;
-	}
-}
\ No newline at end of file
+public class StandardColorSpaceHelper implements ColorSpaceHelper
+{
+    /**
+     * The context which contains useful information to process the validation.
+     */
+    protected PreflightContext context = null;
+    /**
+     * The ICCProfile contained in the DestOutputIntent
+     */
+    protected ICCProfileWrapper iccpw = null;
+    /**
+     * High level object which represents the colors space to check.
+     */
+    protected PDColorSpace pdcs = null;
+
+    protected StandardColorSpaceHelper(PreflightContext _context, PDColorSpace _cs)
+    {
+        this.context = _context;
+        this.pdcs = _cs;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see net.awl.edoc.pdfa.validation.graphics.color.ColorSpaceHelper#validate(java .util.List)
+     */
+    public final void validate() throws ValidationException
+    {
+        if (pdcs == null)
+        {
+            throw new ValidationException("Unable to create a PDColorSpace with the value null");
+        }
+
+        this.iccpw = ICCProfileWrapper.getOrSearchICCProfile(context);
+        processAllColorSpace(pdcs);
+    }
+
+    /**
+     * Method called by the validate method. According to the ColorSpace, a specific ColorSpace method is called.
+     * 
+     * @param pdcs
+     *            the color space object to check.
+     * @param result
+     *            the list of error to update if the validation fails.
+     * @return true if the validation succeed, false otherwise.
+     */
+    protected final void processAllColorSpace(PDColorSpace pdcs)
+    {
+        ColorSpaces cs = ColorSpaces.valueOf(pdcs.getName());
+
+        switch (cs)
+        {
+        case DeviceRGB:
+        case DeviceRGB_SHORT:
+            processRGBColorSpace(pdcs);
+            break;
+        case DeviceCMYK:
+        case DeviceCMYK_SHORT:
+            processCYMKColorSpace(pdcs);
+            break;
+        case CalRGB:
+        case CalGray:
+        case Lab:
+            processCalibratedColorSpace(pdcs);
+            break;
+        case DeviceGray:
+        case DeviceGray_SHORT:
+            processGrayColorSpace(pdcs);
+            break;
+        case ICCBased:
+            processICCBasedColorSpace(pdcs);
+            break;
+        case DeviceN:
+            processDeviceNColorSpace(pdcs);
+            break;
+        case Indexed:
+        case Indexed_SHORT:
+            processIndexedColorSpace(pdcs);
+            break;
+        case Separation:
+            processSeparationColorSpace(pdcs);
+            break;
+        case Pattern:
+            processPatternColorSpace(pdcs);
+            break;
+        default:
+            context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_UNKNOWN_COLOR_SPACE, cs.getLabel()
+                    + " is unknown as ColorSpace"));
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is DeviceRGB.
+     * 
+     */
+    protected void processRGBColorSpace(PDColorSpace pdcs)
+    {
+        if (!processDefaultColorSpace(pdcs))
+        {
+            if (iccpw == null)
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING,
+                        "DestOutputProfile is missing"));
+            }
+            else if (!iccpw.isRGBColorSpace())
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_RGB,
+                        "DestOutputProfile isn't RGB ColorSpace"));
+            }
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is DeviceCYMK.
+     * 
+     */
+    protected void processCYMKColorSpace(PDColorSpace pdcs)
+    {
+        if (!processDefaultColorSpace(pdcs))
+        {
+            if (iccpw == null)
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING,
+                        "DestOutputProfile is missing"));
+            }
+            else if (!iccpw.isCMYKColorSpace())
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_CMYK,
+                        "DestOutputProfile isn't CMYK ColorSpace"));
+            }
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is a Pattern.
+     */
+    protected void processPatternColorSpace(PDColorSpace pdcs)
+    {
+        if (iccpw == null)
+        {
+            context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING,
+                    "DestOutputProfile is missing"));
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is DeviceGray.
+     * 
+     */
+    protected void processGrayColorSpace(PDColorSpace pdcs)
+    {
+        if (!processDefaultColorSpace(pdcs) && iccpw == null)
+        {
+            context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING,
+                    "DestOutputProfile is missing"));
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is a Clibrated Color (CalGary, CalRGB, Lab).
+     * 
+     */
+    protected void processCalibratedColorSpace(PDColorSpace pdcs)
+    {
+        // ---- OutputIntent isn't mandatory
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is a ICCBased color space. Because this kind
+     * of ColorSpace can have alternate color space, the processAllColorSpace is called to check this alternate color
+     * space. (Pattern is forbidden as Alternate Color Space)
+     * 
+     * @param pdcs
+     *            the color space object to check.
+     */
+    protected void processICCBasedColorSpace(PDColorSpace pdcs)
+    {
+        PDICCBased iccBased = (PDICCBased) pdcs;
+        try
+        {
+            ICC_Profile iccp = ICC_Profile.getInstance(iccBased.getPDStream().getByteArray());
+            if (iccp == null)
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_ICCBASED,
+                        "Unable to read ICCBase color space "));
+                return;
+            }
+            List<PDColorSpace> altCs = iccBased.getAlternateColorSpaces();
+            for (PDColorSpace altpdcs : altCs)
+            {
+                if (altpdcs != null)
+                {
+
+                    ColorSpaces altCsId = ColorSpaces.valueOf(altpdcs.getName());
+                    if (altCsId == ColorSpaces.Pattern)
+                    {
+                        context.addValidationError(new ValidationError(
+                                ERROR_GRAPHIC_INVALID_PATTERN_COLOR_SPACE_FORBIDDEN,
+                                "Pattern is forbidden as AlternateColorSpace of a ICCBased"));
+                        return;
+                    }
+
+                    /*
+                     * According to the ISO-19005-1:2005
+                     * 
+                     * A conforming reader shall render ICCBased colour spaces as specified by the ICC specification,
+                     * and shall not use the Alternate colour space specified in an ICC profile stream dictionary
+                     * 
+                     * We don't check the alternate ColorSpaces
+                     */
+                }
+            }
+        }
+        catch (IOException e)
+        {
+            context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE,
+                    "Unable to read ICCBase color space : " + e.getMessage()));
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is DeviceN. Because this kind of ColorSpace
+     * can have alternate color space, the processAllColorSpace is called to check this alternate color space. (There
+     * are no restrictions on the Alternate Color space)
+     * 
+     * @param pdcs
+     *            the color space object to check.
+     */
+    protected void processDeviceNColorSpace(PDColorSpace pdcs)
+    {
+        PDDeviceN deviceN = (PDDeviceN) pdcs;
+        try
+        {
+            if (iccpw == null)
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_MISSING,
+                        "DestOutputProfile is missing"));
+                return;
+            }
+
+            PDColorSpace altColor = deviceN.getAlternateColorSpace();
+            if (altColor != null)
+            {
+                processAllColorSpace(altColor);
+            }
+
+            int numberOfColorants = 0;
+            PDDeviceNAttributes attr = deviceN.getAttributes();
+            if (attr != null)
+            {
+                Map colorants = attr.getColorants();
+                if (colorants != null)
+                {
+                    numberOfColorants = colorants.size();
+                    for (Object col : colorants.values())
+                    {
+                        if (col != null)
+                        {
+                            processAllColorSpace((PDColorSpace) col);
+                        }
+                    }
+                }
+            }
+            int numberOfComponents = deviceN.getNumberOfComponents();
+            if (numberOfColorants > MAX_DEVICE_N_LIMIT || numberOfComponents > MAX_DEVICE_N_LIMIT)
+            {
+                context.addValidationError(new ValidationError(
+                        ERROR_GRAPHIC_INVALID_COLOR_SPACE_TOO_MANY_COMPONENTS_DEVICEN,
+                        "DeviceN has too many tint components or colorants"));
+            }
+        }
+        catch (IOException e)
+        {
+            context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE,
+                    "Unable to read DeviceN color space : " + e.getMessage()));
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is Indexed. Because this kind of ColorSpace
+     * can have a Base color space, the processAllColorSpace is called to check this base color space. (Indexed and
+     * Pattern can't be a Base color space)
+     * 
+     * @param pdcs
+     *            the color space object to check.
+     */
+    protected void processIndexedColorSpace(PDColorSpace pdcs)
+    {
+        PDIndexed indexed = (PDIndexed) pdcs;
+        try
+        {
+            PDColorSpace based = indexed.getBaseColorSpace();
+            ColorSpaces cs = ColorSpaces.valueOf(based.getName());
+            if (cs == ColorSpaces.Indexed || cs == ColorSpaces.Indexed_SHORT)
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_INDEXED,
+                        "Indexed color space can't be used as Base color space"));
+                return;
+            }
+            if (cs == ColorSpaces.Pattern)
+            {
+                context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_INDEXED,
+                        "Pattern color space can't be used as Base color space"));
+                return;
+            }
+            processAllColorSpace(based);
+        }
+        catch (IOException e)
+        {
+            context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE,
+                    "Unable to read Indexed color space : " + e.getMessage()));
+        }
+    }
+
+    /**
+     * Method called by the processAllColorSpace if the ColorSpace to check is Separation. Because this kind of
+     * ColorSpace can have an alternate color space, the processAllColorSpace is called to check this alternate color
+     * space. (Indexed, Separation, DeviceN and Pattern can't be a Base color space)
+     * 
+     * @param pdcs
+     *            the color space object to check.
+     */
+    protected void processSeparationColorSpace(PDColorSpace pdcs)
+    {
+        PDSeparation separation = (PDSeparation) pdcs;
+        try
+        {
+
+            PDColorSpace altCol = separation.getAlternateColorSpace();
+            if (altCol != null)
+            {
+                ColorSpaces acs = ColorSpaces.valueOf(altCol.getName());
+                switch (acs)
+                {
+                case Separation:
+                case DeviceN:
+                case Pattern:
+                case Indexed:
+                case Indexed_SHORT:
+                    context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE_ALTERNATE, acs
+                            .getLabel() + " color space can't be used as alternate color space"));
+                    break;
+                default:
+                    processAllColorSpace(altCol);
+                }
+            }
+        }
+        catch (IOException e)
+        {
+            context.addValidationError(new ValidationError(ERROR_GRAPHIC_INVALID_COLOR_SPACE,
+                    "Unable to read Separation color space : " + e.getMessage()));
+        }
+    }
+
+    /**
+     * Look up in the closest PDResources objects if there are a default ColorSpace. If there are, check that is a
+     * authorized ColorSpace.
+     * 
+     * @param pdcs
+     * @return true if the default colorspace is a right one, false otherwise.
+     */
+    protected boolean processDefaultColorSpace(PDColorSpace pdcs)
+    {
+        boolean result = false;
+
+        // get default color space
+        PreflightPath vPath = context.getValidationPath();
+        PDResources resources = vPath.getClosestPathElement(PDResources.class);
+        if (resources != null && resources.getColorSpaces() != null)
+        {
+            PDColorSpace defaultCS = null;
+
+            Map<String, PDColorSpace> colorsSpaces = resources.getColorSpaces();
+            if (pdcs.getName().equals(ColorSpaces.DeviceCMYK.getLabel()))
+            {
+                defaultCS = colorsSpaces.get("DefaultCMYK");
+            }
+            else if (pdcs.getName().equals(ColorSpaces.DeviceRGB.getLabel()))
+            {
+                defaultCS = colorsSpaces.get("DefaultRGB");
+            }
+            else if (pdcs.getName().equals(ColorSpaces.DeviceGray.getLabel()))
+            {
+                defaultCS = colorsSpaces.get("DefaultGray");
+            }
+
+            if (defaultCS != null)
+            {
+                // defaultCS is valid if the number of errors hasn't changed
+                int nbOfErrors = context.getDocument().getResult().getErrorsList().size();
+                processAllColorSpace(defaultCS);
+                int newNbOfErrors = context.getDocument().getResult().getErrorsList().size();
+                result = (nbOfErrors == newNbOfErrors);
+            }
+
+        }
+
+        return result;
+    }
+}

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java Wed Mar  6 16:46:35 2013
@@ -42,69 +42,80 @@ import org.apache.xmpbox.type.Structured
  * @author Germain Costenobel
  * 
  */
-public class PDFAIdentificationValidation {
+public class PDFAIdentificationValidation
+{
 
-  /**
-   * Check if PDFAIdentification is valid
-   * 
-   * @param document
-   *          the PDF Document
-   * @param metadata
-   *          the XMP MetaData
-   * @return List of validation errors
-   * @throws ValidationException
-   */
-  public List<ValidationError> validatePDFAIdentifer(XMPMetadata metadata) throws ValidationException {
-    List<ValidationError> ve = new ArrayList<ValidationError>();
-    PDFAIdentificationSchema id = metadata.getPDFIdentificationSchema();
-    if (id == null) {
-      ve.add(new ValidationError(ERROR_METADATA_PDFA_ID_MISSING));
-      return ve;
+    /**
+     * Check if PDFAIdentification is valid
+     * 
+     * @param document
+     *            the PDF Document
+     * @param metadata
+     *            the XMP MetaData
+     * @return List of validation errors
+     * @throws ValidationException
+     */
+    public List<ValidationError> validatePDFAIdentifer(XMPMetadata metadata) throws ValidationException
+    {
+        List<ValidationError> ve = new ArrayList<ValidationError>();
+        PDFAIdentificationSchema id = metadata.getPDFIdentificationSchema();
+        if (id == null)
+        {
+            ve.add(new ValidationError(ERROR_METADATA_PDFA_ID_MISSING));
+            return ve;
+        }
+
+        // According to the PDF/A specification, the prefix must be pdfaid for this schema.
+        StructuredType stBasic = XMPBasicSchema.class.getAnnotation(StructuredType.class);
+        StructuredType stPdfaIdent = PDFAIdentificationSchema.class.getAnnotation(StructuredType.class);
+        if (!id.getPrefix().equals(stPdfaIdent.preferedPrefix()))
+        {
+            if (metadata.getSchema(stPdfaIdent.preferedPrefix(), stBasic.namespace()) == null)
+            {
+                ve.add(unexpectedPrefixFoundError(id.getPrefix(), stPdfaIdent.preferedPrefix(),
+                        PDFAIdentificationSchema.class.getName()));
+            }
+            else
+            {
+                id = (PDFAIdentificationSchema) metadata.getSchema(stPdfaIdent.preferedPrefix(),
+                        stPdfaIdent.namespace());
+            }
+        }
+        checkConformanceLevel(ve, id.getConformance());
+        checkPartNumber(ve, id.getPart());
+        return ve;
     }
 
-    // According to the PDF/A specification, the prefix must be pdfaid for this schema.
-    StructuredType stBasic = XMPBasicSchema.class.getAnnotation(StructuredType.class);
-    StructuredType stPdfaIdent = PDFAIdentificationSchema.class.getAnnotation(StructuredType.class);
-    if (!id.getPrefix().equals(stPdfaIdent.preferedPrefix())) {
-      if (metadata.getSchema(stPdfaIdent.preferedPrefix(), stBasic.namespace()) == null) {
-        ve.add(unexpectedPrefixFoundError(id.getPrefix(),
-                        stPdfaIdent.preferedPrefix(), PDFAIdentificationSchema.class.getName()));
-      } else {
-        id = (PDFAIdentificationSchema) metadata.getSchema(
-            stPdfaIdent.preferedPrefix(), stPdfaIdent.namespace());
-      }
+    /**
+     * Return a validationError formatted when a schema has not the expected prefix
+     * 
+     * @param prefFound
+     * @param prefExpected
+     * @param schema
+     * @return
+     */
+    protected ValidationError unexpectedPrefixFoundError(String prefFound, String prefExpected, String schema)
+    {
+        StringBuilder sb = new StringBuilder(80);
+        sb.append(schema).append(" found but prefix used is '").append(prefFound).append("', prefix '")
+                .append(prefExpected).append("' is expected.");
+
+        return new ValidationError(ERROR_METADATA_WRONG_NS_PREFIX, sb.toString());
     }
-    checkConformanceLevel(ve, id.getConformance());
-    checkPartNumber(ve, id.getPart());
-    return ve;
-  }
-
-  /**
-   * Return a validationError formatted when a schema has not the expected
-   * prefix
-   * 
-   * @param prefFound
-   * @param prefExpected
-   * @param schema
-   * @return
-   */
-  protected ValidationError unexpectedPrefixFoundError(String prefFound, String prefExpected, String schema) {
-    StringBuilder sb = new StringBuilder(80);
-    sb.append(schema).append(" found but prefix used is '").append(prefFound)
-        .append("', prefix '").append(prefExpected).append("' is expected.");
-
-    return new ValidationError(ERROR_METADATA_WRONG_NS_PREFIX, sb.toString());
-  }
-
-  protected void checkConformanceLevel(List<ValidationError> ve, String value) {
-    if (!(value.equals("A") || value.equals("B"))) {
-      ve.add(new ValidationError(ERROR_METADATA_INVALID_PDFA_CONFORMANCE));
+
+    protected void checkConformanceLevel(List<ValidationError> ve, String value)
+    {
+        if (!(value.equals("A") || value.equals("B")))
+        {
+            ve.add(new ValidationError(ERROR_METADATA_INVALID_PDFA_CONFORMANCE));
+        }
     }
-  }
 
-  protected void checkPartNumber(List<ValidationError> ve, int value) {
-    if (value != 1) {
-      ve.add(new ValidationError(ERROR_METADATA_INVALID_PDFA_VERSION_ID));
+    protected void checkPartNumber(List<ValidationError> ve, int value)
+    {
+        if (value != 1)
+        {
+            ve.add(new ValidationError(ERROR_METADATA_INVALID_PDFA_VERSION_ID));
+        }
     }
-  }
 }

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/RDFAboutAttributeConcordanceValidation.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/RDFAboutAttributeConcordanceValidation.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/RDFAboutAttributeConcordanceValidation.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/RDFAboutAttributeConcordanceValidation.java Wed Mar  6 16:46:35 2013
@@ -23,56 +23,59 @@ package org.apache.pdfbox.preflight.meta
 
 import java.util.List;
 
-
 import org.apache.pdfbox.preflight.exception.ValidationException;
 import org.apache.xmpbox.XMPMetadata;
 import org.apache.xmpbox.schema.XMPSchema;
 
 /**
- * Class which all elements within an rdf:RDF have the same value for their
- * rdf:about attributes
+ * Class which all elements within an rdf:RDF have the same value for their rdf:about attributes
  * 
  * @author Germain Costenobel
  * 
  */
-public class RDFAboutAttributeConcordanceValidation {
+public class RDFAboutAttributeConcordanceValidation
+{
 
-  /**
-   * 
-   * @param metadata
-   * @return
-   * @throws DifferentRDFAboutException
-   * @throws ValidationException
-   */
-  public void validateRDFAboutAttributes(XMPMetadata metadata)
-      throws ValidationException, DifferentRDFAboutException {
-
-    List<XMPSchema> schemas = metadata.getAllSchemas();
-    if (schemas.size() == 0) {
-      throw new ValidationException(
-          "Schemas not found in the given metadata representation");
-    }
-    String about = schemas.get(0).getAboutValue();
-    // rdf:description must have an rdf:about attribute
-    for (XMPSchema xmpSchema : schemas) {
-      checkRdfAbout(about, xmpSchema);
-    }
+    /**
+     * 
+     * @param metadata
+     * @return
+     * @throws DifferentRDFAboutException
+     * @throws ValidationException
+     */
+    public void validateRDFAboutAttributes(XMPMetadata metadata) throws ValidationException, DifferentRDFAboutException
+    {
+
+        List<XMPSchema> schemas = metadata.getAllSchemas();
+        if (schemas.size() == 0)
+        {
+            throw new ValidationException("Schemas not found in the given metadata representation");
+        }
+        String about = schemas.get(0).getAboutValue();
+        // rdf:description must have an rdf:about attribute
+        for (XMPSchema xmpSchema : schemas)
+        {
+            checkRdfAbout(about, xmpSchema);
+        }
 
-  }
+    }
 
-  private void checkRdfAbout(String about, XMPSchema xmpSchema)
-      throws DifferentRDFAboutException {
-    if (!about.equals(xmpSchema.getAboutValue())) {
-      throw new DifferentRDFAboutException();
+    private void checkRdfAbout(String about, XMPSchema xmpSchema) throws DifferentRDFAboutException
+    {
+        if (!about.equals(xmpSchema.getAboutValue()))
+        {
+            throw new DifferentRDFAboutException();
+        }
     }
-  }
 
-  public static class DifferentRDFAboutException extends Exception {
+    public static class DifferentRDFAboutException extends Exception
+    {
 
-    private static final long serialVersionUID = 1L;
+        private static final long serialVersionUID = 1L;
 
-    public DifferentRDFAboutException() {
-      super("all rdf:about in RDF:rdf must have the same value");
+        public DifferentRDFAboutException()
+        {
+            super("all rdf:about in RDF:rdf must have the same value");
+        }
     }
-  }
 }

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/SynchronizedMetaDataValidation.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/SynchronizedMetaDataValidation.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/SynchronizedMetaDataValidation.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/SynchronizedMetaDataValidation.java Wed Mar  6 16:46:35 2013
@@ -27,7 +27,6 @@ import java.util.Calendar;
 import java.util.Iterator;
 import java.util.List;
 
-
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDDocumentInformation;
 import org.apache.pdfbox.preflight.PreflightConstants;
@@ -42,492 +41,551 @@ import org.apache.xmpbox.type.AbstractFi
 import org.apache.xmpbox.type.TextType;
 
 /**
- * Class which check if document information available in a document are
- * synchronized with XMP
+ * Class which check if document information available in a document are synchronized with XMP
  * 
  * @author Germain Costenobel
  * 
  */
-public class SynchronizedMetaDataValidation {
+public class SynchronizedMetaDataValidation
+{
+
+    /**
+     * Analyze if Title embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param dc
+     *            Dublin Core Schema
+     * @param ve
+     *            The list of validation errors
+     */
+    protected void analyzeTitleProperty(PDDocumentInformation dico, DublinCoreSchema dc, List<ValidationError> ve)
+    {
+        String title = dico.getTitle();
+        if (title != null)
+        {
+            if (dc != null)
+            {
+                // Check the x-default value, if not found, check with the first value
+                // found
+                if (dc.getTitle() != null)
+                {
+                    if (dc.getTitle("x-default") != null)
+                    {
+                        if (!dc.getTitle("x-default").equals(title))
+                        {
+                            ve.add(unsynchronizedMetaDataError("Title"));
+                        }
+                    }
+                    else
+                    {
+                        // This search of first value is made just to keep compatibility
+                        // with lot of PDF documents
+                        // which use title without lang definition
+                        // REM : MAY we have to delete this option in the future
+                        Iterator<AbstractField> it = dc.getTitleProperty().getContainer().getAllProperties().iterator();
+                        if (it.hasNext())
+                        {
+                            AbstractField tmp = it.next();
+                            if (tmp instanceof TextType)
+                            {
+                                if (!((TextType) tmp).getStringValue().equals(title))
+                                {
+                                    ve.add(unsynchronizedMetaDataError("Title"));
+                                }
+                            }
+                            else
+                            {
+                                ve.add(AbsentXMPPropertyError("Title", "Property is badly defined"));
+                            }
+                        }
+                        else
+                        {
+                            ve.add(AbsentXMPPropertyError("Title", "Property is not defined"));
+                        }
+                    }
+
+                }
+                else
+                {
+                    ve.add(AbsentXMPPropertyError("Title", "Property is not defined"));
+                }
+            }
+            else
+            {
+                ve.add(AbsentSchemaMetaDataError("Title", "Dublin Core"));
+            }
+        }
+    }
+
+    /**
+     * Analyze if Author(s) embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param dc
+     *            Dublin Core Schema
+     * @param ve
+     *            The list of validation errors
+     */
+    protected void analyzeAuthorProperty(PDDocumentInformation dico, DublinCoreSchema dc, List<ValidationError> ve)
+    {
+        String author = dico.getAuthor();
+        if (author != null)
+        {
+            if (dc != null)
+            {
+                if (dc.getCreatorsProperty() != null)
+                {
+                    if (dc.getCreators().size() != 1)
+                    {
+                        ve.add(AbsentXMPPropertyError("Author",
+                                "In XMP metadata, Author(s) must be represented by a single entry in a text array (dc:creator) "));
+                    }
+                    else
+                    {
+                        if (dc.getCreators().get(0) == null)
+                        {
+                            ve.add(AbsentXMPPropertyError("Author", "Property is defined as null"));
+                        }
+                        else
+                        {
+                            if (!dc.getCreators().get(0).equals(author))
+                            {
+                                ve.add(unsynchronizedMetaDataError("Author"));
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    ve.add(AbsentXMPPropertyError("Author", "Property is not defined in XMP Metadata"));
+                }
+            }
+            else
+            {
+                ve.add(AbsentSchemaMetaDataError("Author", "Dublin Core"));
+            }
+        }
+    }
+
+    /**
+     * Analyze if Subject(s) embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param dc
+     *            Dublin Core Schema
+     * @param ve
+     *            The list of validation errors
+     */
+    protected void analyzeSubjectProperty(PDDocumentInformation dico, DublinCoreSchema dc, List<ValidationError> ve)
+    {
+        String subject = dico.getSubject();
+        if (subject != null)
+        {
+            if (dc != null)
+            {
+                // PDF/A Conformance Erratum (2007) specifies XMP Subject
+                // as a Text type embedded in the dc:description["x-default"].
+                if (dc.getDescriptionProperty() != null)
+                {
+                    if (dc.getDescription("x-default") == null)
+                    {
+                        ve.add(AbsentXMPPropertyError("Subject",
+                                "Subject not found in XMP (dc:description[\"x-default\"] not found)"));
+                    }
+                    else
+                    {
+                        if (!dc.getDescription("x-default").equals(subject))
+                        {
+                            ve.add(unsynchronizedMetaDataError("Subject"));
+
+                        }
+                    }
+                }
+                else
+                {
+                    ve.add(AbsentXMPPropertyError("Subject", "Property is defined as null"));
+                }
+            }
+            else
+            {
+                ve.add(AbsentSchemaMetaDataError("Subject", "Dublin Core"));
+            }
+        }
+    }
+
+    /**
+     * Analyze if Keyword(s) embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param pdf
+     *            PDF Schema
+     * @param ve
+     *            The list of validation errors
+     */
+    protected void analyzeKeywordsProperty(PDDocumentInformation dico, AdobePDFSchema pdf, List<ValidationError> ve)
+    {
+        String keyword = dico.getKeywords();
+        if (keyword != null)
+        {
+            if (pdf != null)
+            {
+                if (pdf.getKeywordsProperty() == null)
+                {
+                    ve.add(AbsentXMPPropertyError("Keywords", "Property is not defined"));
+                }
+                else
+                {
+                    if (!pdf.getKeywords().equals(keyword))
+                    {
+                        ve.add(unsynchronizedMetaDataError("Keywords"));
+                    }
+                }
+            }
+            else
+            {
+                ve.add(AbsentSchemaMetaDataError("Keywords", "PDF"));
+            }
+        }
+    }
+
+    /**
+     * Analyze if Producer embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param pdf
+     *            PDF Schema
+     * @param ve
+     *            The list of validation errors
+     */
+    protected void analyzeProducerProperty(PDDocumentInformation dico, AdobePDFSchema pdf, List<ValidationError> ve)
+    {
+        String producer = dico.getProducer();
+        if (producer != null)
+        {
+            if (pdf != null)
+            {
+                if (pdf.getProducerProperty() == null)
+                {
+                    ve.add(AbsentXMPPropertyError("Producer", "Property is not defined"));
+                }
+                else
+                {
+                    if (!pdf.getProducer().equals(producer))
+                    {
+                        ve.add(unsynchronizedMetaDataError("Producer"));
+                    }
+                }
+            }
+            else
+            {
+                ve.add(AbsentSchemaMetaDataError("Producer", "PDF"));
+            }
+        }
+
+    }
+
+    /**
+     * Analyze if the creator tool embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param xmp
+     *            XMP Basic Schema
+     * @param ve
+     *            The list of validation errors
+     * 
+     */
+    protected void analyzeCreatorToolProperty(PDDocumentInformation dico, XMPBasicSchema xmp, List<ValidationError> ve)
+    {
+        String creatorTool = dico.getCreator();
+        if (creatorTool != null)
+        {
+            if (xmp != null)
+            {
+                if (xmp.getCreatorToolProperty() == null)
+                {
+                    ve.add(AbsentXMPPropertyError("CreatorTool", "Property is not defined"));
+                }
+                else
+                {
+                    if (!xmp.getCreatorTool().equals(creatorTool))
+                    {
+                        ve.add(unsynchronizedMetaDataError("CreatorTool"));
+                    }
+                }
+            }
+            else
+            {
+                ve.add(AbsentSchemaMetaDataError("CreatorTool", "PDF"));
+            }
+        }
 
-  /**
-   * Analyze if Title embedded in Document Information dictionary and in XMP
-   * properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param dc
-   *          Dublin Core Schema
-   * @param ve
-   *          The list of validation errors
-   */
-  protected void analyzeTitleProperty(PDDocumentInformation dico,
-      DublinCoreSchema dc, List<ValidationError> ve) {
-    String title = dico.getTitle();
-    if (title != null) {
-      if (dc != null) {
-        // Check the x-default value, if not found, check with the first value
-        // found
-        if (dc.getTitle() != null) {
-          if (dc.getTitle("x-default") != null) {
-            if (!dc.getTitle("x-default").equals(title)) {
-              ve.add(unsynchronizedMetaDataError("Title"));
-            }
-          } else {
-            // This search of first value is made just to keep compatibility
-            // with lot of PDF documents
-            // which use title without lang definition
-            // REM : MAY we have to delete this option in the future
-            Iterator<AbstractField> it = dc.getTitleProperty().getContainer()
-                .getAllProperties().iterator();
-            if (it.hasNext()) {
-              AbstractField tmp = it.next();
-              if (tmp instanceof TextType) {
-                if (!((TextType) tmp).getStringValue().equals(title)) {
-                  ve.add(unsynchronizedMetaDataError("Title"));
-                }
-              } else {
-                ve.add(AbsentXMPPropertyError("Title",
-                    "Property is badly defined"));
-              }
-            } else {
-              ve
-                  .add(AbsentXMPPropertyError("Title",
-                      "Property is not defined"));
-            }
-          }
-
-        } else {
-          ve.add(AbsentXMPPropertyError("Title", "Property is not defined"));
-        }
-      } else {
-        ve.add(AbsentSchemaMetaDataError("Title", "Dublin Core"));
-      }
-    }
-  }
-
-  /**
-   * Analyze if Author(s) embedded in Document Information dictionary and in XMP
-   * properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param dc
-   *          Dublin Core Schema
-   * @param ve
-   *          The list of validation errors
-   */
-  protected void analyzeAuthorProperty(PDDocumentInformation dico,
-      DublinCoreSchema dc, List<ValidationError> ve) {
-    String author = dico.getAuthor();
-    if (author != null) {
-      if (dc != null) {
-        if (dc.getCreatorsProperty() != null) {
-          if (dc.getCreators().size() != 1) {
-            ve
-                .add(AbsentXMPPropertyError(
-                    "Author",
-                    "In XMP metadata, Author(s) must be represented by a single entry in a text array (dc:creator) "));
-          } else {
-            if (dc.getCreators().get(0) == null) {
-              ve.add(AbsentXMPPropertyError("Author",
-                  "Property is defined as null"));
-            } else {
-              if (!dc.getCreators().get(0).equals(author)) {
-                ve.add(unsynchronizedMetaDataError("Author"));
-              }
-            }
-          }
-        } else {
-          ve.add(AbsentXMPPropertyError("Author",
-              "Property is not defined in XMP Metadata"));
-        }
-      } else {
-        ve.add(AbsentSchemaMetaDataError("Author", "Dublin Core"));
-      }
-    }
-  }
-
-  /**
-   * Analyze if Subject(s) embedded in Document Information dictionary and in
-   * XMP properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param dc
-   *          Dublin Core Schema
-   * @param ve
-   *          The list of validation errors
-   */
-  protected void analyzeSubjectProperty(PDDocumentInformation dico,
-      DublinCoreSchema dc, List<ValidationError> ve) {
-    String subject = dico.getSubject();
-    if (subject != null) {
-      if (dc != null) {
-        // PDF/A Conformance Erratum (2007) specifies XMP Subject
-        // as a Text type embedded in the dc:description["x-default"].
-        if (dc.getDescriptionProperty() != null) {
-          if (dc.getDescription("x-default") == null) {
-            ve
-                .add(AbsentXMPPropertyError("Subject",
-                    "Subject not found in XMP (dc:description[\"x-default\"] not found)"));
-          } else {
-            if (!dc.getDescription("x-default").equals(subject)) {
-              ve.add(unsynchronizedMetaDataError("Subject"));
-
-            }
-          }
-        } else {
-          ve.add(AbsentXMPPropertyError("Subject",
-              "Property is defined as null"));
-        }
-      } else {
-        ve.add(AbsentSchemaMetaDataError("Subject", "Dublin Core"));
-      }
-    }
-  }
-
-  /**
-   * Analyze if Keyword(s) embedded in Document Information dictionary and in
-   * XMP properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param pdf
-   *          PDF Schema
-   * @param ve
-   *          The list of validation errors
-   */
-  protected void analyzeKeywordsProperty(PDDocumentInformation dico,
-      AdobePDFSchema pdf, List<ValidationError> ve) {
-    String keyword = dico.getKeywords();
-    if (keyword != null) {
-      if (pdf != null) {
-        if (pdf.getKeywordsProperty() == null) {
-          ve.add(AbsentXMPPropertyError("Keywords", "Property is not defined"));
-        } else {
-          if (!pdf.getKeywords().equals(keyword)) {
-            ve.add(unsynchronizedMetaDataError("Keywords"));
-          }
-        }
-      } else {
-        ve.add(AbsentSchemaMetaDataError("Keywords", "PDF"));
-      }
-    }
-  }
-
-  /**
-   * Analyze if Producer embedded in Document Information dictionary and in XMP
-   * properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param pdf
-   *          PDF Schema
-   * @param ve
-   *          The list of validation errors
-   */
-  protected void analyzeProducerProperty(PDDocumentInformation dico,
-      AdobePDFSchema pdf, List<ValidationError> ve) {
-    String producer = dico.getProducer();
-    if (producer != null) {
-      if (pdf != null) {
-        if (pdf.getProducerProperty() == null) {
-          ve.add(AbsentXMPPropertyError("Producer", "Property is not defined"));
-        } else {
-          if (!pdf.getProducer().equals(producer)) {
-            ve.add(unsynchronizedMetaDataError("Producer"));
-          }
-        }
-      } else {
-        ve.add(AbsentSchemaMetaDataError("Producer", "PDF"));
-      }
-    }
-
-  }
-
-  /**
-   * Analyze if the creator tool embedded in Document Information dictionary and
-   * in XMP properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param xmp
-   *          XMP Basic Schema
-   * @param ve
-   *          The list of validation errors
-   * 
-   */
-  protected void analyzeCreatorToolProperty(PDDocumentInformation dico,
-      XMPBasicSchema xmp, List<ValidationError> ve) {
-    String creatorTool = dico.getCreator();
-    if (creatorTool != null) {
-      if (xmp != null) {
-        if (xmp.getCreatorToolProperty() == null) {
-          ve.add(AbsentXMPPropertyError("CreatorTool",
-              "Property is not defined"));
-        } else {
-          if (!xmp.getCreatorTool().equals(creatorTool)) {
-            ve.add(unsynchronizedMetaDataError("CreatorTool"));
-          }
-        }
-      } else {
-        ve.add(AbsentSchemaMetaDataError("CreatorTool", "PDF"));
-      }
-    }
-
-  }
-
-  /**
-   * Analyze if the CreationDate embedded in Document Information dictionary and
-   * in XMP properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param xmp
-   *          XMP Basic Schema
-   * @param ve
-   *          The list of validation errors
-   * @throws ValidationException
-   */
-  protected void analyzeCreationDateProperty(PDDocumentInformation dico,
-      XMPBasicSchema xmp, List<ValidationError> ve) throws ValidationException {
-    Calendar creationDate;
-    try {
-      creationDate = dico.getCreationDate();
-    } catch (IOException e) {
-      // If there is an error while converting this property to a date
-      throw formatAccessException("Document Information", "CreationDate", e);
-    }
-    if (creationDate != null) {
-      if (xmp != null) {
-        Calendar xmpCreationDate = xmp.getCreateDate();
-
-        if (xmpCreationDate == null) {
-          ve.add(AbsentXMPPropertyError("CreationDate",
-              "Property is not defined"));
-        } else {
-          if (!DateConverter.toISO8601(xmpCreationDate).equals(
-              DateConverter.toISO8601(creationDate))) {
-            ve.add(unsynchronizedMetaDataError("CreationDate"));
-          }
-        }
-
-      } else {
-        ve.add(AbsentSchemaMetaDataError("CreationDate", "Basic XMP"));
-      }
-    }
-  }
-
-  /**
-   * Analyze if the ModifyDate embedded in Document Information dictionary and
-   * in XMP properties are synchronized
-   * 
-   * @param dico
-   *          Document Information Dictionary
-   * @param xmp
-   *          XMP Basic Schema
-   * @param ve
-   *          The list of validation errors
-   * @throws ValidationException
-   */
-  protected void analyzeModifyDateProperty(PDDocumentInformation dico,
-      XMPBasicSchema xmp, List<ValidationError> ve) throws ValidationException {
-    Calendar modifyDate;
-    try {
-      modifyDate = dico.getModificationDate();
-      if (modifyDate != null) {
-        if (xmp != null) {
-
-          Calendar xmpModifyDate = xmp.getModifyDate();
-          if (xmpModifyDate == null) {
-            ve.add(AbsentXMPPropertyError("ModifyDate",
-                "Property is not defined"));
-          } else {
-            if (!DateConverter.toISO8601(xmpModifyDate).equals(
-                DateConverter.toISO8601(modifyDate))) {
-
-              ve.add(unsynchronizedMetaDataError("ModificationDate"));
-            }
-          }
-
-        } else {
-          ve.add(AbsentSchemaMetaDataError("ModifyDate", "Basic XMP"));
-        }
-      }
-    } catch (IOException e) {
-      // If there is an error while converting this property to a date
-      throw formatAccessException("Document Information", "ModifyDate", e);
-    }
-
-  }
-
-  /**
-   * Check if document information entries and XMP information are synchronized
-   * 
-   * @param document
-   *          the PDF Document
-   * @param metadata
-   *          the XMP MetaData
-   * @return List of validation errors
-   * @throws ValidationException
-   */
-  public List<ValidationError> validateMetadataSynchronization(PDDocument document, XMPMetadata metadata) 
-  throws ValidationException {
-    List<ValidationError> ve = new ArrayList<ValidationError>();
-
-    if (document == null) {
-      throw new ValidationException("Document provided is null");
-    } else {
-      PDDocumentInformation dico = document.getDocumentInformation();
-      if (metadata == null) {
-        throw new ValidationException("Metadata provided are null");
-      } else {
-        DublinCoreSchema dc = metadata.getDublinCoreSchema();
-
-        // TITLE
-        analyzeTitleProperty(dico, dc, ve);
-        // AUTHOR
-        analyzeAuthorProperty(dico, dc, ve);
-        // SUBJECT
-        analyzeSubjectProperty(dico, dc, ve);
-
-        AdobePDFSchema pdf = metadata.getAdobePDFSchema();
-
-        // KEYWORDS
-        analyzeKeywordsProperty(dico, pdf, ve);
-        // PRODUCER
-        analyzeProducerProperty(dico, pdf, ve);
-
-        XMPBasicSchema xmp = metadata.getXMPBasicSchema();
-
-        // CREATOR TOOL
-        analyzeCreatorToolProperty(dico, xmp, ve);
-
-        // CREATION DATE
-        analyzeCreationDateProperty(dico, xmp, ve);
-
-        // MODIFY DATE
-        analyzeModifyDateProperty(dico, xmp, ve);
-
-      }
-
-    }
-    return ve;
-  }
-
-  /**
-   * Return a validationError formatted when a schema has not the expected
-   * prefix
-   * 
-   * @param prefFound
-   * @param prefExpected
-   * @param schema
-   * @return
-   */
-  protected ValidationError unexpectedPrefixFoundError(String prefFound,
-      String prefExpected, String schema) {
-    StringBuilder sb = new StringBuilder(80);
-    sb.append(schema).append(" found but prefix used is '").append(prefFound)
-        .append("', prefix '").append(prefExpected).append("' is expected.");
-
-    return new ValidationError(
-        PreflightConstants.ERROR_METADATA_WRONG_NS_PREFIX, sb.toString());
-  }
-
-  /**
-   * Return an exception formatted on IOException when accessing metadata
-   * 
-   * @param type
-   *          type of property (Document Info or XMP)
-   * @param target
-   *          the name of the metadata
-   * @param cause
-   *          the raised IOException
-   * @return the generated exception
-   */
-  protected ValidationException formatAccessException(String type,
-      String target, Throwable cause) {
-    StringBuilder sb = new StringBuilder(80);
-    sb.append("Cannot treat ").append(type).append(" ").append(target).append(
-        " property");
-    return new ValidationException(sb.toString(), cause);
-  }
-
-  /**
-   * Return an exception formatted on IOException when accessing on metadata
-   * schema
-   * 
-   * @param target
-   *          the name of the schema
-   * @param cause
-   *          the raised IOException
-   * @return the generated exception
-   */
-  protected ValidationException SchemaAccessException(String target,
-      Throwable cause) {
-    StringBuilder sb = new StringBuilder(80);
-    sb.append("Cannot access to the ").append(target).append(" schema");
-    return new ValidationException(sb.toString(), cause);
-  }
-
-  /**
-   * Return a formatted validation error when metadata are not synchronized
-   * 
-   * @param target
-   *          the concerned property
-   * @return the generated validation error
-   */
-  protected ValidationError unsynchronizedMetaDataError(String target) {
-    StringBuilder sb = new StringBuilder(80);
-    sb
-        .append(target)
-        .append(
-            " present in the document catalog dictionary doesn't match with XMP information");
-    return new ValidationError(PreflightConstants.ERROR_METADATA_MISMATCH, sb
-        .toString());
-  }
-
-  /**
-   * Return a formatted validation error when a specific metadata schema can't
-   * be found
-   * 
-   * @param target
-   *          the concerned property
-   * @param schema
-   *          the XMP schema which can't be found
-   * @return the generated validation error
-   */
-  protected ValidationError AbsentSchemaMetaDataError(String target,
-      String schema) {
-    StringBuilder sb = new StringBuilder(80);
-    sb
-        .append(target)
-        .append(
-            " present in the document catalog dictionary can't be found in XMP information (")
-        .append(schema).append(" schema not declared)");
-    return new ValidationError(PreflightConstants.ERROR_METADATA_MISMATCH, sb
-        .toString());
-  }
-
-  /**
-   * Return a formatted validation error when a specific XMP property can't be
-   * found
-   * 
-   * @param target
-   *          the concerned property
-   * @param details
-   *          comments about the XMP property
-   * @return the generated validation error
-   */
-  protected ValidationError AbsentXMPPropertyError(String target, String details) {
-    StringBuilder sb = new StringBuilder(80);
-    sb
-        .append(target)
-        .append(
-            " present in the document catalog dictionary can't be found in XMP information (")
-        .append(details).append(")");
-    return new ValidationError(PreflightConstants.ERROR_METADATA_MISMATCH, sb
-        .toString());
-  }
+    }
+
+    /**
+     * Analyze if the CreationDate embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param xmp
+     *            XMP Basic Schema
+     * @param ve
+     *            The list of validation errors
+     * @throws ValidationException
+     */
+    protected void analyzeCreationDateProperty(PDDocumentInformation dico, XMPBasicSchema xmp, List<ValidationError> ve)
+            throws ValidationException
+    {
+        Calendar creationDate;
+        try
+        {
+            creationDate = dico.getCreationDate();
+        }
+        catch (IOException e)
+        {
+            // If there is an error while converting this property to a date
+            throw formatAccessException("Document Information", "CreationDate", e);
+        }
+        if (creationDate != null)
+        {
+            if (xmp != null)
+            {
+                Calendar xmpCreationDate = xmp.getCreateDate();
+
+                if (xmpCreationDate == null)
+                {
+                    ve.add(AbsentXMPPropertyError("CreationDate", "Property is not defined"));
+                }
+                else
+                {
+                    if (!DateConverter.toISO8601(xmpCreationDate).equals(DateConverter.toISO8601(creationDate)))
+                    {
+                        ve.add(unsynchronizedMetaDataError("CreationDate"));
+                    }
+                }
+
+            }
+            else
+            {
+                ve.add(AbsentSchemaMetaDataError("CreationDate", "Basic XMP"));
+            }
+        }
+    }
+
+    /**
+     * Analyze if the ModifyDate embedded in Document Information dictionary and in XMP properties are synchronized
+     * 
+     * @param dico
+     *            Document Information Dictionary
+     * @param xmp
+     *            XMP Basic Schema
+     * @param ve
+     *            The list of validation errors
+     * @throws ValidationException
+     */
+    protected void analyzeModifyDateProperty(PDDocumentInformation dico, XMPBasicSchema xmp, List<ValidationError> ve)
+            throws ValidationException
+    {
+        Calendar modifyDate;
+        try
+        {
+            modifyDate = dico.getModificationDate();
+            if (modifyDate != null)
+            {
+                if (xmp != null)
+                {
+
+                    Calendar xmpModifyDate = xmp.getModifyDate();
+                    if (xmpModifyDate == null)
+                    {
+                        ve.add(AbsentXMPPropertyError("ModifyDate", "Property is not defined"));
+                    }
+                    else
+                    {
+                        if (!DateConverter.toISO8601(xmpModifyDate).equals(DateConverter.toISO8601(modifyDate)))
+                        {
+
+                            ve.add(unsynchronizedMetaDataError("ModificationDate"));
+                        }
+                    }
+
+                }
+                else
+                {
+                    ve.add(AbsentSchemaMetaDataError("ModifyDate", "Basic XMP"));
+                }
+            }
+        }
+        catch (IOException e)
+        {
+            // If there is an error while converting this property to a date
+            throw formatAccessException("Document Information", "ModifyDate", e);
+        }
+
+    }
+
+    /**
+     * Check if document information entries and XMP information are synchronized
+     * 
+     * @param document
+     *            the PDF Document
+     * @param metadata
+     *            the XMP MetaData
+     * @return List of validation errors
+     * @throws ValidationException
+     */
+    public List<ValidationError> validateMetadataSynchronization(PDDocument document, XMPMetadata metadata)
+            throws ValidationException
+    {
+        List<ValidationError> ve = new ArrayList<ValidationError>();
+
+        if (document == null)
+        {
+            throw new ValidationException("Document provided is null");
+        }
+        else
+        {
+            PDDocumentInformation dico = document.getDocumentInformation();
+            if (metadata == null)
+            {
+                throw new ValidationException("Metadata provided are null");
+            }
+            else
+            {
+                DublinCoreSchema dc = metadata.getDublinCoreSchema();
+
+                // TITLE
+                analyzeTitleProperty(dico, dc, ve);
+                // AUTHOR
+                analyzeAuthorProperty(dico, dc, ve);
+                // SUBJECT
+                analyzeSubjectProperty(dico, dc, ve);
+
+                AdobePDFSchema pdf = metadata.getAdobePDFSchema();
+
+                // KEYWORDS
+                analyzeKeywordsProperty(dico, pdf, ve);
+                // PRODUCER
+                analyzeProducerProperty(dico, pdf, ve);
+
+                XMPBasicSchema xmp = metadata.getXMPBasicSchema();
+
+                // CREATOR TOOL
+                analyzeCreatorToolProperty(dico, xmp, ve);
+
+                // CREATION DATE
+                analyzeCreationDateProperty(dico, xmp, ve);
+
+                // MODIFY DATE
+                analyzeModifyDateProperty(dico, xmp, ve);
+
+            }
+
+        }
+        return ve;
+    }
+
+    /**
+     * Return a validationError formatted when a schema has not the expected prefix
+     * 
+     * @param prefFound
+     * @param prefExpected
+     * @param schema
+     * @return
+     */
+    protected ValidationError unexpectedPrefixFoundError(String prefFound, String prefExpected, String schema)
+    {
+        StringBuilder sb = new StringBuilder(80);
+        sb.append(schema).append(" found but prefix used is '").append(prefFound).append("', prefix '")
+                .append(prefExpected).append("' is expected.");
+
+        return new ValidationError(PreflightConstants.ERROR_METADATA_WRONG_NS_PREFIX, sb.toString());
+    }
+
+    /**
+     * Return an exception formatted on IOException when accessing metadata
+     * 
+     * @param type
+     *            type of property (Document Info or XMP)
+     * @param target
+     *            the name of the metadata
+     * @param cause
+     *            the raised IOException
+     * @return the generated exception
+     */
+    protected ValidationException formatAccessException(String type, String target, Throwable cause)
+    {
+        StringBuilder sb = new StringBuilder(80);
+        sb.append("Cannot treat ").append(type).append(" ").append(target).append(" property");
+        return new ValidationException(sb.toString(), cause);
+    }
+
+    /**
+     * Return an exception formatted on IOException when accessing on metadata schema
+     * 
+     * @param target
+     *            the name of the schema
+     * @param cause
+     *            the raised IOException
+     * @return the generated exception
+     */
+    protected ValidationException SchemaAccessException(String target, Throwable cause)
+    {
+        StringBuilder sb = new StringBuilder(80);
+        sb.append("Cannot access to the ").append(target).append(" schema");
+        return new ValidationException(sb.toString(), cause);
+    }
+
+    /**
+     * Return a formatted validation error when metadata are not synchronized
+     * 
+     * @param target
+     *            the concerned property
+     * @return the generated validation error
+     */
+    protected ValidationError unsynchronizedMetaDataError(String target)
+    {
+        StringBuilder sb = new StringBuilder(80);
+        sb.append(target).append(" present in the document catalog dictionary doesn't match with XMP information");
+        return new ValidationError(PreflightConstants.ERROR_METADATA_MISMATCH, sb.toString());
+    }
+
+    /**
+     * Return a formatted validation error when a specific metadata schema can't be found
+     * 
+     * @param target
+     *            the concerned property
+     * @param schema
+     *            the XMP schema which can't be found
+     * @return the generated validation error
+     */
+    protected ValidationError AbsentSchemaMetaDataError(String target, String schema)
+    {
+        StringBuilder sb = new StringBuilder(80);
+        sb.append(target).append(" present in the document catalog dictionary can't be found in XMP information (")
+                .append(schema).append(" schema not declared)");
+        return new ValidationError(PreflightConstants.ERROR_METADATA_MISMATCH, sb.toString());
+    }
+
+    /**
+     * Return a formatted validation error when a specific XMP property can't be found
+     * 
+     * @param target
+     *            the concerned property
+     * @param details
+     *            comments about the XMP property
+     * @return the generated validation error
+     */
+    protected ValidationError AbsentXMPPropertyError(String target, String details)
+    {
+        StringBuilder sb = new StringBuilder(80);
+        sb.append(target).append(" present in the document catalog dictionary can't be found in XMP information (")
+                .append(details).append(")");
+        return new ValidationError(PreflightConstants.ERROR_METADATA_MISMATCH, sb.toString());
+    }
 }

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/XpacketParsingException.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/XpacketParsingException.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/XpacketParsingException.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/XpacketParsingException.java Wed Mar  6 16:46:35 2013
@@ -27,44 +27,49 @@ import org.apache.pdfbox.preflight.Valid
  * This exception is raised when the parsing of the xpacket fails
  * 
  */
-public class XpacketParsingException extends Exception {
+public class XpacketParsingException extends Exception
+{
 
-  /**
-	 * 
-	 */
-  private static final long serialVersionUID = 1L;
-
-  protected ValidationError error;
-
-  /**
-   * Constructor
-   * 
-   * @param message
-   *          the message
-   * @param cause
-   *          the cause
-   */
-  public XpacketParsingException(String message, Throwable cause) {
-    super(message, cause);
-  }
-
-  /**
-   * Constructor
-   * 
-   * @param message
-   *          the message
-   */
-  public XpacketParsingException(String message) {
-    super(message);
-  }
-
-  public XpacketParsingException(String message, ValidationError error) {
-    super(message);
-    this.error = error;
-  }
-
-  public ValidationError getError() {
-    return error;
-  }
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+
+    protected ValidationError error;
+
+    /**
+     * Constructor
+     * 
+     * @param message
+     *            the message
+     * @param cause
+     *            the cause
+     */
+    public XpacketParsingException(String message, Throwable cause)
+    {
+        super(message, cause);
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param message
+     *            the message
+     */
+    public XpacketParsingException(String message)
+    {
+        super(message);
+    }
+
+    public XpacketParsingException(String message, ValidationError error)
+    {
+        super(message);
+        this.error = error;
+    }
+
+    public ValidationError getError()
+    {
+        return error;
+    }
 
 }