TRINIDAD-1163 - Improvements to property deprecation and a new no-op feature

Thanks to Gary van Matre for his patch.
diff --git a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/AbstractComponentGenerator.java b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/AbstractComponentGenerator.java
index 9967db3..58de9be 100644
--- a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/AbstractComponentGenerator.java
+++ b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/AbstractComponentGenerator.java
@@ -668,8 +668,20 @@
     {
       out.println(" * @deprecated");
     }
+    
+    if (property.getDeprecated() != null)
+    {
+      out.print(" * @deprecated ");
+      out.println(convertMultilineComment(property.getDeprecated()));      
+    }
+    
     out.println(" */");
 
+    if (property.getDeprecated() != null)
+    {
+      out.println("@Deprecated");
+    }
+ 
     if (isAccessorMethodFinal())
     {
       out.print("final ");
@@ -729,8 +741,20 @@
     {
       out.println(" * @deprecated");
     }
+    
+    if (property.getDeprecated() != null)
+    {
+      out.print(" * @deprecated ");
+      out.println(convertMultilineComment(property.getDeprecated()));
+    }
+    
     out.println(" */");
 
+    if (property.getDeprecated() != null)
+    {
+      out.println("@Deprecated");
+    }
+  
     if (isUnchecked)
     {
       out.println("@SuppressWarnings(\"unchecked\")");
@@ -976,7 +1000,30 @@
   protected String convertMultilineComment(
       String commentBody)
   {
-    return commentBody.replaceAll("\n", "\n * ");
+   StringBuilder buff = new StringBuilder(commentBody.replaceAll("\n", "\n * "));
+   
+   
+   // escape markup within <pre> blocks.  The tag doc gen plugin escapes the ampersand
+   // making it not possible to escape causing issue with javadoc.
+   int s = 0;
+   do {
+     s = buff.indexOf("<pre>", s);
+     if (s > 0)
+     {
+       s = s + "<pre>".length();
+       int e = buff.indexOf("</pre>", s);
+       e = e - "</pre>".length();
+       String markup = buff.substring(s, e);
+       markup = markup.replaceAll("<", "&lt;");
+       markup = markup.replaceAll(">", "&gt;");
+       buff.delete(s, e);
+       buff.insert(s, markup);
+       
+       s = buff.indexOf("<pre>", s + markup.length() + "</pre>".length());
+     }
+   } while (s > 0);
+    
+   return buff.toString(); 
   }
 
   protected class ResolvableTypeFilter extends PropertyFilter
@@ -1030,4 +1077,6 @@
 
   static private final Pattern _GENERIC_TYPE = Pattern.compile("([^<]+)<(.+)>");
   static final private Map _RESOLVABLE_TYPES = _createResolvableTypes();
+  
+  
 }
diff --git a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/TrinidadComponentGenerator.java b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/TrinidadComponentGenerator.java
index 60c597f..a1b9970 100644
--- a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/TrinidadComponentGenerator.java
+++ b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/component/TrinidadComponentGenerator.java
@@ -57,7 +57,13 @@
 
         // ComponentUtils only needed for resolvable properties
         if (resolvable.accept(property))
+        {
           imports.add("org.apache.myfaces.trinidad.util.ComponentUtils");
+        }
+        if (property.isNoOp())
+        {
+          imports.add("org.apache.myfaces.trinidad.logging.TrinidadLogger");
+        }  
       }
     }
   }
@@ -95,6 +101,11 @@
       String propKey = Util.getConstantNameFromProperty(propName, "_KEY");
       String propAlias = property.getAliasOf();
 
+      if (property.getDeprecated() != null)
+      {
+        out.println("@Deprecated");
+      }
+      
       out.println("static public final PropertyKey " + propKey + " =");
       out.indent();
       if (propAlias != null)
@@ -166,15 +177,25 @@
     String propKey = Util.getConstantNameFromProperty(propName, "_KEY");
     String propVar = Util.getVariableFromName(propName);
 
-    if (Util.isPrimitiveClass(propertyClass))
+    if (!property.isNoOp())
     {
-      out.println("setProperty(" + propKey + ", " +
+      if (Util.isPrimitiveClass(propertyClass))
+      {
+        out.println("setProperty(" + propKey + ", " +
                   convertVariableToBoxedForm(propertyClass, propVar) +
                   ");");
+      }
+      else
+      {
+        out.println("setProperty(" + propKey + ", (" + propVar + "));");
+      }
     }
-    else
-    {
-      out.println("setProperty(" + propKey + ", (" + propVar + "));");
+    else 
+    { 
+      out.println("TrinidadLogger log = TrinidadLogger.createTrinidadLogger(this.getClass());");  
+      out.print("log.warning(\"property \\\"" + propName + "\\\" is ");
+      out.print("using a no-op implementation. Used in extreme cases when the property value, beyond the default value, results in unwanted behavior.");
+      out.println("\");");
     }
   }
 
@@ -268,6 +289,10 @@
       out.println(" * Adds a " + convertMultilineComment(description));
     }
     out.println(" */");
+    if (property.getDeprecated() != null)
+    {
+      out.println("@Deprecated");
+    }
     out.println("final public void " + addMethod + "(" + propertyClass + " " +
         propVar + ")");
     out.println("{");
@@ -304,6 +329,10 @@
       out.println(" * Gets all " + convertMultilineComment(description));
     }
     out.println(" */");
+    if (property.getDeprecated() != null)
+    {
+      out.println("@Deprecated");
+    }
     out.println("final public " + propertyClass + "[] " + getMethod + "()");
     out.println("{");
     out.indent();
@@ -396,4 +425,5 @@
     }
     return sb.toString();
   }
+    
 }
diff --git a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/taglib/TrinidadComponentTagGenerator.java b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/taglib/TrinidadComponentTagGenerator.java
index 8d284bd..72e06b7 100644
--- a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/taglib/TrinidadComponentTagGenerator.java
+++ b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/generator/taglib/TrinidadComponentTagGenerator.java
@@ -135,6 +135,11 @@
       {
         imports.add(propertyClass);
       }
+      
+      if (property.isNoOp())
+      {
+        imports.add("org.apache.myfaces.trinidad.logging.TrinidadLogger");
+      }  
     }
   }
 
@@ -147,6 +152,10 @@
     String jspPropType = GeneratorHelper.getJspPropertyType(property, _is12);
 
     out.println();
+    if (property.getDeprecated() != null)
+    {
+      out.println("@Deprecated");
+    }
     out.println("private " + jspPropType + " " + fieldPropName + ";");
   }
 
@@ -160,11 +169,25 @@
     String setMethod = Util.getPrefixedPropertyName("set", jspPropName);
     String jspPropType = GeneratorHelper.getJspPropertyType(property, _is12);
 
+    if (property.getDeprecated() != null)
+    {
+      out.println("@Deprecated");
+    }
     out.print("final ");
     out.println("public void " + setMethod + "(" + jspPropType + " " + propVar + ")");
     out.println("{");
     out.indent();
-    out.println(fieldPropName + " = " + propVar + ";");
+    if (property.isNoOp())
+    {
+      out.println("TrinidadLogger log = TrinidadLogger.createTrinidadLogger(this.getClass());");  
+      out.print("log.warning(\"property \\\"" + propName + "\\\" setter is ");
+      out.print("using a no-op implementation. Used in extreme cases when the property value, beyond the default value, results in unwanted behavior.");
+      out.println("\");");  
+    }
+    else
+    {
+      out.println(fieldPropName + " = " + propVar + ";");
+    }
     out.unindent();
     out.println("}");
   }
diff --git a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/FacesConfigParser.java b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/FacesConfigParser.java
index 5beb387..b9aff09 100644
--- a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/FacesConfigParser.java
+++ b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/FacesConfigParser.java
@@ -249,6 +249,8 @@
     // faces-config/component/property/property-extension/property-metada
     digester.addBeanPropertySetter("faces-config/component/property/property-extension/property-metadata/use-max-time",
                                    "useMaxTime");
+    digester.addBeanPropertySetter("faces-config/component/property/property-extension/property-metadata/deprecated");
+    digester.addCallMethod("faces-config/component/property/property-extension/property-metadata/no-op", "makeNoOp");
 
 
     // XInclude rules
diff --git a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/PropertyBean.java b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/PropertyBean.java
index 60391c9..18fb37d 100644
--- a/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/PropertyBean.java
+++ b/maven-faces-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/faces/parse/PropertyBean.java
@@ -447,6 +447,42 @@
     this._hidden = hidden;
   }
 
+  /**
+   * Sets the property deprecated flag
+   * @param deprecated
+   */
+  public void setDeprecated(String deprecated) 
+  {
+    this._deprecated = deprecated;
+  }
+
+  /**
+   * Value is provided through the deprecated extended property metadata.
+   * @return deprecated description if the component property should be deprecated
+   */
+  public String getDeprecated() {
+    return _deprecated;
+  }
+
+
+  /**
+   * @return <code>true</code> if the property should be generated with a no-op
+   *    setter.
+   */
+  public boolean isNoOp()
+  {
+    return _noOp;
+  }
+  
+  /**
+   * Invoked if the no-op extended property meta-data is provided for the component 
+   * property.
+   */
+  public void makeNoOp() 
+  {
+    this._noOp = true;
+  }
+  
   private String  _aliasOf;
   private String  _jspPropertyName;
   private String  _fieldPropertyName;
@@ -462,6 +498,8 @@
   private String[] _propertyValues;
   private String[] _unsupportedAgents = _EMPTY_ARRAY;
   private String[] _unsupportedRenderKits = _EMPTY_ARRAY;
+  private String _deprecated;
+  private boolean _noOp = false;
 
   static private String[] _EMPTY_ARRAY = new String[0];
 
diff --git a/maven-faces-plugin/src/main/resources/org/apache/myfaces/trinidadbuild/plugin/faces/resources/transform.xsl b/maven-faces-plugin/src/main/resources/org/apache/myfaces/trinidadbuild/plugin/faces/resources/transform.xsl
index 3b27cbb..57f8f98 100644
--- a/maven-faces-plugin/src/main/resources/org/apache/myfaces/trinidadbuild/plugin/faces/resources/transform.xsl
+++ b/maven-faces-plugin/src/main/resources/org/apache/myfaces/trinidadbuild/plugin/faces/resources/transform.xsl
@@ -44,6 +44,7 @@
   <!ELEMENT attribute-values (#PCDATA)>

   <!ELEMENT base-component-type (#PCDATA)>

   <!ELEMENT deprecated (#PCDATA)>

+  <!ELEMENT no-op (#PCDATA)>

   <!ELEMENT display-order (#PCDATA)>

   <!ELEMENT expert (#PCDATA)>

   <!ELEMENT favorite-property (#PCDATA)>

diff --git a/maven-faces-plugin/src/test/resources/META-INF/maven-faces-plugin/components/trinidad/faces/Command.xml b/maven-faces-plugin/src/test/resources/META-INF/maven-faces-plugin/components/trinidad/faces/Command.xml
index e8f9388..6bfc9ca 100644
--- a/maven-faces-plugin/src/test/resources/META-INF/maven-faces-plugin/components/trinidad/faces/Command.xml
+++ b/maven-faces-plugin/src/test/resources/META-INF/maven-faces-plugin/components/trinidad/faces/Command.xml
@@ -32,18 +32,28 @@
     <description>

       A base abstraction for components that implement ActionSource.

     </description>

-

+    

     <xi:include href="TestInclude.xml" xpointer="/faces-config/component/*"></xi:include>

 

     <property>

       <property-name>action</property-name>

       <property-class>javax.faces.el.MethodBinding</property-class>

-      <description>

+      <description><![CDATA[

+      

           The reference to the Java method that will be invoked when

-          an ActionEvent is broadcast by this component.  The method

-          signature takes zero parameters and may return String or void.

-          If a non-null String value is returned, it will be used as

-          an outcome for navigation.

+          an ActionEvent is broadcast by this component. The method

+          signature takes a single ActionEvent parameter and returns

+          void.

+          

+          Test to make sure that markup in a pre block is escaped.

+          <pre>

+            <af:commandButton />

+          </pre>

+          <pre>

+            <af:commandButton />

+          </pre>

+

+      ]]>    

       </description>

       <property-extension>

         <mfp:state-holder>true</mfp:state-holder>

@@ -59,11 +69,13 @@
     <property>

       <property-name>actionListener</property-name>

       <property-class>javax.faces.el.MethodBinding</property-class>

-      <description>

+      <description><![CDATA[

+      

           The reference to the Java method that will be invoked when

           an ActionEvent is broadcast by this component.  The method

           signature takes a single ActionEvent parameter and returns

           void.

+      ]]>    

       </description>

       <property-extension>

         <mfp:state-holder>true</mfp:state-holder>

@@ -98,19 +110,41 @@
     <property>

       <property-name>immediate</property-name>

       <property-class>boolean</property-class>

-      <description>

-        a reference to an action method sent by the command component, 

-or the static outcome of an action.  When immediate is true, the 

-default ActionListener provided by the JavaServer Faces implementation 

-should be executed during Apply Request Values phase of the request 

-processing lifecycle, rather than waiting until the Invoke Application 

-phase.

+      <description>a reference to an action method sent by the command component, 

+           or the static outcome of an action.  When immediate is true, the 

+           default ActionListener provided by the JavaServer Faces implementation 

+           should be executed during Apply Request Values phase of the request 

+           processing lifecycle, rather than waiting until the Invoke Application 

+           phase.

       </description>

       <property-extension>

         <mfp:required>false</mfp:required>

       </property-extension>

     </property>

 

+    <property>

+      <description><![CDATA[the visibility of the component.  If it is "false", the component will 

+      be hidden on the client.  Unlike "rendered", this does not affect the lifecycle on the server 

+      - the component may have its bindings executed, etc. - and the visibility of the component can 

+      be toggled on and off on the client, or toggled with PPR.  When "rendered" is false, the 

+      component will not in any way be rendered, and cannot be made visible on the client. 

+      In most cases, use the "rendered" property instead of the "visible" property.]]>

+      </description>

+      <property-name>visible</property-name>

+      <property-class>boolean</property-class>

+      <default-value>true</default-value>

+      <property-extension>

+        <mfp:required>false</mfp:required>

+        <mfp:unsupported-render-kits>org.apache.myfaces.trinidad.core</mfp:unsupported-render-kits>

+        <mfp:property-metadata>

+          <mfp:deprecated>The "visible" attribute has been deprecated.  

+            Use the af:showPopupBehavior tag or the show/hide methods on the popup client component.

+          </mfp:deprecated>

+          <mfp:no-op/>

+        </mfp:property-metadata>

+      </property-extension>

+    </property>

+

     <component-extension>

       <mfp:component-family>org.apache.myfaces.trinidad.Command</mfp:component-family>

       <mfp:default-renderer-type>org.apache.myfaces.trinidad.Button</mfp:default-renderer-type>

@@ -119,6 +153,8 @@
       <mfp:jsp-tag-class>org.apache.myfaces.trinidadinternal.taglib.UIXCommandTag</mfp:jsp-tag-class>

       <mfp:jsp-tag-name>af:command</mfp:jsp-tag-name>

 

+      <!-- <mfp:implementation-type>trinidad</mfp:implementation-type> -->

+

       <mfp:event>

         <mfp:event-type>javax.faces.Action</mfp:event-type>

         <mfp:event-delivery-phases>Invoke Application,Apply Request Values</mfp:event-delivery-phases>

diff --git a/maven-tagdoc-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/tagdoc/TagdocReport.java b/maven-tagdoc-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/tagdoc/TagdocReport.java
index 8677b85..6ed5033 100644
--- a/maven-tagdoc-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/tagdoc/TagdocReport.java
+++ b/maven-tagdoc-plugin/src/main/java/org/apache/myfaces/trinidadbuild/plugin/tagdoc/TagdocReport.java
@@ -910,6 +910,26 @@
           out.write(valStr);
           out.write("<br/>");
         }
+        
+        if (attr.getDeprecated() != null) 
+        {
+          out.write("<b>");
+          out.write(attr.getDeprecated());
+          out.write("</b>");
+        }
+        
+        if (attr.isNoOp()) 
+        {
+          out.write("<b>");
+          out.write("This property has a no-op setter for both the client and server components effectively making it a read-only property.");
+          out.write("</b>");            
+        }
+        
+        if (attr.isNoOp() || attr.getDeprecated() != null) 
+        {
+          out.write("<br/><br/>");
+        }
+        
         out.write(attr.getDescription());
         if (unsupAgentsStr != null)
         {