<?xml version="1.0" encoding="utf-8"?>

<ruleset name="net.ranides.assira.custom"
    xmlns="http://pmd.sf.net/ruleset/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">

    <description>
    Assira Quality Policy - custom rules
    </description>

    <rule
        name="TooManyDifferentMethods"
        since="4.3"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        message="This class has too many different methods, consider refactoring it."
        externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#TooManyMethods"
        language="java"
        >
        <description><![CDATA[Counts unique methods (all overloaded versions are considered as the same). Ignores UtilityClassess.]]></description>
        <priority>3</priority>
        <properties>
            <property name="maximum" type="Integer" description="The method count reporting threshold " min="1" max="1000" value="15"/>
            <property name="xpath"><value>
            <![CDATA[
            //ClassOrInterfaceDeclaration[
            
                count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration[
                    MethodDeclaration
                    and not(Annotation/MarkerAnnotation/Name[@Image='Override'])
                    and not(starts-with(MethodDeclaration/@MethodName,'get'))
                    and not(starts-with(MethodDeclaration/@MethodName,'set'))
                    and not(
                        MethodDeclaration/@MethodName
                        =
                        preceding-sibling::ClassOrInterfaceBodyDeclaration/MethodDeclaration/@MethodName
                        )
                ]) > $maximum
            
                and not (
                    @Final='true'
                    and
                    ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true'][@ParameterCount='0']
                    and
                    count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)=1
                )
            ]
            ]]>
            </value></property>
        </properties>
    </rule>
    
    
    <rule
        name="TooManyPublicMethods"
        since="4.3"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        message="This class has too many public methods, consider refactoring it."
        externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#TooManyMethods"
        language="java"
        >
        <description><![CDATA[Counts public methods]]></description>
        <priority>3</priority>
        <properties>
            <property name="maximum" type="Integer" description="The method count reporting threshold " min="1" max="1000" value="40"/>
            <property name="xpath"><value>
            <![CDATA[
            //ClassOrInterfaceDeclaration[
                count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
                    @Public='true'
                    and not(starts-with(@MethodName,'get'))
                    and not(starts-with(@MethodName,'set'))
                    and not(../Annotation/MarkerAnnotation/Name[@Image='Override'])
                ]) > $maximum
            ]
            ]]>
            </value></property>
        </properties>
    </rule>
    
<!--
    <rule
        name="ShortVar" 
        since="2.0" 
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        message="Avoid variables with short names like {0}"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#ShortVariable"
        language="java"
        >
        <description>
            <![CDATA[Detects when a field, local, or parameter has a very short name.Ignores primitive types, local Iterators and for-variables.]]>
        </description>
        <priority>3</priority>
        <properties><property name="xpath" pluginname="true"><value>
            <![CDATA[
            //VariableDeclaratorId [
               string-length(@Image) < 3
               and not(@Image='_')
               and not(@Image='id')
               and not(ancestor::ForInit)
               and not(../Type/PrimitiveType)
               and not(../../Type/PrimitiveType)
               and not(
                  (../../Type/ReferenceType/ClassOrInterfaceType[@Image='Iterator'])
                  or
                  (../../../FormalParameter)
               )
               and not(/TypeDeclaration/ClassOrInterfaceDeclaration[ends-with(@Image,'Test')])
               and not((ancestor::FormalParameter) and (ancestor::TryStatement))
               and not((@Image='em') and (../../Type/@TypeImage='EntityManager'))
               and not((@Image='em') and (../Type/@TypeImage='EntityManager'))
            ]
            ]]>
        </value></property></properties>
    </rule>
-->    
    <rule
        name="LongVar"
      	since="0.3"
        message="Avoid excessively long variable names like {0}"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#LongVariable"
        language="java"
        >
        <description>Detects when a field, formal or local variable is declared with a long name.</description>
        <priority>3</priority>
        <properties>
            <property name="minimum" type="Integer" description="The variable length reporting threshold" min="1" max="1000" value="16"/>
            <property name="xpath" pluginname="true"><value>
            <![CDATA[
                //VariableDeclaratorId[
                    string-length(@Image) > $minimum
                    and (@Static='false' or @Final='false')
                ]
            ]]>
            </value></property>
        </properties>
    </rule>


    <rule name="FieldNameRules" since="2.0" class="net.sourceforge.pmd.lang.rule.XPathRule"
        message="Field name doesn't respect required pattern"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#VariableNamingRegexp"
        language="java"
    >
        <description>Checks all field names against regular expression</description>
        <priority>3</priority>
        <properties><property name="xpath" pluginname="true"><value>
            <![CDATA[
            //FieldDeclaration[
                not(matches(@VariableName,'^(m_|\$)?([a-z][a-zA-Z0-9]*)$'))
                and( (@Static='false') or (@Final='false') )
            ]
            ]]>
        </value></property></properties>
    </rule>

    <rule name="MethodNameRules" since="2.0" class="net.sourceforge.pmd.lang.rule.XPathRule"
        message="Method name doesn't respect required pattern"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#VariableNamingRegexp"
        language="java"
    >
        <description>Checks all methods names against regular expression</description>
        <priority>3</priority>
        <properties><property name="xpath" pluginname="true"><value>
            <![CDATA[
            //ClassOrInterfaceBodyDeclaration
                [not(Annotation/MarkerAnnotation/Name[@Image='Test'])]
                [not(Annotation/MarkerAnnotation/Name[@Image='InterfaceTest'])]
            /MethodDeclaration/MethodDeclarator
                [not(matches(@Image,'^(m_|\$)?([a-z][a-zA-Z0-9]*)$'))]
            ]]>
        </value></property></properties>
    </rule>

    <rule
        name="InvalidUtilityClass"
    	since="3.0"
        message="Utility class does not provide any static methods, fields or interfaces"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#InvalidUtilityClass"
        language="java"
        >
        <description>A class that has private constructors and does not have any static methods, fields or type declarations cannot be used.</description>
        <priority>3</priority>
        <properties><property name="xpath"><value>
            <![CDATA[
            //ClassOrInterfaceDeclaration[@Nested='false'][
                (
                    count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)>0
                    and 
                    count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) = count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true']) 
                )
                and count(.//MethodDeclaration[@Static='true'])=0
                and count(.//FieldDeclaration[@Private='false'][@Static='true'])=0
                and count(.//ClassOrInterfaceDeclaration[@Interface='true'])=0
                and count(.//AnnotationTypeDeclaration)=0
                and count(.//ClassOrInterfaceDeclaration[@Static='true' and @Private='false'])=0
            ]
            ]]>
        </value></property></properties>
    </rule>
    
    <rule
        name="TooManyParams"
    	since="3.0"
        message="Avoid really long parameter lists."
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyParams"
        language="java"
        >
        <description>Long parameter lists can indicate that a new object should be created to wrap the numerous parameters.  Basically, try to group the parameters together.</description>
        <priority>3</priority>
        <properties>
            <property name="maximum" type="Integer" description="The parameter count reporting threshold" min="1" max="1000" value="3"/>
            <property name="xpath"><value>
            <![CDATA[
            //ClassOrInterfaceBodyDeclaration
                [ MethodDeclaration/MethodDeclarator/FormalParameters[@ParameterCount>$maximum] ]
                [ not(Annotation/MarkerAnnotation/Name[@Image='Override']) ]
            ]]>
            </value></property>
        </properties>
    </rule>
    
    <rule
        name="AvoidThreadGroup"
        since="3.6"
        message="Avoid using java.lang.ThreadGroup; it is not thread safe"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#AvoidThreadGroup"
        language="java"
        typeResolution="true"
        >
        <description>Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment it contains methods that are not thread safe.</description>
        <priority>3</priority>
        <properties>
            <property name="xpath"><value>
            <![CDATA[
            //AllocationExpression/ClassOrInterfaceType
                [ typeof(@Image, 'java.lang.ThreadGroup') and contains(@Image, 'ThreadGroup') ]
            |
            //PrimarySuffix[contains(@Image, 'getThreadGroup')]
            ]]>
            </value></property>
        </properties>
    </rule>
    
    <rule
        name="UseSingleton"
    	since="3.0"
        message="All methods are static.  Consider using Singleton instead.  Alternatively, you could add a private constructor or make the class abstract to silence this warning."
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#UseSingleton"
        language="java"
        >
        <description><![CDATA[If you have a class that has nothing but static methods, consider making it a Singleton. If you want this class to be a Singleton, remember to add a private constructor to prevent instantiation.]]></description>
        <priority>3</priority>
        <properties>
            <property name="xpath"><value>
            <![CDATA[
            //ClassOrInterfaceDeclaration[
                @Interface='false' and @Abstract='false'
                and not(ExtendsList)
                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
                    @Private!='true' and @Static='false'
                ]) 
                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[
                    @Private!='true' and @Static='false'
                ])
                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
                    @MethodName='main' and
                    @Static='true' and
                    @Public='true' and
                    @Void='true' and
                    MethodDeclarator/FormalParameters[@ParameterCount=1] and
                    MethodDeclarator/FormalParameters/FormalParameter/Type[@Array='true' and @TypeImage='String']
                ])
                and (
                    @Final='false' or
                    count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)!=1
                    or not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[
                        @Private='true'
                        and FormalParameters[@ParameterCount=0]
                    ])
                )
            ]
            ]]>
            </value></property>
        </properties>
    </rule>
    
    
    <rule
        name="TooManyFields"
        since="4.3"
        message="Too many fields"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyFields"
        typeResolution="true"
        language="java"
        >
        <description><![CDATA[Classes that have too many fields could be redesigned to have fewer fields, possibly through some nested object grouping of some of the information.  For example, a class with city/state/zip fields could instead have one Address field.]]></description>
        <priority>3</priority>
        <properties>
            <property name="maximum" type="Integer" description="The field count reporting threshold " min="1" max="1000" value="15"/>
            <property name="xpath"><value>
            <![CDATA[
            //ClassOrInterfaceDeclaration[
                count(
                    ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration
                    [@Final='false']
                    [@Static='false']
                ) > $maximum
            ]
            ]]>
            </value></property>
        </properties>
    </rule>

    <rule name="UnusedParameter"
              language="java"
              since="5.3"
              message="Avoid unused {0} parameters such as ''{1}''."
              class="net.ranides.assira.rules.UnusedParameterRule"
              externalInfoUrl="${pmd.website.baseurl}/rules/java/unusedcode.html#UnusedFormalParameter">
        <description>
            Avoid passing parameters to methods or constructors without actually referencing them in the method body.
            Note: that rule ignores parameters prefixed with $ or _.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
public class Foo {
	private void bar(String howdy) {
	// howdy is not used
	}
}
]]>
        </example>
    </rule>
    
    <!--
    <rule
        name="LexicableConstructor"
        since="4.3"
        message="Lexicable class must be constructable from LexicalContext"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyFields"
        typeResolution="true"
        >
        <description><![CDATA[Classes that implement Lexicable interface must declare apriotiate ocnstructor with signature: Construct(LexicalContext context). It can be public but this is not obligatory.]]></description>
        <priority>3</priority>
        <properties>
            <property name="xpath"><value>
            <![CDATA[
            //ClassOrInterfaceDeclaration[
                ImplementsList/ClassOrInterfaceType[
                    @Image='Lexicable' or @Image='net.ranides.assira.text.Lexicable'
                ]
                and
                not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[
                    FormalParameters[
                        @ParameterCount='1' 
                        and 
                        FormalParameter/Type[@Array='false'][@TypeImage='LexicalContext' or @TypeImage='net.ranides.assira.text.LexicalContext']
                    ]
                ])
            ]
            ]]>
            </value></property>
        </properties>
    </rule>
    -->

</ruleset>