sonar plugins and why i had to fork the sonar web plugin to add a rule

Last weekend, a few of the CodeRanch moderators were discussing a Trac item that we’d like to get rid of the I18N messages from our HTML. It’s there at all because open source JForum had it. We haven’t been updating it and have been using it inconsistently. Also, we do want to externalize the ones in Java which is why we can’t just get rid of the file wholesale – someone could add more references from HTML. I suggested that this would be a good thing to set up a SonarQube rule and volunteered to create the rule. This was a far harder and more interesting task than I expected it to be when I said I’d do it.
webProps

The web plugin scans HTML files and has a bunch of pre-defined rules and templates for them. You can set any file extensions you’d like so I had set “.html,.html,.ftl” in Administration > Configuration > Web to hit both our HTML and Freemarker code. Alternatively, you can set this in your Sonar properties file.

Looking through the rules and rule templates in the web plugin, there wasn’t one for what I wanted – plain String or regular expression search. Nuts! There are a few existing rules that do what I want, however I couldn’t use them:

Rule Why can’t use
Some Java packages or classes should not be used in JSP files In web plugin, but only for jsp/jsp files
Disallowed methods should not be allowed In Java plugin so only works for Java code
XPath rule Only works for XML files
The text plugin regular expression rule So close! This does exactly what I need. Except (see next section)

Great, the text plugin meets my needs. But alas. You can only associate a file extension with one plugin for each Sonar run. The HTML/Freemarker files are already considered web files.

So what’s wrong with the text plugin?

The text plugin has a rule called “Simple Regex Match”. When configured with the proper regular expression, it does exactly what I want. Except for one huge problem. In order to use it, I have to associate the text plugin with HTML/Freemarker files. This is a two step procedure:

  • In the browser, Administration > Configuration > Web – set the web extensions to “foo”. Leaving it blank is insufficient as it defaults to include HTML and Sonar does not let the same file extension be associated with multiple plugins.
  • In sonar-project.properties, add the line: sonar-text-plugin.file.suffixes=.htm,.html,.ftl

You also have to run sonar-runner twice. Once with the HTML/Freemarker files associated with the web plugin to get those results and again with them associate with the text plugin to get the rule I’m trying to write. This means you need to have the code show up as two projects within SonarQube. (otherwise Sonar will tell you the rule violations were fixed for whichever analysis you run last.)

Extending the web plugin

Ok. I clearly need to extend the web plugin so that I can have a regular expression rule associated with the web plugin. The docs say the web plugin doesn’t support extending it with Java or XPath rules as does this post. I tried anyway hoping this was out of date. I was able to get my new rule to show up in Sonar, but not to run. Everything I’d need to do in order to get it to run was considered a duplicate and prevented Sonar from even starting up. For example, “org.sonar.api.utils.SonarException: Can not add the same measure twice” or “duplicate keys not allowed”. So I concede this path is a non-starter. It would have been nice to have my custom rule in a separate Maven project rather than having to fork the existing one.

Forking the web plugin

Sigh. Last resort. Time to fork. This newsgroup post pointed to a commit that shows how to add a rule to the web plugin. I wanted to add a rule template rather than a rule, but the idea is the same. It wasn’t hard to make the change within the project. It’s just that forking isn’t good in the long run as I’ll have to keep re-merging. What I needed to change in my fork:

  1. Add custom rule template class to org.sonar.plugins.web.checks.coding package. The code was pretty similar to the rule for illegal spaces:
    package org.sonar.plugins.web.checks.coding;
    
    import java.io.IOException;
    import java.nio.charset.Charset;
    import java.util.List;
    
    import org.sonar.api.utils.SonarException;
    import org.sonar.check.Priority;
    import org.sonar.check.Rule;
    import org.sonar.check.RuleProperty;
    import org.sonar.plugins.web.checks.AbstractPageCheck;
    import org.sonar.plugins.web.checks.RuleTags;
    import org.sonar.plugins.web.node.Node;
    import org.sonar.plugins.web.visitor.CharsetAwareVisitor;
    import org.sonar.squidbridge.annotations.NoSqale;
    import org.sonar.squidbridge.annotations.RuleTemplate;
    
    import com.google.common.io.Files;
    
    @Rule(
      key = "RegularExpressionNotAllowedOnLineCheck", 
      name = "Regular expression \"regex\" not allowed on web page", 
      priority = Priority.MAJOR, tags = {
      RuleTags.CONVENTION })
    @RuleTemplate
    @NoSqale
    public final class RegularExpressionNotAllowedOnLineCheck extends AbstractPageCheck implements CharsetAwareVisitor {
    
    	@RuleProperty(
          key = "regex", 
          description = "Single line regular expression to prohibit on web pages")
    	public String regex = "";
    	
    	private Charset charset;
    
    	@Override
    	public void setCharset(Charset charset) {
    	   this.charset = charset;
    	}
    
    	@Override
    	public void startDocument(List<Node> nodes) {
    		List<String> lines;
    		try {
    			lines = Files.readLines(getWebSourceCode().inputFile().file(), charset);
    		} catch (IOException e) {
    			throw new SonarException(e);
    		}
    		for (int i = 0; i < lines.size(); i++) {
    			// only support matching text within a single line to facilitate identifying line number
    			if (lines.get(i).matches("^.*" + regex + ".*$")) {
    				createViolation(i + 1, "Replace all instances of regular expression: " + regex);
    			}
    		}
    	}
    
    }
    
  2. Add the rule template to org.sonar.plugins.web.rules.CheckClasses so the web plugin knows about.
  3. Create a new HTML file in the resources localization directory.
  4. Write/update tests. I like that the sonar-web-plugin project uses JUnit tests to enforce some of there conventions like rules ending in “Check”.

Where is the code?

I’ve placed my fork on Github. It’s 2.5-SNAPSHOT because I didn’t see any need to version it. I also created a pull request for the sonar-web-plugin in hopes they are interested in merging it. The plugin was last released a year ago so I imagine I’ll be using my fork for along the foreseeable future in any case. Which is fine. CodeRanch is a volunteer run website so no rules against using forked software.

why the paperless office doesn’t work for everyone

For years, we’ve been hearing about how the paperless office is the future. Now that we have tablets, the future has clearly arrived. Quick. Throw out the paper. Actually, hold on for a second.

Different people have different work styles. For some, a paperless office is great. For others, not so much. Let’s look at a few valueable uses of paper.

Notes while coding
Personally, I like to make notes while coding. Ideas of things I still need to do. Stray thoughts. Anything. This is very transient information.

Some I could put into //TODO s in Eclipse. Some are better free form. Some are just stray thoughts that I can’t put into Eclipse because I don’t want to break flow.

Manuals
We only have so much screen space. Some things, like the Java Docs, are great to have on screen.

Others, like learning a new technology from a book, can be nice to have on the table next to you. That also allows me to take notes (in the book) while writing.

I’ve seen teammates do the same with “how to” wiki pages they were unfamiliar with.

Proofreading
When I proofread, I do a mix of on my iPad and printed. I try to do a final read on printed paper. I find more errors that way.

I read a study that indicated there is actually some science to this.

Spatial memory
I use where information lies on the page as spatial memory. That way I can train my brain to location and not just data.

For example, when I’m giving a presentation I always print the slides and run through them in my hand. That extra tactial/spatial info helps me retain it better.

To do lists
My “master” to do list has been electronic for years. I do keep micro “to do” lists on paper though.

They are half baked thoughts of things that I am doing today. Or maybe a tiny piece of a task. Or what I am up to when getting up to take a break.

Contingency
What do you do when your laptop freees/crashes? (Thank you Windows. It is 2015 and I still need to have a plan for what to do when you freeze.)

I go to my paper at that point while I wait for the computer to get back to me. I can organize my thoughts on paper. Or read something I have printed.

The same holds from when I call the help desk and they are using my computer. I don’t have dead time with some paper around.

Conclusion
I’m not saying everyone needs paper. Just that I think we are a far way from getting of paper completely.

I do try to recycle. I use the backs of paper that served another purpose for my notes. And I print 2 pages to a side in Word or PowerPoint when reviewing. Trying to balance saving trees and productivity.

The e-office of the future is great. Maybe we will get there one day.

playing with scratch

Scratch is an intro programming language for kids. (Like Logo was, but way better). When I saw edx was offering an Intro to Scratch course, I decided to take that opportunity to learn it. It’s cute and a great starting point for programming. It offers the ability to write a really simple program. But it also lets you learn about lists and event handling.

For my final project for the course, I wrote a two player game of tic tac toe. Here’s what jumped out me when doing the project.

Components used

  1. Multiple sprites and event handling (broadcast/wait)
  2. Key and mouse listeners
  3. Functions (custom blocks)
  4. Logic (loops/conditionals)
  5. Lists
  6. Comments

What I missed

As a programmer used to full fledged (non-simplified) programming languages and environments, there are a few things I missed.

  1. Real 2D arrays. I used a string in a 1D array and getting the character at each position.
  2. Grouping parens. I wanted to write something equivalent to (a==b and b==c) or (d==e and e=f)). While this possible to do in Scratch, it uses the layering of blocks rather than parens so is hard to read. I wound up splitting into two if statements.
  3. Local variables. There are “sprite only” variables, but they still clutter up the namespace and make it hard to find the variable you need at a given point.
  4. elsif/elseif. Yes, you can nest if/else statements. But harder to read.
  5. I didn’t work on the program for two weeks and went back to it. I really wanted “search” functionality to find uses of a variable or where a custom block was defined.
  6. I miss having rollback/history for changes. When the program “used to work” and then doesn’t, it’s hard to figure out what you accidentally drag and dropped.

 

Other interesting points

  1. Scratch uses 1 based indexes. Makes sense for a first language to break with the odd tradition practically ever other language uses. But feels weird.
  2. There is no distinction between character and numeric types. This meant I could get a character out of a string and use it as a loop index.
  3. Regular mode and turbo mode allows you to control the speed the sprites draw. This is useful when drawing things like circles. When coding, turbo mode is enabled with Edit > Turbo Mode. When in the play view, it is enabled by holding shift when pressing the green flag to start. I wish there were a way to either “save” with turbo mode or turn turbo mode on in the code.
  4. There are blocks for length of on list and and operator/string. Calling the wrong length block on a list doesn’t fail, but does return unexpected data.

Refactoring?

  1. I have some duplication in drawO vs draw X and if statements when drawing the grid. I could put in variable but didn’t feel like it was clearer that way. Similarly in calculating if the a player won.
  2. I also have duplication in “when I receive move” if statements. I got lazy when drawing the line.