On 2008-08-28

  • still waiting for the maglev presentation #
  • watching maglev presentation #

Utility classes en default constructors

Checkstyle heeft standaard een warning als je een utility class, een class met alleen static methods, hebt waarvan je een nutteloze instantie kan maken. De oplossing is dan om een private default constructor te maken. Ja, java kent geen modules dus de "nette" manier om van een class een module te maken is door er een stukje "unreachable" code in te plaatsen. Alsof je niet al voldoende code moet lezen in java.

Anyway, ik doe daar niet aan mee. Ik ga ervan uit dat degene die mijn utility class gebruikt, capabel genoeg is om te zien dat een instantie ervan nutteloos is. Ik bedoel, wat kan er fout gaan? Je maakt een instantie, en vervolgens merk je dat je er niks mee kan. Voordat je op de compile knop drukt heb je de code al weggehaald en de kans dat het in productie code komt is nihil. Het beschermen van de programmeur tegen zichzelf heeft java al lastig genoeg gemaakt (zoals checked exceptions).

Wat nog wel een ander probleem was met een private constructor voor een utility class, is dat cobertura wel de constructor ziet en vind dat deze niet getest is. Je Code Coverage er mee omlaag gaat, en als je op 100% zit is het zonde om dan weer terug te gaan naar 99%. Dan valt de echte niet geteste code minder op.

Maar als je toch de private constructor wilt gebruiken kun je met reflectie toch nog op 100% code coverage komen.

1
2
3
4
5
6
7
8
9
10
11
12
public void testPrivateConstructor() throws
         IllegalAccessException,
         InvocationTargetException,
         InstantiationException {
 
    final Class<?> aClass = Environment.class;
    final Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
    constructor.setAccessible(true);
    final Object n = constructor.newInstance((Object[]) null);
    assertEquals("should have environment instance", 
                          Environment.class, n.getClass());        
}

Of je zet nog meer onzin code in de productie code door een static initializer toe te passen:

1
2
3
{
   new Environment();
}

JRuby to the rescue

Onze applicatie zorgt eens in de zoveel tijd voor een out of swap space error, waardoor tomcat down gaat. De oorzaak van de error is een externe library waar we nog geen oplossing voor hebben. Voor nu willen we dat tomcat automatisch weer opstart als de out of swap space error zich weer voordoet.

Via de pid van het tomcat proces kan ik controleren of het proces nog draait. Hiervoor moet ik wel de CATALINA_PID environment gebruiken, zodat ik de pid uit een bestand kan halen.

Voor het scottie project had ik al iets vergelijkbaars gemaakt met Ruby componenten. Ruby is echter niet geinstalleerd op de Solaris productie omgeving. Om deployment simpel te houden heb ik het geprobeerd met een shell script, maar ik merkte dat ik daarvoor nog te weinig van af wist. Uiteindelijk kon het ook met JRuby. Het enige is dat JRuby zich net wat anders gedraagd dan MRI als het gaat om processen. Waar MRI een exceptie gooit, geeft JRuby een -1 terug.

Het script heb ik eerst geprobeerd als cron job te draaien, maar ik zat dan weer met environment settings die dan ontbraken.

Voor nu heb ik gewoon een loop in de code gemaakt en start ik het script met nohup.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/ruby
class Tomcat
 
  def initialize(pidfile)
    @pidfile=pidfile
  end
 
  def running?
    begin
      Process.getpgid(pid)!= -1
    rescue Errno::ESRCH, Errno::ENOENT
      false
    end
  end
 
  def pid
    File.open(@pidfile) do |f|
      f.gets.to_i
    end
  end
 
  def start
    puts "Starting tomcat"
    `./startup.sh`
  end
 
end
 
@pidfile=ENV["CATALINA_PID"]
if @pidfile.nil?
  puts "CATALINA_PID environment variable not set."
  exit
end
 
tomcat = Tomcat.new(@pidfile)
loop do
  puts "checking"
  tomcat.start unless tomcat.running?
  sleep(30)
end

Ben nog bezig het in gem vorm te gieten en heb het intussen op github geplaatst.