Monday, May 25, 2009

PHP CodeSniffer tips

I really love tools which help my code be more correct and more readable. I have referred to tools like JSLint (JS) and FindBugs (Java) in previous posts and now I am going to write some tips about using PHP CodeSniffer (PHP) (a.k.a. phpcs). It is probably the most aggressive of the three and can be especially tricky on the requirements it puts on your file headers.

Here is a sample file header:

<?php
/**
* Presto - a lightweight REST framework for PHP
*
* Presto is a simple to use and very lightweight REST framework for PHP,
* it will help you to handle rest routing and input/output of data without
* getting in your way
*
* PHP Version 5
*
* LICENSE:
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @category File
* @package Presto
* @author Aaron Zeckoski <azeckoski@vt.edu>
* @copyright 2009 Aaron Zeckoski
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version SVN: $Id:$
* @link https://link/to/your/project/site
* @since inception
*/

A few comments about the header:
  • The copyright cannot have a comma after the year but the year can be a range. "2002-2009 AZ" is ok, "2009, AZ" is not
  • The license should appear inside the header like shown, not above it (this would cause an ERROR in phpcs)
  • The alignment of the data after the tags (e.g. @license, @version) is not optional, misaligned data causes an ERROR
Sample class:

/**
* My class which does some stuff
*
* @category Class
* @package Presto
* @author Aaron Zeckoski <azeckoski@vt.edu>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link https://link/to/the/project/again
*/
class RestController
{
const DEFAULT_RESOURCES_DIR = 'resources';

/**
* This is a method in my class
*
* @param object $_resourcesPath [optional] the resource path
*
* @return void
*/
protected function loadResources($_resourcesPath = self::DEFAULT_RESOURCES_DIR)
{

There are also a few of the rules about classes that caught me out as well:
  • Class methods must use camelCase. myMethodName is good, my_method_name is not
  • Classes MUST have a comment on them and it has to include a lot of the fields from the header. The ones I list in the sample above are the minimum (seriously).
  • The space between @params and @return is not optional
  • Just a note on constants in PHP, you use const inside classes and define outside
Take a look at the sample file and class headers here for more details: http://pear.php.net/manual/en/standards.sample.php

Saturday, May 23, 2009

Open Repositories 09 developer view

I just got back from the Open Repositories 2009 conference in Atlanta, GA, US and wanted to highlight a few things which were interesting to me (from a developer's perspective).
  1. Pluggable (extendable) repository systems
    DSpace 2 was initially designed to support plugins and there were some suggestions which will improve it further. The Eprints team showed off a really cool proof of concept of a plugins store which allows browsing, downloading, and installing from within eprints. The Fedora Commons team indicated interest in using OSGi to manage their services and enable plugin points.
  2. ReST interfaces
    All the major systems have some ReST in place now and are working on having fully restful access available in the fairly near future. I think (and hope) this will lead to more mashup style integrations and easier access to repository data which can only be a good thing.
  3. DuraSpace
    The merging of the DSpace and Fedora Commons communities into DuraSpace is cool because it means 2 teams of great developers will now be one. They also showed off the DuraCloud distributed storage service which is interesting from a scaling and backup perspective.
  4. Developer Repo Challenge
    There were some really cool projects and ideas demonstrated for the repo challenge. My personal favorite was the EprintsAppStore. I also really liked the FedoraFS entry from a technical coolness perspective and MentionIt (the winner) for its simplicity.

Tuesday, May 19, 2009

OSGi system and bundle start levels

OSGi has a concept of start levels. This is fairly well documented in the r4 core spec but there seems to be some confusion around how they work so here is a quick summary for my own reference (and in case it helps anyone else).

Start Levels determine the start order of bundles (not services). There are two types of start levels in an OSGi system. The system start level and the bundle start level (set for each bundle). The default start level of an OSGi system will be 1 (this is called the beginning start level and can be configured) and the bundles installed in an OSGi system will use the default start level when they are installed unless this is changed manually. An OSGi system has a current level (called the active start level) which determines the bundles which are allowed to be started. If a bundle has a start level higher than the active start level it will not start when the OSGi system starts up and it will not start if given a manual start command. If the active start level increases to be greater than or equal to the level of the bundle it will be started. Likewise, if the active start level changes to be below the level of a bundle, it will be shutdown.

Here are a few points about start levels that were not completely obvious to me:
  • The bundles at a given start level will all have their start() method completely executed before any bundles at a higher level are started. Start order within the start level is indeterminate.
  • When the active start level is changed, the system will move in increments of 1 until the desired level is reached. For example, from 5 to 10 means the system will do 6, 7, 8, 9, and finally 10.
  • If the start level is changed many times rapidly it must completely reach all requested levels in sequence. The system will not give up on level 3 if it was requested and has not been reached yet just because level 15 was requested while it was moving to level 3.
  • The system bundle is always located at start level 0. This cannot be changed.
  • Start level should NOT be used as a way to control service startup order. This is considered a programming error in OSGi as service start orders are not guaranteed and services may come and go at will.
  • Start level can be used as a way to reduce load on a system by setting non-critical parts as high start levels. This allows the level to be reduced in order to reduce the load and shutdown non-critical services and bundles.
  • OSGi has a compatibility mode which forces all bundles to use start level 1 (this is a good way to check to make sure you are not depending on the start levels as a way to ensure service start order).
NOTE: If you are working with apache felix 1.6.0 there is a confusing error in the default config file. The system start level property is commented out as org.osgi.framework.startlevel but the correct value is org.osgi.framework.startlevel.beginning.

The OSGi spec (section 8, page 2o3) has more details about start levels.