Stacktrace

Sida 1 av 2312345...1020...Sista »

När man skapar en ny EC2 instans på AWS och väljer AMI’n Amazon Linux AMI, så kommer den med Open JDK 7. Det känns ju lite 2010, man vill ju gärna köra Java 8. Nedan följer några enkla instruktioner hur man kan gå tillväga för att installera Sun JDK 8 på sina nya, fräscha EC2-instans:

1. Börja med att ladda ner den senaste version (i skrivande stund JDK-8u5)


$ wget --no-cookies --header \
"Cookie: gpw_e24=xxx;oraclelicense=accept-securebackup-cookie;" \

http://download.oracle.com/otn-pub/java/jdk/8u5-b13/jdk-8u5-linux-x64.rpm

2. Installera


$ sudo rpm -i jdk-8u5-linux-x64.rpm

3. Konfigurera så att Sun JDK 8 blir default för java-kommandot


$ sudo /usr/sbin/alternatives --install \
/usr/bin/java java /usr/java/jdk1.8.0_05/bin/java 20000
$ sudo /usr/sbin/alternatives --config java

4. Verifiera att ändringarna har tagit


$ java -version

Till byggmiljön Jenkins finns flertalet kraftfulla plugins för att underlätta kodunderhåll och kvalitetskontroll, bland annat PMDFindbugsDRY och Checkstyle som tillsammans blir en bra kombination för automatisk genomlysning av kodbasen. En hel del av varningarna som kommer att uppstå vid första bygget är Controversial Rules. Som benämningen tydligt uttrycker så är de inte självklara och det uppstår ofta en diskussion inom teamet ifall de ska vara kvar eller ej. De går i slutänden att konfigurera bort och det brukar ta några dagar eller någon vecka innan mängden varningar stabiliseras.

Ibland skapas dock varningar som är felaktiga (false positives). Men hur tas en varning bort som är felaktig? Vanliga @SuppressWarnings går att använda om man medvetet vill dölja en typ av fel för PMD, men annoteringen sker på metodnivå och påverkar hela metoden. Specifika PMD-varningar går också att eliminera med kommentaren // NOPMD som då påverkar enbart den givna förekomsten.

För en hel metod eller på klassnivå kan en varning filtreras bort med @SuppressWarnings("PMD.[FILTERNAMN]"). Filternamnet finns i rapporten för varje klass. Gå in på statussidan för bygget i Jenkins och sedan vidare via grafen till statusrapporterna där varje klass med varningar listas, klicka på klasslänken i rapporten och lägg muspekaren över den lilla varningstriangeln. Textrutan som nu visas innehåller en kolumn som kallas Class vilket är samma som filternamnet.

PMD_FilterName

För att dölja den här varningen, lägg till:

@SuppressWarnings("PMD.ConfusingTernary")
private void methodWithWarning() {...

För att enbart ta bort  den här specifika förekomsten (på radnivå) och låta PMD härja fritt i resten av metoden, lägg till // NOPMD i slutet av raden. Att bara lägga till NOPMD kan vara kryptiskt för andra utvecklare och en enkel förklaring efter flaggningen underlättar och visar att varningen är medvetet eliminerad. Exempel:

for (final String part : parts.keySet()) { // NOPMD Key is needed in this loop.
...

Men, det biter inte på Findbugs.

Standardversionen av @SuppressWarnings ger inget stöd för att ta bort Findbugs-varningar, det finns inte heller någon kommentarsfunktion som för PMD för att eliminera varningar. Lyckligtvis är det mer sällan som Findbugs ska filtreras istället för att faktiskt åtgärdas, men det förekommer dock att det kan uppstå falska varningar som kan behöva plockas bort. För att kunna göra det behövs en extern JAR för Findbugs-annoteringar. Om projektet är Maven-baserat, lägg till följande i dependency-kedjan:

    <dependency>
        <groupId>com.google.code.findbugs</groupId>
        <artifactId>annotations</artifactId>
        <version>2.0.3</version>
        <scope>compile</scope>
    </dependency>

Nu finns möjligheten att lägga till en annotering som döljer Findbugs-varningar. Annoteringen vill ha textsträngen justification som också ger en notering till andra utvecklare – och dig själv – att det är ett medvetet val och inte en slentrianmässig bortfiltrering. För att ta bort Findbugs-varningar kan exempelvis @SuppressFBWarnings användas:

@SuppressFBWarnings(value = "WMI_WRONG_MAP_ITERATOR", justification = "The key is needed in the loop")
...

Lycka till med saneringen!

Om man vill använda AutoCloseable i JDK 1.7 och högre ser man ganska snabbt att metoden close kastar Exception:

public interface AutoCloseable {
  void close() throws Exception;
}

Detta gör en inte glad om man vill undvika checked exceptions. En implementation enligt följande:

public class Resource implements AutoCloseable {
  @Override
  public void close() throws Exception {
    //stäng något
  }
}

leder nämligen till att man måste hantera Exception på något sätt i try-blocket:

try(Resource r = new Resource()) {
   //gör något med r
} catch(Exception e) {
  //hantera e som vi inte ville ha från början
}

Nyckelinsikten här är att man kan overrida metoder som slänger checked exceptions med sådana som inte gör detta (se JLS §8.4.8.3). Just detta omnämns även i dokumentationen till AutoCloseable.html#close(). Så vi kan implementera utan att slänga exceptions:

public class Resource implements AutoCloseable {
  @Override
  public void close() {
    //stäng något
  }
}

Detta gör att vi kan ha en try utan checked-exception hantering:

try(Resource r = new Resource()) {
   //gör något med r
}

Mission accomplished.

EDIT:
Tack till Mats Andersson som påpekade att man kunde ta bort throws-deklarationen helt istället för att kasta ett mer specifikt fel (RuntimeException).

Neo4j är en NoSQL-databas eller närmare bestämt en grafdatabas. Det är en javabaserad open source-produkt och utvecklarna bakom Neo4j beskriver den så här:

Embedded, disk-based, fully transactional Java persistence engine that stores data structured in graphs rather than in tables

Detta inlägg beskriver kort några av de features som Neo4j erbjuder och en kortare introduktion till frågespråket Cypher som används för att hitta rätt i grafen.

Läs mer >>

För att minska på fingerslitaget vid inloggning till flera maskiner på olika domäner via SSH kan man nyttja resolv.conf och .ssh/config. Med hjälp av dessa kan man sätta default-användarnamn och även undvika att skriva olika användarnamn för olika domäner.

I det tänkta scenariot har du fått ett login på en subdomän hos företaget example.com. Användarnamnet är ett annat än ditt normala login och du behöver logga in på flera servrar, så många att det blir opraktiskt att lista alla i .ssh/config. Målet med setupen är att istället för att behöva skriva:

ssh exampleuser@exampleserver0.long.subdomain.example.com

och

ssh exampleuser@exampleserver1.long.subdomain.example.com

bara kunna skriva följande:

ssh exampleserver0

och

ssh exampleserver1

För att undvika att behöva skriva hela domännamnen lägger vi till en search-entry i resolv.conf. I Debian genereras resolv.conf av programmet resolvconf, så därför editerar vi istället /etc/resolvconf/resolv.conf.d/base och lägger till raden:

search long.subdomain.example.com

Du kan sedan generera om resolv.conf med kommandot ”resolvconf -u”. Detta gör att du kan ansluta till servrarna utan att ange hela domännamnet, dvs att du kan ansluta med t.ex:

ssh exampeluser@exampleserver0

För att knyta det avvikande användarnamnet till denna subdomän använder vi oss sedan av .ssh/config där vi lägger till raderna:

Host exampleserver*
  User exampleuser

På detta sätt har vi nått vårt mål. Dock väljs användarnamnet ”exampleuser” så fort ett hostname börjar på ”exampleserver”. Varför gjorde vi så? Jo, det visar sig att .ssh/config-entries inte matchas mot fulla domännamn, utan endast mot argumentet som ges till ssh (se ‘canonicalized host name’ i ssh_config).

På grund av denna begränsning måste vi använda mönstermatchning på endast hostnamnet. Om hostnamnen inte skiljer på ett sådant sätt att mönstermatchning lämpar sig är ett ett annat sätt att komma runt detta att matcha mot del-domäner. Genom att till exempel konfigurera resolvconf med:

search subdomain.example.com

kan du konfa ssh med:

Host *.long
  User exampleuser

Observera att denna lösning gör att du får logga in till servrarna med:

ssh exampleserver0.long

och

ssh exampleserver1.long

Om man driftar sitt eget Git-repo (och därmed saknar det inbyggda stödet i t.ex. GitHub och BitBucket) är det enkelt att lägga in kopplingar (hooks) så att ett bygge automatiskt startas vid commit. På så sätt kan man undivka att byggservern kontinuerligt måste polla repot efter förändringar. Detta är framför allt till stor nytta om man vill ha en snabbare återkoppling mellan incheckning och automatiska tester m.m.

Nedan visar jag hur man automatiskt kan trigga två olika typer av Jenkins-byggen från Gits post-receive hook. När en git-tag pushas upp triggas ett parametriserat release-bygge och när ett gren-huvud uppdateras triggas ett vanligt dev-bygge.

I det första fallet triggas bygget direkt. I det andra fallet säger vi till Jenkins att det är dags att polla repot för ett visst jobb. Man kan ju naturligtvis tänka sig att även dev-byggen är parametriserade byggen, men detta var vad som behövdes när jag skrev hooken.

Alla som jobbar med serverapplikationer i Java har väl någon gång stött på behovet av en connection pool. Länge var Apache DBCP den dominerande poolen, eventuellt med c3p0 som alternativ. Båda dessa har sina egna mer eller mindre obskyra problem.

För en del år sedan dök det så upp en ny pool, som helt enkelt heter JDBC Connection Pool. Den ingår numera som en modul i Tomcat, är betydligt modernare än sin föregångare och den skall fungera med alla containrar (Tomcat, Jetty, JBoss etc). Den har dessutom en hel uppsjö inställningar, skall fungera bättre på multi-core-maskiner och är enklare i sin interna uppbyggnad än DBCP. Så här ser Maven-beroendet ut just nu:

&lt;dependency&gt;
   &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;
   &lt;artifactId&gt;tomcat-jdbc&lt;/artifactId&gt;
   &lt;version&gt;7.0.26&lt;/version&gt;
&lt;/dependency&gt;

Ett vanligt problem med databaskopplingar är connections som ”dör” på olika sätt. Routrar och brandväggar konfigureras ibland så att kopplingar bara får ha en viss livslängd, och samma sak gäller databasservrar – och så har vi ju ibland helt vanliga nätverksproblem också. Det traditionella sättet att lösa det på är att använda en så kallad ”validation query”. Det innebär att connection-poolen, t.ex. innan den delar ut en connection från poolen, skickar en testfråga till databasen, t.ex. SELECT 1. Exakt vilken fråga som är lämplig beror på vilken databas det är, och t.ex. MySQL har en speciell fråga avsedd för detta ändamål.

Min erfarenhet är att detta inte alltid funkar något vidare. Beroende på vilket tillstånd TCP-kopplingen har så kan en sådan fråga hänga sig en lång stund, vilket leder till att poolen svälter. Det man normalt vill uppnå är att poolen bara kastar connections som inte svarar snabbt, och skapar nya i stället. JDBC Connection Pool tillsammans med Java 1.6 har en trevlig lösning på det, och nu börjar vi äntligen närma oss min poäng!

Sedan Java 1.6 finns en metod i java.sql.Connection som heter isValid. Denna låter JDBC-drivern självt avgöra om en koppling kommer att fungera, i stället för att använda mystiska validation queries. Metoden tar som parameter en timeout i sekunder som är separat från övriga timeouts. Detta passar som handen i handsken med en inställning i JDBC Connection Pool som heter validatorClassName. Man sätter validatorClassName till namnet på en klass som man själv implementerar, och poolen anropar den för att kontrollera om en connection får användas, innan den ger ut den till klientkoden. Så här ser min variant på validator-klass ut:

public class JDBCValidator implements Validator {
    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCValidator.class);

    @Override
    public boolean validate(Connection connection, int validateAction) {
        LOGGER.trace(&quot;validate called for connection {}, validateAction = {}&quot;,
                  connection, validateAction);
        try {
            // 10 seconds should do it
            if (connection.isValid(10)) {
                LOGGER.trace(&quot;Connection {} is VALID&quot;, connection);
                return true;
            }
            LOGGER.warn(&quot;Invalid DB connection detected&quot;);
            return false;
        } catch (SQLException e) {
            LOGGER.warn(&quot;Invalid DB connection detected&quot;, e);
            return false;
        }
    }
}

Tack vare loggningen så får man stenkoll på hur databasen och nätet verkar agera, och det funkar dessutom varje gång!

Under några månaders tid har jag stört mig på att Ubuntu återställer tangentbindningar som jag gjort när datorn bootas om. T.ex. så krockar Ubuntus Alt+F7 Move Window med Intellijs IDEAs find. Det verkar vara en bug i 12.10 och 13.04 som introducerade detta.

Som temporär lösning på problemet har jag lagt följande i filen $HOME/.gsettings som jag sedan läser in i $HOME/.bashrc (tidigare skrev jag att man kunde lägga inläsningen i .profile istället, men det verkar som att Ubuntu återställer gsettings efter att .profile körts).

# Check what bindings are available
# gsettings list-recursively  |grep key|less

gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-left "['<Shift><Control><Alt>Left']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-right "['<Shift><Control><Alt>Right']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-up "['<Shift><Control><Alt>Up']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-down "['<Shift><Control><Alt>Down']"

gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['<Control><Super><Alt>Left']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-right "['<Control><Super><Alt>Right']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-up "['<Control><Super><Alt>Up']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-down "['<Control><Super><Alt>Down']"

gsettings set org.gnome.settings-daemon.plugins.media-keys screensaver '<Super>l'
gsettings set org.gnome.desktop.wm.keybindings begin-move "['<Super>F7']"
gsettings set org.gnome.desktop.wm.keybindings begin-resize "['<Super>F8']"
gsettings set org.gnome.desktop.wm.keybindings show-desktop "['<Super>d']"

gsettings set org.gnome.desktop.wm.keybindings toggle-shaded "['disabled']"
if [ -f "$HOME/.gsettings" ]; then
    . "$HOME/.gsettings"
fi

Som nyexad webbprogrammerare var det inte helt lätt att slänga sig in i certifieringsdjungeln. Det var många nya begrepp och ofta förstod jag varken frågorna eller förklaringarna när jag först började läsa. Även om jag hade haft Java som huvudspråk under min utbildningen var jag inte så van vid att prata om språket och jag hade definitivt inte ställts inför frågor om regler på hur saker och ting fungerar beroende på om man gör si eller så. Vissa klasser och metoder hade jag inte stött på tidigare och då blev de kodexempel, som egentligen skulle underlätta, ett hinder mer än ett hjälpmedel. Men skam den som ger sig… nu har jag min Java Programmer-certifiering. Det här är mina tips för hur du lyckas! Läs mer >>

Vagrant är ett verktyg för att på ett smidigt sätt via kommandoraden kunna hantera olika virtuella boxar (Oracle VirtualBox). Vagrant används för att skapa och konfigurera lättviktiga, reproducerbara och portabla utvecklingsmiljöer.

Grundkrav

Sätt igång

Då är vi redo att börja. För att skapa en ny virtuell box med Ubuntu 12.04 LTS kör du bara följande kommandon:

$ vagrant box add precise64 http://files.vagrantup.com/precise64.box
$ mkdir -p testenv
$ cd testenv
$ vagrant init precise64
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Kommandot på rad 1 laddar ned en färdig box med Ubuntu 12.04 LTS. Denna box namnges till precise64 och kan sedan återanvändas för flera virtuella maskiner. Nedladdning sker endast en gång. Rad 2 och 3 skapar en katalog där din virtuella maskin sparas. Kommandot på rad 4 skapar en så kallad Vagrantfile som beskriver hur just din box ska konfigureras (bland annat port forwarding). Vagrant själva skriver att:

A Vagrantfile is to Vagrant as a Makefile is to Make

Innehållet i vår nyskapade Vagrantfile ser ut ungefär så här:

Vagrant::Config.run do |config|
  # Setup the box
  config.vm.box = "precise64"
end

Den katalogen som innehåller Vagrantfile mappas (per default) upp som en shared folder så din maskin och den virtuella boxen kan dela filer där på ett smidigt sätt.

För att sedan starta vår virtuella server används följande kommando:

$ vagrant up

Och för att koppla upp dig via SSH mot servern körs detta kommando:

$ vagrant ssh

När du kopplat upp dig via SSH kan du accessa dina delade filer i foldern /vagrant

Om du gör förändringar av din virtuella box som du sedan vill återanvända kan du skapa egna paket (boxar) som du senare kan utgå från. Detta sker enkelt via kommandot:

$ vagrant package

Då skapas en box – package.box – som kan läggas till bland dina befintliga boxar med hjälp av

$ vagrant box add my_box /path/to/package.box

När du känner att du är färdig med din virtuella box kan du använda följande kommando för att stänga ned maskinen (och därmed spara CPU/RAM):

$ vagrant halt

Alternativt, om du bara vill göra en suspend (det går snabbare att starta maskinen senare isf):

$ vagrant suspend

För att starta maskinen efter halt eller suspend är det bara att köra:

$ vagrant up

Om du vill ta bort din virtuella box från disken helt och hållet kör du bara kommandot:

$ vagrant destroy

Vagrant erbjuder också stöd för mer avancerade features såsom provisioning mha Chef eller Puppet. Allt detta finns att läsa på Vagrants hemsida.

Så, superenkel hantering av virtuella boxar med hjälp av Vagrant – rekommenderas varmt!

Lathund:

$ vagrant init Skapar en Vagrantfile
$ vagrant up Startar en virtuell box
$ vagrant halt Stoppar den virtuella boxen
$ vagrant suspend Pausar den virtuella boxen
$ vagrant destroy Stoppar och tar bort den virtuella boxen från disken
$ vagrant package Skapar ett nytt box-paket baserat på en befintlig box
$ vagrant box add my_box /path/to/package.box Lägger till en ny box-typ (my_box) som pekas ut via path eller HTTP
$ vagrant box list Listar tillgängliga boxar för din lokala miljö. En lista över boxar nedladdningsbara boxar finns här.
Sida 1 av 2312345...1020...Sista »