domenica 31 marzo 2013

Pull on Git Gui

http://stackoverflow.com/questions/7299237/how-can-i-do-a-git-pull-in-the-gitg-gitx-visual-tool

You cannot directly pull from git gui, but given than a pull is a fetch followed by a merge, you can fetch the remote (in the remote menu and fetch from), and then merge the remote branch into yours (Merge menu and Local merge, select tracking branch).

Git And Remote Repositories


Commands discussed in this section:

  • git clone
  • git pull
  • git push

“Here is The Git URL”

For many people, the first time they use git occurs when somebody says: “Our source repository is in git. Here is the git URL”. You might be given a URL that looks like one of these:
  • http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
  • ssh://user@host.com/var/git/project.git
  • git://git.debian.org/collab-maint/usplash.git
  • file:///var/git/project.git
The URL describes where the repository is located and what protocol (http, ssh, git, local file, etc.) to use to get it.
To get started with a git repository, all you need to do is type git clone followed by the URL you were given.
You don’t have to understand the details of remote repositories to work with them. Typically, if you want to participate in a project using git, you can follow this standard workflow:
  • git clone URL:
    After you have done a git clone, you have a copy of the complete repository.
  • Make some changes to the local version of the repository, then git add and git commit the changes to the local repository.
  • git push to publish the changes (“commits”) to the remote repository
  • Periodically git pull to retrieve any new updates from the remote repository.
That’s all there is to it for the typical case.
git remote overview

martedì 26 marzo 2013

Git Branching

http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is

3.1 Git Branching - What a Branch Is

What a Branch Is

To really understand the way Git does branching, we need to take a step back and examine how Git stores its data. As you may remember from Chapter 1, Git doesn’t store data as a series of changesets or deltas, but instead as a series of snapshots.
When you commit in Git, Git stores a commit object that contains a pointer to the snapshot of the content you staged, the author and message metadata, and zero or more pointers to the commit or commits that were the direct parents of this commit: zero parents for the first commit, one parent for a normal commit, and multiple parents for a commit that results from a merge of two or more branches.
To visualize this, let’s assume that you have a directory containing three files, and you stage them all and commit. Staging the files checksums each one (the SHA-1 hash we mentioned in Chapter 1), stores that version of the file in the Git repository (Git refers to them as blobs), and adds that checksum to the staging area:
$ git add README test.rb LICENSE
$ git commit -m 'initial commit of my project'
When you create the commit by running git commit, Git checksums each subdirectory (in this case, just the root project directory) and stores those tree objects in the Git repository. Git then creates a commit object that has the metadata and a pointer to the root project tree so it can re-create that snapshot when needed.
Your Git repository now contains five objects: one blob for the contents of each of your three files, one tree that lists the contents of the directory and specifies which file names are stored as which blobs, and one commit with the pointer to that root tree and all the commit metadata. Conceptually, the data in your Git repository looks something like Figure 3-1.

Figure 3-1. Single commit repository data.
If you make some changes and commit again, the next commit stores a pointer to the commit that came immediately before it. After two more commits, your history might look something like Figure 3-2.

Figure 3-2. Git object data for multiple commits.
A branch in Git is simply a lightweight movable pointer to one of these commits. The default branch name in Git is master. As you initially make commits, you’re given a master branch that points to the last commit you made. Every time you commit, it moves forward automatically.

Figure 3-3. Branch pointing into the commit data’s history.
What happens if you create a new branch? Well, doing so creates a new pointer for you to move around. Let’s say you create a new branch called testing. You do this with the git branch command:
$ git branch testing
This creates a new pointer at the same commit you’re currently on (see Figure 3-4).

Figure 3-4. Multiple branches pointing into the commit’s data history.
How does Git know what branch you’re currently on? It keeps a special pointer called HEAD. Note that this is a lot different than the concept of HEAD in other VCSs you may be used to, such as Subversion or CVS. In Git, this is a pointer to the local branch you’re currently on. In this case, you’re still on master. The git branch command only created a new branch — it didn’t switch to that branch (see Figure 3-5).

Figure 3-5. HEAD file pointing to the branch you’re on.
To switch to an existing branch, you run the git checkout command. Let’s switch to the new testing branch:
$ git checkout testing
This moves HEAD to point to the testing branch (see Figure 3-6).

Figure 3-6. HEAD points to another branch when you switch branches.
What is the significance of that? Well, let’s do another commit:
$ vim test.rb
$ git commit -a -m 'made a change'
Figure 3-7 illustrates the result.

Figure 3-7. The branch that HEAD points to moves forward with each commit.
This is interesting, because now your testing branch has moved forward, but your master branch still points to the commit you were on when you ran git checkout to switch branches. Let’s switch back to the master branch:
$ git checkout master
Figure 3-8 shows the result.

Figure 3-8. HEAD moves to another branch on a checkout.
That command did two things. It moved the HEAD pointer back to point to the master branch, and it reverted the files in your working directory back to the snapshot that master points to. This also means the changes you make from this point forward will diverge from an older version of the project. It essentially rewinds the work you’ve done in your testing branch temporarily so you can go in a different direction.
Let’s make a few changes and commit again:
$ vim test.rb
$ git commit -a -m 'made other changes'
Now your project history has diverged (see Figure 3-9). You created and switched to a branch, did some work on it, and then switched back to your main branch and did other work. Both of those changes are isolated in separate branches: you can switch back and forth between the branches and merge them together when you’re ready. And you did all that with simple branch and checkout commands.

Figure 3-9. The branch histories have diverged.
Because a branch in Git is in actuality a simple file that contains the 40 character SHA-1 checksum of the commit it points to, branches are cheap to create and destroy. Creating a new branch is as quick and simple as writing 41 bytes to a file (40 characters and a newline).
This is in sharp contrast to the way most VCS tools branch, which involves copying all of the project’s files into a second directory. This can take several seconds or even minutes, depending on the size of the project, whereas in Git the process is always instantaneous. Also, because we’re recording the parents when we commit, finding a proper merge base for merging is automatically done for us and is generally very easy to do. These features help encourage developers to create and use branches often.
Let’s see why you should do so.

venerdì 22 marzo 2013

Compilare plugin PMD

Compilare plugin PMD

I sorgenti si trovano qui: https://github.com/pmd/pmd/tree/master/pmd-eclipse-plugin

Ant

Non sono riuscito a compilare con ANT. Hoprovato a modificare i lfile di build  build.xml con le impostazioni del mio sistema (cioè dei plugin installati in C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\plugins ), modificando le properties:



7    <property name="eclipse.home" value="C:/Program Files/Java/eclipse-jee-juno-win32/eclipse"/>
8    <property name="eclipse.pde.version" value="3.8.0.v20120523-1555"/>
9  
10  <property name="eclipse.launcher.version" value="1.3.0.v20120522-1813"/>


ma ottengo sempre il seguente errore:


[java] generateScript:
 [java]
 [java] BUILD FAILED
 [java] [eclipse.buildScript] Some inter-plug-in dependencies have not been satisfied.
 [java] C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\plugins\org.eclipse.pde.build_3.8.0.v20120523-1555\scripts\build.xml:35: The following error occurred while executing this line:
 [java] [eclipse.buildScript] Bundle net.sourceforge.pmd.eclipse.plugin:
 [java] C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\plugins\org.eclipse.pde.build_3.8.0.v20120523-1555\scripts\build.xml:91: The following error occurred while executing this line:
 [java] [eclipse.buildScript]       Another singleton version selected: net.sourceforge.pmd.eclipse.plugin_4.0.0.201211080927
 [java] C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\plugins\org.eclipse.pde.build_3.8.0.v20120523-1555\templates\headless-build\customTargets.xml:12: The following error occurred while executing this line:
 [java] C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\plugins\org.eclipse.pde.build_3.8.0.v20120523-1555\templates\headless-build\allElements.xml:16: The following error occurred while executing this line:
 [java] C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\plugins\org.eclipse.pde.build_3.8.0.v20120523-1555\scripts\genericTargets.xml:111: Unable to find feature: net.sourceforge.pmd.eclipse.
 [java]
 [java] Total time: 8 seconds
 [java] An error has occurred. See the log file
 [java] C:\Users\Duccio\workspace\.metadata\.log.
BUILD FAILED
C:\Users\Duccio\Lavori\PMDPlugin\pmd-pmd-5.0.x\pmd-eclipse-plugin\build.xml:47: Java returned: 13
Total time: 16 seconds

Dopo alcune ricerche e tentativi, post su forum: 
http://sourceforge.net/p/pmd/discussion/188194/thread/3dd4adf9/
https://sourceforge.net/p/pmd/discussion/188194/thread/3dd4adf9/?limit=25#b53a/83b8

ho lasciato perdere e ho provato a compilare il tutto con Eclipse


Eclipse

Anche in questo caso c'è da fare alcune modifiche ma alla fine sono riuscito a compilare.
Per importare i file in eclipse ho seguito le indicazioni del readme:


Importing the projects in Eclipse
=================================

In the Java perspective, select "Import" -> "Existing Java projects", select
the directory where this file is located.  The next panel should have four
projects:

net.sourceforge.pmd.eclipse
net.sourceforge.pmd.eclipse.plugin
pmd-eclipse-test
pmd-eclipse-test-fragment

Dopo occorre:


- In net.sourceforge.pmd.eclipse.plugin\META-INF\MANIFEST.MF tolto riferimento a org.eclipse.help.appserver secondo quanto descritto qui:
http://www.eclipse.org/eclipse/development/porting/4.2/incompatibilities.html

- Modificato in pmd-eclipse-plugin\features\net.sourceforge.pmd.eclipse\feature.xml la versione di net.sourceforge.pmd.eclipse, sostituendo 5.0.0.v20100826 a  5.0.0.v200810141040

- In pmd-eclipse-plugin\features\net.sourceforge.pmd.eclipse\build.properties "Versions" "Copy Versions"

- pmd-eclipse-plugin\pmd-eclipse-test\plugin.xml

In questo modo si dovrebbe compilare e esportare in modalità "deployable feature".
in questo modo si ottengono due folder "plugins" "features" che andranno copiate nella cartella eclipse_home (ad es. C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\dropins).
Per maggiore ordine si può introdurre una cartella "pmd" dentro la  dropin:
C:\Program Files\Java\eclipse-jee-juno-win32\eclipse\dropins\pmd.
Fatto questo si riavvia eclipse e il gioco è fatto.
Per disinstallare il plugin basta cancellare le cartelle inserite e riavviare eclipse.
E' tutto qui :)

Per installare insieme al plugin una versione modificata di pmd, occorre ricompilare pmd con le modifiche.
ATTENZIONE! il plugin è stato compilato con una versione vecchia del plugin, dovrebbe essere la versione  5.0-SNAPSHOT, se si prova a compilare con una versione recente, ad esempio la 5.1.0 si ha un errore in quanto il plugin cerca di usare delle classi che nelle nuove versioni di PMD non sono più presenti.
Ci troviamo quindi davanti a due opzioni: modificare il plugin per renderlo compatibile con le ultime versioni di pmd, oppure recuperare la versione di pmd usata per compilare il plugin e modificare quella.
Io ho optato per la seconda strada, in quanto mi sembrava più veloce.

La versione di pmd "5.0-SNAPSHOT" si trova in github, ma non mi è chiaro a quale commit corrisponda.
Credo si tratti di SHA1: d54a66857c33c0859a1881f90a97fa4e272e79c3

Per recuperare questa versione occorre installare il client github, ad esempio Git-Gi (http://www.ohloh.net/p/git-gui).
Una volta installato si fa un clone del repositori pmd da https://github.com/pmd/pmd.git su un repository locale sulla propria macchina.
A questo punto abbiamo in locale tutta la storia dei commit di tutto il progetto.Andando a ritroso nel tempo fino al 31 gennaio 2012 si arriva appunto alla versione che mi sembra quella usata per compilare il plugin.

A questo punto si fa un "crea ramo" specificando il SHA1 opportuno, così nel repository locale si dovrebbe recuperare i sorgenti ricercati. Compilandoli con mvn package si dovrebbe ottenere pmd-5.0-SNAPSHOT.jar.

QUesto jar va copiato nella cartella lib del progetto eclcipse con cui si vuole compilare il plugin, dopodichè va aggiunto al build path delle referenced library nel package explorer di eclipse. Questa operazione va fatta specificando che il jar deve essere locale e non esterno al progetto, nell'elenco dei jar nel package explorer non deve comparire il path in cui si trova, ma deve comparire come tutti gli altri senza path. Sono arrivato a questo risultato solo dopo diversi tentativi, chiudendo e riaprendo eclipse e non so con esattezza quale sia la procedura corretta.

ATTENZIONE, in origine il jar si chiamava solo pmd-5.0.jar e anche in META-INF/MANIFEST.MF è indicato con questo nome, ho l'impressione che vada modificato il file assegnando il nuovo nome del .jar.

Facendo tutto ciò, lanciando la compilazione da eclipse.. nella cartella bin del progetto si dovrebbero trovare le classi compilate.

__________________________________________________________________
che genererà il nuovo .jar. Ad esempio:
- nel package package net.sourceforge.pmd.lang.java.rule.codesize si copia il file ExcessiveClassLengthRule.java e lo si rinomina in ClasseTroppoLungaRule.java.
Si rinomina il nome della classe e del costruttore e si salva.
- In src\main\resources si modifica l ruleset codesize.xml aggiungendo una descrizione anche per ClasseTroppoLungaRule e si salva.
- Si modifica artifactId in pom.xml, ad esempio impostandolo a pmdDuccius e si salva
Se non ci sono problemi dentro la cartella target del progetto si dovrebbe trovare il file pmdDuccius-5.0.0.jar.
- questo va aggiunto alla cartella lib del progetto del plugin e nel progetto la si aggiunge alle referenced libraries
- si elimina la vecchia pmd 5.0.0



mercoledì 20 marzo 2013

Improving Code Quality with PMD and Eclipse


http://www.eclipsezone.com/articles/pmd/


PMD is a static code analyzer for Java. Developers use PMD to comply with coding standards and deliver quality code. Team leaders and Quality Assurance folks use it to change the nature of code reviews. PMD has the potential to transform a mechanical and syntax check oriented code review into a to dynamic peer-to-peer discussion.
This article looks at PMD as an Eclipse plugin and the ways it can be used to improve the code quality and shorten the code review process. Since every organization has a unique set of coding conventions and quality metrics, it also demonstrates how to customize PMD to meet these needs.

What is PMD?

PMD works by scanning Java code and checks for violations in three major areas:
  • Compliance with coding standards such as:
    • Naming conventions - class, method, parameter and variable names
    • Class and method length
    • Existence and formatting of comments and JavaDocs
  • Coding antipatterns such as:
    • Empty try/catch/finally/switch blocks
    • Unused local variables, parameters and private methods
    • Empty if/while statements
    • Overcomplicated expressions - unnecessary if statements, for loops that could be while loops
    • Classes with high Cyclomatic Complexity measurements
  • Cut and Paste Detector (CPD) - a tool that scans files and looks for suspect code replication. CPD can be parameterized by the minimum size of the code block.
In its current version, PMD comes packaged with 149 rules in 19 rulesets. Most of these rules can be parameterized at runtime by supplying properties or parameters. The standard package offers many well-thought rules. In addition users also have the ability to add their own rules for particular coding convention or quality metrics. Here are some of the rules distributed with PMD:
  • EmptyFinalizer - If the finalize() method is empty, then it does not need to exist.
  • EmptyFinallyBlock - Avoid empty finally blocks - these can be deleted.
  • UnnecessaryReturn - Avoid unnecessary return statements
  • OnlyOneReturn - A method should have only one exit point, and that should be the last statement in the method.
  • CyclomaticComplexity - Complexity is determined by the number of decision points in a method plus one for the method entry. The decision points are 'if', 'while', 'for', and 'case labels'. Generally, 1-4 is low complexity, 5-7 indicates moderate complexity, 8-10 is high complexity, and 11+ is very high complexity.
  • TooManyFields - 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.
  • LongVariable - Detects when a field, formal or local variable is declared with a long name.
  • NoPackage - Detects when a class or interface does not have a package definition.

Where to find it?

PMD started as a standalone application and today it is an open-source project hosted under SourceForge.net. It is still distributed as a standalone application, however there is now substantial support for most popular Java IDEs. The PMD team has developed plugins for JDeveloper, Eclipse, JEdit, JBuilder, Omnicore's CodeGuide, NetBeans/Sun Java Studio Enterprise/Creator, IntelliJ IDEA, TextPad, Maven, Ant, Gel, JCreator, and Emacs. This article covers PMD's Eclipse plugin only.
PMD binaries and source files can be downloaded from PMD's Sourceforge directory. For an open-source project, PMD is relatively well-documented. Among the items inPMD's main site are topics such as installation, PMD-related products and books, best practices, licensing info, usage guides and more. There is also a section for developers interested in joining the project. The following items target the latter: compiling PMD, project info, project reports, and development process.

How to install it?

The easiest way to install PMD is by using the remote update site. Users behind firewalls should check proxy settings before going any further. If these settings are misconfigured the updater will not work. PMD also supplies a zip file for manual installation. Download the file and follow the readme. Demonstrated below is installing PMD via the Eclipse Software Updater.
  1. Launch Eclipse.
  2. Navigate to Help | Software Updates | Find and Install...
  3. Select "Search for new features to install" and click Next
  4. Click New Remote Site...
  5. Enter a name (PMD) and the URL http://pmd.sourceforge.net/eclipse
  6. In Sites to include in search check PMD and click Finish
  7. In the Search Results dialog check PMD for Eclipse 3 3.1.0 and click Next
  8. Accept the terms of the license agreements and click Next
  9. Click Finish.
  10. Wait for Eclipse to download the required jar files, then click Install
  11. Restart the workbench. This will load the PMD plugin.
  12. Navigate to Window | Show View | Other...
  13. Select PMD | PMD Violations
  14. PMD Violations view should appear at the bottom pane

How to use it?

Before launching Eclipse make sure you have enough memory for PMD. This is particularly important when analyzing large projects. In these situations PMD tends to be memory-hungry. Hence, make sure to start with as much memory as you can afford, for example 512M (eclipse.exe -vmargs -Xmx512M)
  1. Launch Eclipse
  2. If you have previously created a Java Project, skip to Step 6. Otherwise click File | New | Project...
  3. Select Java Project and click Next
  4. Enter a project name (QA Project) and leave everything else in the default state.
  5. Click Finish. Eclipse will ask if you want to switch to the Java Perspective. Click Yes.
  6. In the Package Explorer right-click on QA Project and select New | Class
  7. In the following dialog enter the class name as Ying and click Finish
  8. A new class Ying is created in project's default package. Paste the following code into the new class:
    public class Ying {
    
     private static final String gOOD = "GOOD";
    
     public void StartSomething() {
      System.out.println("Hello PMD World!");
     }
    
     public String thisIsCutAndPaste(String pFirst, int pSecond) {
      System.out.println("New world");
      return "New world";
     }
    }
  9. Similarly, create a second class Yang and paste the following code:
    public class Yang extends Thread {
     public Yang(String str) {
      super(str);
     }
    
     public void run() {
      for (int i = 0; i < 10; i++) {
       System.out.println(i + " " + getName());
       try {
        sleep((long) (Math.random() * 1000));
       } catch (InterruptedException e) {
       }
      }
      System.out.println("DONE! " + getName());
     }
    
     public void WRITE_SOMETHING(String INPUT_PARAMETER) {
      System.out.println(INPUT_PARAMETER);
     }
    
     public static void main(String[] args) {
      new Yang("Good").start();
      new Yang("Bad").start();
     }
    
     public String thisIsCutAndPaste(String pFirst, int pSecond) {
      System.out.println("New world");
      return "New world";
     }
    }
  10. In the Package Explorer right-click on QA Project and select PMD | Check Code With PMD
  11. Wait for PMD to scan Ying and Yang
  12. If PMD Violations view is not open navigate to Window | Show View | Other... and select PMD | PMD Violations
  13. In the PMD Violations view notice a list of 17 violations. In large projects this list could easily grow up to several thousand. This is one of the reasons PMD allows violations be filtered by priority. Priority is a configurable attribute of a PMD rule. PMD assigns priorities from 1 to 5 and each priority is represented by a colored square at the top-right corner of the view. These little squares are actually clickable on-off switches used to control the visibility of the violations they represent.
    The results table itself is well laid out and most columns are sortable. It is also possible to get more detail on a violation by simply right-clicking it and selectingShow rule. PMD pops-up a dialog with information such as rule name, implementation class, message, description and an example. This feature can be helpful when trying to makes sense of a new rule or letting inhouse developers know about a particular company rule or coding convention.
    Finally, in the PMD Violations table it is possible to add review annotations to the source where the violation occurred. This can be an effective way to mark target files for further review. Just right-click on any violation in the list and select Mark review. PMD will insert a review annotation to the Java source right above the violation line itself. The review annotation should look like this:
    // @PMD:REVIEWED:MethodNamingConventions: by Levent Gurses on 3/28/04 5:04 PM
    
    
    Review annotations can be removed anytime by right-clicking QA Project and selecting PMD | Clear violations reviews. Similarly, PMD Violations can be cleaned-up by right-clicking QA Project and selecting PMD | Clear PMD Violations..

Finding Cut and Paste Code

Repeated (Cut&Paste) code generally indicates poor planning or team coordination. Therefore, refactoring classes with repeating code should be given a high priority. PMD can help identify these classes by scanning the code in a way similar to PMD violation checks. The number of lines of similarity (the metrics used by PMD to match code patterns) is 25 by default and can be set in PMD's Preferences page.
  1. In Package Explorer right-click on QA Project and select PMD | Find Suspect Cut And Paste
  2. PMD creates a folder reports under QA Project and stores the result text file
  3. Select Window | Show View | Navigator
  4. In Navigator view click on QA Project and then on the reports folder
  5. The report file cpd-report.txt should look like this:
    =====================================================================
    Found a 8 line (25 tokens) duplication in the following files:
    Starting at line 6 of C:\temp\QA Project\Ying.java
    Starting at line 23 of C:\temp\QA Project\Yang.java
      new Yang("Bad").start();
     }
    
     public String thisIsCutAndPaste(String pFirst, int pSecond) {
      System.out.println("New world");
      return "New world";
     }
    }

Generating Reports

After running a lengthy violation check it may be desirable to share the findings with peers or store them for later reference. For situations of this kind PMD provides a handy reporting tool capable of generating reports in multiple formats. Currently PMD can generate reports in HTML, XML, plain text as well as Comma Separated Value (CSV) formats.
  1. In Package Explorer right-click on QA Project and select PMD | Generate reports
  2. PMD creates a folder reports under QA Project and stores four report files
  3. Select Window | Show View | Navigator
  4. In Navigator view click on QA Project and then on the reports folder
  5. Of the four report files pmd-report.html should look like this:
    #FileLineProblem
    1Yang.java8System.out.print is used
    2Yang.java14System.out.print is used
    3Yang.java17Method name does not begin with a lower case character.
    4Yang.java17Method names should not contain underscores
    5Yang.java17Parameter 'INPUT_PARAMETER' is not assigned and could be declared final
    6Yang.java18System.out.print is used
    7Yang.java21Parameter 'args' is not assigned and could be declared final
    8Yang.java27System.out.print is used
    9Ying.java1Each class should declare at least one constructor
    10Ying.java3Avoid unused private fields such as 'gOOD'
    11Ying.java5Method name does not begin with a lower case character.
    12Ying.java6System.out.print is used
    13Ying.java9Parameter 'pFirst' is not assigned and could be declared final
    14Ying.java9Parameter 'pSecond' is not assigned and could be declared final
    15Ying.java10System.out.print is used

Customizing PMD

The easiest way to begin customizing PMD is by playing with existing rules. Adding new rules is also possible as well as removing unnecessary ones, however these require more knowledge. Since experimenting with existing rules is the easiest, it makes sense to start with them.
Each PMD rule has six attributes:
  • Rule name - immutable
  • Rule implementation class - immutable
  • Priority
  • Message
  • Description
  • Example
Of these six attributes the first two are immutable - they cannot be customized by users. While Message, Description and Example are text-based properties and can accept any String data, Priority is an integer field ranging from 1 to 5.
PMD stores rule configuration in a special repository referred to as the Ruleset XML file. This configuration file carries information about currently installed rules and their attributes. Changes made through the Eclipse Preferences page are also stored in this file. In addition, the PMD Preferences page allows exporting and importing Rulesets which makes them a convenient vehicle for sharing rules and coding conventions across the enterprise.
Before starting the customization it may be a good idea to back-up existing configuration.
  1. Navigate to Window | Preferences... | PMD | Rules configuration
  2. Click Export rule set...
  3. Enter a file name e.g. pmd-rules.xml and click Save
  4. Back in the Rules configuration page scroll-down and click on SystemPrintln rule
  5. With the rule selected, click the Priority column and change the priority from Error (2) to Information (5)
  6. With the rule still selected, click the Edit rule... button on the right
  7. Change the Message, Description and Example. Click OK when done
  8. Click Export rule set...
  9. Enter a new file name e.g. pmd-rules-customized.xml and click Save
  10. Compare the two XML files - they are different
  11. In Package Explorer right-click on QA Project and select PMD | Clear PMD Violations
  12. In Package Explorer right-click on QA Project and select PMD | Check Code With PMD
  13. Wait for PMD to finish the scan
  14. If PMD Violations view is not open navigate to Window | Show View | Other... and select PMD | PMD Violations
  15. Notice SystemPrintln is now priority 5

Adding New Rules

PMD allows new rules in two formats: Java-based rules where the rule is written as a Java implementation class and XPath rules where the rule is defined in an XML file. Both ways are equally applicable and the choice is probably a matter of preference. This article will demonstrate creating a new rule with both Java and XPath. The rule, ParameterNameConvention, will be a simple coding convention checker making sure all method parameters start with a lowercase "p". To accomplish its task the rule will take advantage of regular expressions and will enforce the following expression to all method parameters: [p][a-zA-Z]+. Later this expression will be made into a rule property which will allow further customization by rule users.
This is all good, but before going any further into the custom PMD rules let's see how this PMD thing actually works.

How PMD works?

PMD relies on the concept of Abstract Syntax Tree (AST), a finite, labeled tree where nodes represent the operators and the edges represent the operands of the operators. PMD creates the AST of the source file checked and executes each rule against that tree. The violations are collected and presented in a report. PMD executes the following steps when invoked from Eclipse (Based on PMD's documentation):
  1. The Eclipse PMD plugin passes a file name, a directory or a project to the core PMD engine (Also part of the Eclipse plugin, however housed in a separate package). This engine then uses the RuleSets as defined in the PMD preferences page to check the file(s) for violations. In the case of a directory or project (multiple source files) the plugin executes the following steps for each file in the set.
  2. PMD uses JavaCC to obtain a Java language parser
  3. PMD passes an InputStream of the source file to the parser
  4. The parser returns a reference of an Abstract Syntax Tree back to the PMD plugin
  5. PMD hands the AST off to the symbol table layer which builds scopes, finds declarations, and find usages
  6. If any rules need data flow analysis, PMD hands the AST over to the DFA layer for building control flow graphs and data flow nodes
  7. Each Rule in the RuleSet gets to traverse the AST and check for violations
  8. The Report is generated based on a list of RuleViolations. These are displayed in the PMD Violations view or get logged in an XML, TXT, CSV or HTML report.
Abstract Syntax Tree
In computer science, an Abstract Syntax Tree (AST) is a finite, labeled, directed tree, where the nodes are labeled by operators, and the edges represent the operands of the node operators. Thus, the leaves have nullary operators, i.e., variables or constants. In computing, it is used in a parser as an intermediate between a parse tree and a data structure, the latter which is often used as a compiler or interpreter's internal representation of a computer program while it is being optimized and from which code generation is performed. The range of all possible such structures is described by the abstract syntax. An AST differs from a parse tree by omitting nodes and edges for syntax rules that do not affect the semantics of the program. The classic example of such an omission is grouping parentheses, since in an AST the grouping of operands is explicit in the tree structure.
Creating an AST in a parser for a language described by a context free grammar, as nearly all programming languages are, is straightforward. Most rules in the grammar create a new node with the nodes edges being the symbols in the rule. Rules that do not contribute to the AST, such as grouping rules, merely pass through the node for one of their symbols. Alternatively, a parser can create a full parse tree, and a post-pass over the parse tree can convert it to an AST by removing the nodes and edges not used in the abstract syntax.
From Wikipedia

PMD Class Hierarchy

Since PMD works on a tree data structure, its unit of operation is Node. Every construct in a Java source file examined by PMD is assigned a node in the Abstract Syntax Tree. These nodes are then visited by all rules in the ruleset and the method public Object visit(SimpleNode node, Object data) of the rule implementation class gets invoked. It is inside this method where the rule logic is defined.
In PMD every node extends net.sourceforge.pmd.ast.SimpleNode. This concrete class implements net.sourceforge.pmd.ast.Node and has 104 first-level children as well as an additional 8 second-level children coming from net.sourceforge.pmd.ast.AccessNode.
This screenshot captures portion of SimpleNodes children. The entire list is available with the source distribution of PMD. This class hierarchy is important for writing custom PMD because each custom rule will rely on one or more of PMD's SimpleNodes to accomplish its task.
This is a good place to see the Abstract Syntax Tree in action.
  1. In Java Perspective, go to Package Explorer and double-click on QA Project and next (default package)
  2. Right-click on Ying.java and select PMD | Generate Abstract Syntax Tree
  3. Click on Window | Show View | Navigator
  4. In Navigator view click on QA Project
  5. The Abstract Syntax Tree file Ying.ast is located in the root level. It should look like this:
    <?xml version="1.0" encoding="UTF-8"?>
    <CompilationUnit beginColumn="1" beginLine="13" endColumn="3" endLine="13">
        <TypeDeclaration beginColumn="1" beginLine="1" endColumn="1" endLine="13">
            <ClassOrInterfaceDeclaration abstract="false" beginColumn="8" beginLine="1" endColumn="1" endLine="13" final="false" image="Ying" interface="false">
                 ...........
                 ...........
      <MethodDeclarator beginColumn="23" beginLine="9" endColumn="67" endLine="9" image="thisIsCutAndPaste" parameterCount="2">
          <FormalParameters beginColumn="40" beginLine="9" endColumn="67" endLine="9" parameterCount="2">
       <FormalParameter abstract="false" array="false" arrayDepth="0" beginColumn="41" beginLine="9" endColumn="53" endLine="9" final="false">
           <Type array="false" arrayDepth="0" beginColumn="41" beginLine="9" endColumn="46" endLine="9">
        <ReferenceType array="false" arrayDepth="0" beginColumn="41" beginLine="9" endColumn="46" endLine="9">
            <ClassOrInterfaceType beginColumn="41" beginLine="9" endColumn="46" endLine="9" image="String"/>
        </ReferenceType>
           </Type>
           <VariableDeclaratorId array="false" arrayDepth="0" beginColumn="48" beginLine="9" endColumn="53" endLine="9" exceptionBlockParameter="false" image="pFirst" typeNameNode="ReferenceType" typeNode="Type"/>
       </FormalParameter>
       <FormalParameter abstract="false" array="false" arrayDepth="0" beginColumn="56" beginLine="9" endColumn="66" endLine="9" final="false">
           <Type array="false" arrayDepth="0" beginColumn="56" beginLine="9" endColumn="58" endLine="9">
        <PrimitiveType array="false" arrayDepth="0" beginColumn="56" beginLine="9" boolean="false" endColumn="58" endLine="9" image="int"/>
           </Type>
           <VariableDeclaratorId array="false" arrayDepth="0" beginColumn="60" beginLine="9" endColumn="66" endLine="9" exceptionBlockParameter="false" image="pSecond" typeNameNode="PrimitiveType" typeNode="Type"/>
       </FormalParameter>
          </FormalParameters>
      </MethodDeclarator>
                 ...........
                 ...........
            </ClassOrInterfaceDeclaration>
        </TypeDeclaration>
    </CompilationUnit>
This AST report gives a full synopsis of the examinee, in this case Ying.java. It is possible for example to gain insight about the method parameter pFirst by expanding the FormalParameter node. Studying this Abstract Syntax Tree can contribute to a better understanding of how a Java source file is examined and what variables play role in the process. This in turn could prove useful when crafting custom rules.

Writing Custom PMD Java Rules

Now, going back to ParameterNameConvention it is time to crank some code. This article will create a Java class for the rule implementation and package it as a plugin fragment. A fragment is an extension of a plug-in and all the classes and resource files it contains are automatically added to the main plug-in classpath. Since PMD searches main plugins classpath for rule implementation classes the fragment will be automatically available. In addition, this structure will allow for faster development and easier distribution.

Creating the plugin fragment in Eclipse

  1. In Eclipse Navigate to Window | Open Perspective | Other...
  2. Select Plug-in Development
  3. In Package Explorer right-click and select New | Project...
  4. In the New Project wizard select Plug-in Development | Fragment Project and click Next
  5. Enter a project name of your liking, e.g. com.jacoozi.pmd.rules and click Next
  6. In the Fragment Content dialog enter details for the fragment and the host plug-in. Click Browse... to locate the host plugin.
  7. In the Plug-in Selection dialog type net.sourceforge.pmd.eclipse then select the only item in the list. Click OK
  8. Back in the Fragment Content dialog select Greater or Equal for Match Rule. This will ensure that future upgrades to the host PMD plug-in do not affect the fragment. The dialog should look like the following:
  9. Click Finish

Implementing the rule class

  1. In Package Explorer right-click on the source folder src and select New | Class
  2. Enter a package name of liking, e.g. com.jacoozi.pmd.rules
  3. Enter the class name ParameterNameConvention
  4. Click Finish
  5. Paste the following code into the new Java class:
    package com.jacoozi.pmd.rules;
    
    import java.util.Iterator;
    
    import net.sourceforge.pmd.AbstractRule;
    import net.sourceforge.pmd.RuleContext;
    import net.sourceforge.pmd.RuleViolation;
    import net.sourceforge.pmd.ast.ASTFormalParameter;
    import net.sourceforge.pmd.ast.ASTMethodDeclaration;
    import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
    
    /**
     * @author Levent Gurses
     * Copyright 2005 Jacoozi
     */
    public class ParameterNameConvention extends AbstractRule {
     private final static String PATTERN = "[p][a-zA-Z]+";
    
     public Object visit(ASTMethodDeclaration node, Object data) {
      RuleContext result = (RuleContext) data;
      String rulePattern = (!getStringProperty("rulePattern").equalsIgnoreCase("")) ? getStringProperty("rulePattern") : PATTERN;
      if (node.containsChildOfType(ASTFormalParameter.class)) {
       Iterator iterator = node.findChildrenOfType(ASTFormalParameter.class).iterator();
       while (iterator.hasNext()) {
        ASTFormalParameter element = (ASTFormalParameter) iterator.next();
        Iterator decIdIterator = element.findChildrenOfType(ASTVariableDeclaratorId.class).iterator();
        while (decIdIterator.hasNext()) {
         ASTVariableDeclaratorId decElement = (ASTVariableDeclaratorId) decIdIterator.next();
         if (!decElement.getImage().matches(rulePattern)) {
          
          result.getReport().addRuleViolation(new RuleViolation(this,
            node.getBeginLine(), "Parameter '" + decElement.getImage() + "' should match regular expression pattern '" +
            rulePattern + "'", result));
         }
        }
       }
      }
      return result;
     }
    }
    Couple of points here. First, notice it extends import net.sourceforge.pmd.AbstractRule. All custom rules must extend this class. Second, notice the AST traversal starts from the method declaration. It then iterates through its children and looks for ASTFormalParameter. Finally, it compares thenode.getImage() against the rule regular expression. Notice that a mismatch causes the creation of a new RuleViolation. As a side note, notice also the regular expression is fed into the rule as a property.

Testing the new rule

The rule class is now complete and there are no compilation errors (red Xs). This means it is ready for testing.
  1. In Plug-in Package Explorer right-click on com.jacoozi.pmd.rules and select Run As | Eclipse Application (Alt+Shift+X,E). Alternatively, to launch a Debug session click on Run | Debug As | Eclipse Application (Alt+Shift+D,E)
  2. Eclipse will launch a fresh instance to test the new PMD rule. In Package Explorer right-click and select Import... | Existing Project into Workspace. Click Next
  3. In Import Projects click Browse to locate the QA Project. Navigate to C:\Documents and Settings\[Your name]\workspace and click OK. This assumes you created the QA Project in Eclipse's default workspace. If not, locate the project in your custom workspace.
  4. Check the QA Project and click Finish
  5. Select Window | Preferences... | PMD | Rules configuration
  6. Click Add rule..., fill the form with the following and click OK
    Rule name:ParameterNameConvention
    Rule implementation class:com.jacoozi.pmd.rules.ParameterNameConvention
    Message:Method parameters should begin with a lowercase "p"
    Description:Method parameters should always begin with a "p". This is equivalent to the parameters complying with regular expression [p][a-zA-Z]+. This expression can be changed the preferences page by adding a property "rulePattern".
    Example:
    public void bringItHome( String pName, int pNumber, boolean pDoneThat, List pTr)
  7. Change rule priority to Error high
  8. Click on Add property... and enter rulePattern as name and [p][a-zA-Z]+ as value.
  9. Click on OK and agree to rebuild.
  10. In Package Explorer right-click on QA Project and select PMD | Check Code with PMD. Open the PMD Violations view. It should display threeParameterNameConvention violations in Yang.java.

Packaging and distributing the new rule

What happens if you want to share a rule with colleagues or make it a common convention for the team? Simple. The fragment project can be exported as a zip file making it easy to distribute. First, export the fragment project; next unzip the file into Eclipse's plugins folder and it's done.
  1. In Plug-in Package Explorer right-click on com.jacoozi.pmd.rules and select Export... | Deployable plug-ins and fragments
  2. Enter a name for the zip file, e.g. com.jacoozi.pmd.rules and click Finish. Eclipse will export the fragment classes into a new archivecom.jacoozi.pmd.rules.zip.
  3. Export ruleset. In PMD Preferences page Click Export rule set.... Zip this file and the fragment zip from previous step together. The portable plugin fragment is now ready for distribution.

Installing the new rule

What happens if you want to share a rule with colleagues or make it a common convention for the team? Simple. The fragment project can be exported as a zip file making it easy to distribute. First, export the fragment project; next unzip the file into Eclipse's plugins folder. That's pretty much it.
  1. Unzip the archive to the target machine. If the target environment uses default Eclipse settings, unzip the file under C:\eclipse (The zip file contains a folderplugins)
  2. Navigate to PMD Preferences page and click Import rule set.... Select the ruleset file from previous step and click OK
  3. Click OK to close the Preferences page.
The new rule is now ready for use.

Writing Custom PMD XPath Rules

The second way to add custom rules to PMD requires some XPath knowledge. XPath has been out for some time now and has proven to be an effective query language for DOM-based XML. Detailed XPath would fill an entire book, therefore for the sake of time and space it is left out. The following Wikipedia definition provides a basic idea of what the language is all about.
XPath
XPath (XML Path Language) is a terse (non-XML) syntax for addressing portions of an XML document.

Originally motivated by a desire to provide a common syntax and behavior model between XPointer and XSL, XPath has rapidly been adopted by developers as a small query language.

The most common kind of XPath expression (and the one which gave the language its name) is a path expression. A path expression is written as a sequence of steps to get from one set of nodes to another set of nodes. The steps are separated by "/" (i.e. path) characters. Each step has three components:
  • Axis Specifier
  • Node Test
  • Predicate
The notation is compact, allowing many defaults and abbreviations for common cases.

The simplest kind of path expression takes a form such as /A/B/C, which selects C elements that are children of B elements that are children of the A element that forms the outermost element of the document.

XPath syntax is designed to mimic URI (Uniform Resource Identifier) syntax or file name syntax. More complex expressions can be constructed by specifying an axis other than the default child axis, a node test, other than a simple name, or predicates, which can be written in square brackets after each step. For example, the expression /A/B/following-sibling::*[1] selects all elements (whatever their name) that immediately follow a B element that is a child of the outermost A element.
From Wikipedia
What is needed here is a way to implement ParameterNameConvention as an XPath rule. The chief advantage of XPath rules in PMD is the power, elegance and simplicity of XPath compared to Java. The main disadvantage is that not many people are familiar with XPath. With that being said, let's see how much time XPath can actually save.
  1. To save confusion, first remove the Java ParameterNameConvention from Eclipse. Navigate to Window | Preferences... | PMD | Rules configuration
  2. Scroll-down the list and select ParameterNameConvention. Click Remove rule
  3. Now, create the new XPath rule. In PMD Rules configuration dialog click Add rule...
  4. This time check XPath rule. The rule implementation class will automatically change to net.sourceforge.pmd.rules.XPathRule. Fill the rest of the form with the following:
    Rule name:ParameterNameConvention
    Message:Method parameters should begin with a lowercase "p"
    Description:Method parameters should always begin with a "p".
    Example:
    public void bringItHome( String pName, int pNumber, boolean pDoneThat, List pTr)
  5. Change rule priority to Error high
  6. Click on Add property... and enter xpath as name and //FormalParameter/VariableDeclaratorId[not (starts-with(@Image, 'p'))] as value.
  7. Click on OK and agree to rebuild.
  8. In Package Explorer right-click on QA Project and select PMD | Check Code with PMD. Open the PMD Violations view. It should display threeParameterNameConvention violations in Yang.java.
That's it. The whole rule takes a single line:
//FormalParameter/VariableDeclaratorId[not (starts-with(@Image, 'p'))]
This one-line XPath rule tells PMD to watch for method parameters whose VariableDeclaratorId name ('Image') does not start with a "p". Very elegant.
XPath-based PMD rules offer an efficient alternative to Java-based rules. As more development tools become XPath-compatible it is likely that an investment in this powerful query language will prove valuable for Java developers.

Wish List

I must admit, I am impressed by PMD's capabilities. It has proven itself as a production grade tool, capable of handling large volumes of Java source files. There are couple of things I wish PMD had. The list below is dedicated to what's missing or can be improved.
  • Add better filtering capabilities to the PMD Violations view. For example add pagination, an important feature when working on large projects. Similarly, improve memory management - large projects may cause the environment to run out of memory.
  • Improve code checking capability by adding advanced query options. For example, add ability to check for a specific rule violation. Support by generating reports for specific rule violation or other more advanced search queries.
  • Move the report generation context menu from the project menu into the PMD Violations view. Support this functionality with advanced filters so that generated could reports include a subset of the violations and not be limited to the entire set.
  • Simplify the rule addition process. Today, Java rules are a bit of a complication to add. Create a WEB-INF-type folder under the core plugin where the classloader would monitor for custom rule implementation classes. This would free developers from having to create plugin fragment projects and a single rule class would be sufficient.
  • Since XPath is such a powerful and efficient way to add custom rules, use AST trees generated from source files to visually guide developers while creating XPath queries. This would help people with little or no XPath experience to begin writing custom rules faster. Alternatively, create an XPath based visual AST editor for Eclipse.
  • Improve the PMD Preferences page. Add multi-line support for Rule properties - important when adding XPath rules.

Summary

There is little doubt that code quality is becoming a prime factor in today's software economy. Many companies are taking real steps to transform old-fashioned, paper-based and in many cases simply ineffective QA practices into modern, efficient, value-added software lifecycle practices. In this path, they are realizing the power of software as a tool to check, correct and improve itself. And a new breed of automated code analyzers is slowly emerging. Designed to free developers from repetitive and error-prone manual code checks, these software "robocops" take the burden from developers, thus enabling them to spend more time on real design and performance issues such as patterns and multithreaded execution.
Automated code analyzers are not meant to replace manual QA. Instead, they should be used in tandem with well-designed manual review processes. Research shows that companies using automated QA tools with paperless, manual QA gain competitive advantage by considerably reducing software maintenance costs. This reduction comes mainly from lower number of defects and less time spent on each defect.
PMD and Eclipse are two great tools for improving personal code quality as well as implementing a consistent company-wide coding convention. PMD operates by applying a set of rules to source files. It comes with a rich suite of rules which can be extended in two ways. The traditional way of adding new rules to PMD is by implementing the rule class in Java and then adding it to the plugin's classpath. PMD has recently added XPath support for custom rules. XPath helps PMD take advantage of the fact it operates on an XML-based Abstract Syntax Tree. Compared to Java rules, XPath rules are much shorter and look way cooler. XPath is a powerful XML query language capable of small wonders. The elegance and beauty of XPath makes it a great choice for developing custom PMD rules.

References

System Information

  • Windows 2000
  • Eclipse 3.1.0
  • JDK 1.4.2_04
  • PMD - pmd-eclipse-3.1
  • XPath 2.0