Fix plugin report information

https://issues.apache.org/jira/browse/EASYANT-77
diff --git a/src/main/java/org/apache/easyant/core/report/XMLEasyAntReportWriter.java b/src/main/java/org/apache/easyant/core/report/XMLEasyAntReportWriter.java
index 9f2c910..347f57f 100644
--- a/src/main/java/org/apache/easyant/core/report/XMLEasyAntReportWriter.java
+++ b/src/main/java/org/apache/easyant/core/report/XMLEasyAntReportWriter.java
@@ -84,7 +84,13 @@
         out.println("\t<configurations>");
 
         for (Configuration configuration : easyAntReport.getModuleDescriptor().getConfigurations()) {
-            out.println("\t\t<configuration name=\"" + XMLHelper.escape(configuration.getName()) + "\" description=\"" + XMLHelper.escape(configuration.getDescription()) + "\" extends=\"" + XMLHelper.escape(Arrays.toString(configuration.getExtends())) + "\" deprecated=\"" + XMLHelper.escape(configuration.getDeprecated()) + "\" visibility=\"" + XMLHelper.escape(configuration.getVisibility().toString()) + "\"/>");
+            // deprecated file can be null (see Javadoc)
+            String deprecated = XMLHelper.escape(configuration.getDeprecated());
+            if (deprecated == null) {
+                // Avoid to display null in the report
+                deprecated = "";
+            }
+            out.println("\t\t<configuration name=\"" + XMLHelper.escape(configuration.getName()) + "\" description=\"" + XMLHelper.escape(configuration.getDescription()) + "\" extends=\"" + XMLHelper.escape(Arrays.toString(configuration.getExtends())) + "\" deprecated=\"" + deprecated + "\" visibility=\"" + XMLHelper.escape(configuration.getVisibility().toString()) + "\"/>");
         }
         out.println("\t</configurations>");
 
@@ -378,11 +384,9 @@
                     param.append(paramReport.getDescription());
                     param.append("\"");
                 }
-                if (paramReport.isRequired()) {
-                    param.append(" required=\"");
-                    param.append(paramReport.isRequired());
-                    param.append("\"");
-                }
+                param.append(" required=\"");
+                param.append(paramReport.isRequired());
+                param.append("\"");
                 param.append("/>");
             }
             out.println(param);
diff --git a/src/main/java/org/apache/easyant/core/services/DefaultPluginService.java b/src/main/java/org/apache/easyant/core/services/DefaultPluginService.java
index 698986f..ac10efb 100644
--- a/src/main/java/org/apache/easyant/core/services/DefaultPluginService.java
+++ b/src/main/java/org/apache/easyant/core/services/DefaultPluginService.java
@@ -407,7 +407,9 @@
         if (parameterTask.getProperty() != null) {
             PropertyDescriptor propertyDescriptor = new PropertyDescriptor(parameterTask.getProperty());
             propertyDescriptor.setDefaultValue(parameterTask.getDefault());
-            propertyDescriptor.setRequired(parameterTask.isRequired());
+            // Use unsafe version since we are in audit mode and we want the real value of the required field 
+            // (#isRequired method will always return false in audit mode)
+            propertyDescriptor.setRequired(parameterTask.isRequiredUnsafe());
             propertyDescriptor.setDescription(parameterTask.getDescription());
             if (parameterTask.getOwningTarget() != null) {
                 propertyDescriptor.setOwningTarget(parameterTask.getOwningTarget().getName());
@@ -417,7 +419,9 @@
         } else if (parameterTask.getPath() != null) {
             ParameterReport parameterReport = new ParameterReport(ParameterType.PATH);
             parameterReport.setName(parameterTask.getPath());
-            parameterReport.setRequired(parameterTask.isRequired());
+            // Use unsafe version since we are in audit mode and we want the real value of the required field 
+            // (#isRequired method will always return false in audit mode)
+            parameterReport.setRequired(parameterTask.isRequiredUnsafe());
             parameterReport.setDescription(parameterTask.getDescription());
             if (parameterTask.getOwningTarget() != null) {
                 parameterReport.setOwningTarget(parameterTask.getOwningTarget().getName());
diff --git a/src/main/java/org/apache/easyant/tasks/ParameterTask.java b/src/main/java/org/apache/easyant/tasks/ParameterTask.java
index 7a5dd51..a1de39e 100644
--- a/src/main/java/org/apache/easyant/tasks/ParameterTask.java
+++ b/src/main/java/org/apache/easyant/tasks/ParameterTask.java
@@ -18,6 +18,7 @@
 package org.apache.easyant.tasks;
 
 import org.apache.easyant.core.EasyAntMagicNames;
+import org.apache.easyant.core.services.PluginService;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.Task;
@@ -146,6 +147,21 @@
             return required;
         }
     }
+    
+    /**
+     * Gets if this parameter is required or not.
+     *
+     * <p>
+     * This is the unsafe version of {@link #isRequired()}, this method does not check if project is in audit mode. This
+     * method should not be use in EasyAnt engine, but only to output the required value in {@link PluginService}.
+     * 
+     * @return {@code true} if this parameter is required, {@code false} otherwise.
+     * 
+     * @see EasyAntMagicNames#AUDIT_MODE
+     */
+    public boolean isRequiredUnsafe() {
+        return required;
+    }
 
     /**
      * specify if the property / path is mandatory
diff --git a/src/main/java/org/apache/easyant/tasks/PluginReport.java b/src/main/java/org/apache/easyant/tasks/PluginReport.java
index 1557997..e1f372f 100644
--- a/src/main/java/org/apache/easyant/tasks/PluginReport.java
+++ b/src/main/java/org/apache/easyant/tasks/PluginReport.java
@@ -17,15 +17,22 @@
  */
 package org.apache.easyant.tasks;
 
+import java.awt.image.ImagingOpException;
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOError;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import javax.xml.transform.Source;
@@ -36,6 +43,7 @@
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 
+import org.apache.easyant.core.EasyAntEngine;
 import org.apache.easyant.core.EasyAntMagicNames;
 import org.apache.easyant.core.report.EasyAntReport;
 import org.apache.easyant.core.report.XMLEasyAntReportWriter;
@@ -204,13 +212,54 @@
         // style should be a file (and not an url)
         // so we have to copy it from classpath to cache
         ResolutionCacheManager cacheMgr = getEasyAntIvyInstance().getResolutionCacheManager();
-        File style = new File(cacheMgr.getResolutionCacheRoot(), "easyant-report.xsl");
+        String styleName = "easyant-report.xsl";
+        File style = new File(cacheMgr.getResolutionCacheRoot(), styleName);
         if (!style.exists()) {
             Message.debug("copying easyant-report.xsl to " + style.getAbsolutePath());
-            FileUtil.copy(XMLEasyAntReportWriter.class.getResourceAsStream("easyant-report.xsl"), style, null);
+            FileUtil.copy(XMLEasyAntReportWriter.class.getResourceAsStream(styleName), style, null);
+        } else {
+            // Check cached and jar style content
+            // If EasyAnt has been updated, maybe the style file is different from the one in previous version
+            InputStream cacheIs = new FileInputStream(style);
+            InputStream jarIs = XMLEasyAntReportWriter.class.getResourceAsStream(styleName);
+            if (!isSame(cacheIs, jarIs)) {
+                Message.debug("Update cache style file");
+                style.delete();
+                FileUtil.copy(XMLEasyAntReportWriter.class.getResourceAsStream(styleName), style, null);
+            }
         }
         return style;
     }
+    
+    public boolean isSame(InputStream is1, InputStream is2) throws IOException {
+        byte[] buffer1 = new byte[1024];
+        byte[] buffer2 = new byte[1024];
+
+        try {
+            while (true) {
+                int count1 = is1.read(buffer1);
+                int count2 = is2.read(buffer2);
+
+                if (count1 > -1) {
+                    if (count2 != count1) {
+                        // not same number of byte in files
+                        return false;
+                    }
+
+                    if (!Arrays.equals(buffer1, buffer2)) {
+                        // same byte count, but contents are different
+                        return false;
+                    }
+                } else {
+                    // same content if is1 and is2 have no more byte to read
+                    return count2 == -1;
+                }
+            }
+        } finally {
+            is1.close();
+            is2.close();
+        }
+    }
 
     private String getOutputPattern(ModuleRevisionId moduleRevisionId, String conf, String ext) {
         return IvyPatternHelper.substitute(outputpattern, moduleRevisionId.getOrganisation(),
diff --git a/src/main/resources/org/apache/easyant/core/report/easyant-report.xsl b/src/main/resources/org/apache/easyant/core/report/easyant-report.xsl
index f35c4a9..8677599 100644
--- a/src/main/resources/org/apache/easyant/core/report/easyant-report.xsl
+++ b/src/main/resources/org/apache/easyant/core/report/easyant-report.xsl
@@ -261,25 +261,25 @@
                 </tr>
             </thead>
             <tbody>
-                <xsl-foreach select="configuration">
+                <xsl:for-each select="configuration">
                     <tr>
                         <td>
-                            <xsl:value-of select="configuration/@name" />
+                            <xsl:value-of select="@name" />
                         </td>
                         <td>
-                            <xsl:value-of select="configuration/@description" />
+                            <xsl:value-of select="@description" />
                         </td>
                         <td>
-                            <xsl:value-of select="configuration/@extends" />
+                            <xsl:value-of select="@extends" />
                         </td>
                         <td>
-                            <xsl:value-of select="configuration/@visibility" />
+                            <xsl:value-of select="@visibility" />
                         </td>
                         <td>
-                            <xsl:value-of select="configuration/@deprecated" />
+                            <xsl:value-of select="@deprecated" />
                         </td>
                     </tr>
-                </xsl-foreach>
+                </xsl:for-each>
             </tbody>
         </table>
     </xsl:template>
@@ -696,7 +696,7 @@
             </table>
         </xsl:if>
 
-        <xsl:if test="count(parameters/parameter) > 0">
+        <xsl:if test="count(parameters/path) > 0">
             <h3>Paths</h3>
             <table>
                 <thead>