About Me

Mein Bild
Freelancing software developer / architect, mobile geek. Topics: Software technologies (java, groovy, agile), politics, web, science, green, mobile, android.
Homepage: www.tutaona.com

"The absence of limitations is the enemy of art." - Orson Welles

Dienstag, 19. August 2014

Pretty fonts for Java desktop software under Ubuntu

Pretty fonts for Java desktop software under Ubuntu

I’m an eclipse (Java IDE) user for a long time. As maybe any eclipse user I’d heared from the IntelliJ camp that their IDE should be much better. Great refactoring and completion… But any evaluation I did in the past - and I did it every couple of years - ended up with that I returned to eclipse because IntelliJ seemed to me totally visually ‘noisy’. Tons of colourful icons and ugly fonts under Linux. I could just not stand it.

But suddenly Android’s official IDE is now based on IntelliJ and in my current project I could just not make the darn maven build work under eclipse while the IntelliJ using colleagues were just importing the pom.xml and started working. So back home this veryevening I gave it another chance: Colourful icons were gone but the fonts were still ugly. But after some reserach I found a solution and now IntelliJ looks almost like a native application.

The solution ist a combination of installing the alternative font rendering Infinality and a patched openJDK. Both hacks are described at webup8.org Better Font Rendering In Linux With Infinality and Install OpenJDK Patched With Font Fixes.

The recipe

1) Install Infinality

sudo add-apt-repository ppa:no1wantdthisname/ppa
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install fontconfig-infinality

2) Configure Infinality
Answer question with linux:

sudo bash /etc/fonts/infinality/infctl.sh setstyle

Edit this file, search for USE_STYLE and set it to UBUNTU:

sudo -H gedit /etc/profile.d/infinality-settings.sh

3) Log out and back in again to see the changes

4) Install the patched openJDK

sudo add-apt-repository ppa:no1wantdthisname/openjdk-fontfix
sudo apt-get update
sudo apt-get upgrade

5) Install openJDK (if not installed)

sudo apt-get install openjdk-7-jdk

6) Ensure IntelliJ is using the patched openJDK by adding this line to {IntelliJ install dir}/bin/idea.sh as first line after the file comment.

IDEA_JDK="/usr/lib/jvm/java-1.7.0-openjdk-amd64"

Mittwoch, 13. November 2013

Pretty fonts for Java desktop software under Ubuntu

I'm an eclipse (Java IDE) user for a long time. As maybe any eclipse user I'd heared from the IntelliJ camp that their IDE should be much better. Great refactoring and completion... But any evaluation I did in the past - and I did it every couple of years - ended up with that I returned to eclipse because IntelliJ seemed to me totally visually 'noisy'. Tons of colourful icons and ugly fonts under Linux. I could just not stand it.

But suddenly Android's official IDE is now based on IntelliJ and in my current project I could just not make the darn maven build work under eclipse while the IntelliJ using colleagues were just importing the pom.xml and started working. So back home this veryevening I gave it another chance: Colourful icons were gone but the fonts were still ugly. But after some research I found a solution and now IntelliJ looks almost like a native application. I did this with Ubuntu 13.10

The solution ist a combination of installing the alternative font rendering Infinality and a patched openJDK. Both hacks are described at webup8.org Better Font Rendering In Linux With Infinality and Install OpenJDK Patched With Font Fixes.

The recipe

1) Install Infinality

sudo add-apt-repository ppa:no1wantdthisname/ppa
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install fontconfig-infinality

2) Configure Infinality Answer question with linux:

sudo bash /etc/fonts/infinality/infctl.sh setstyle

Edit this file, search for USE_STYLE and set it to UBUNTU:

sudo -H gedit /etc/profile.d/infinality-settings.sh

3) Log out and back in again to see the changes

4) Install the patched openJDK

sudo add-apt-repository ppa:no1wantdthisname/openjdk-fontfix
sudo apt-get update
sudo apt-get upgrade

5) Install openJDK (if not installed)

sudo apt-get install openjdk-7-jdk

6) Ensure IntelliJ is using the patched openJDK by adding this line to {IntelliJ install dir}/bin/idea.sh as first line after the file comment.

IDEA_JDK="/usr/lib/jvm/java-1.7.0-openjdk-amd64"

7) If there are still bold fonts in the software's menu uninstall this package

sudo apt-get remove fonts-unfonts-core

Montag, 3. September 2012

Migrate Data from MySQL to MongoDB

A grails project needed to migrate from MySQL to MongoDB. The data included persons with an adress but the new data model should leave room for more than one address per person. Moreover the adresses have got geo coordinates, so the lat/lon values must be moved to a nested structure as mongo needs it if you want to query a geo spatial index.

As there is no reasonable tool for that I ended up writing migration code by myself. I also think that there can't be a good tool for that, because the paradigm shift from schema-full to schema-less is too big. IMHO it's recommendable to refine your datastructures as with MongoDB it is sometimes recomendable to have realted data embedded instaed of linked.

Anyway, I tried to migrate the person table with 400.000+ rows. I decided for embedded addresses here as they are usually not shared among several persons. The data should look like this:

{
    "_id" : ObjectId("5044ab202b5e1ae2ffcd44a1"),
    "firstname" : "John",
    "lastname" : "Doe",
    "address" : [
        {
            "city" : "Großerlach",
            "street" : "Sulzbacher Str. 50",
            "zip" : "71577",
            "loc" : {
                "lon" : 9.57669,
                "lat" : 49.03721
            }
        }
    ]
}


My first stupid attempt was to solve this completely with GORM. I installed the grails mongodb plugin and tried something like this:

Person.list().each() {
    it.mongo.save()
}

GORM seemed to be horribly slow when handling huge datasets at once. After some research I learned that I should do it in chunks and flush the hibernate session inbetween chunks. I tried with a chunk size of 1000 rows.

def sessionFactory

def copyToMongo() {
    int chunk = 1000
    long offset = 0
    long max = Person.count()
    while(offset < max)  {
        Person.list(max:page, offset:offset).each {
            it.mongo.save()
        }
        sessionFactory.currentSession.flush()
     offset += chunk
    }
}

But this was again very slow. After inserting about 60.000 rows the performance started to degrade and after 180.000 rows I ran out of heap memory. Finally I found out that it's best not to use GORM and Hibernate at all when handling a massive amount of data. No object mapping, just raw data and it worked quite well. My solution uses bare Groovy SQL and the low level API of MongoDB using the bulk insert feature:

def mongo
def dataSource

def copyToMongo() {
    int chunk = 1000
    long offset = 0
 
    def db = mongo.getDB("test")
    db.person.drop()
 
    Sql sql = new Sql(dataSource)
 
    long max = Person.count()
    while(offset < max)  {
        def bulk = []
        sql.eachRow("SELECT * FROM person LIMIT 1000 OFFSET $offset", {
            bulk << [
                firstname:it.firstname,
                lastname:it.lastname,
                address:[[
                    city:it.city, street:it.street, zip:it.zip, 
                    loc: [lon:it.longitude, lat:it.latitude]
                ]]
            ]
        })
        db.person.insert(bulk)
        offset += chunk
    }
    db.person.ensureIndex(['address.loc':'2d'])
    render "Done. "
    render "MySQL: $max "
    render "Mongo: ${db.person.count()}"
}

Donnerstag, 30. August 2012

EqualsAndHashCode

Today I stumbled over a AST transformation that I'd never noticed before, but I'm sure I'm going to use it frequently from now on. A simple way to make two instances with the same values equal.

http://groovy.codehaus.org/gapi/groovy/transform/EqualsAndHashCode.html


import groovy.transform.EqualsAndHashCode
 @EqualsAndHashCode
 class Person {
     String first, last
     int age
 }
 def p1 = new Person(first:'John', last:'Smith', age:21)
 def p2 = new Person(first:'John', last:'Smith', age:21)
 assert p1 == p2
 def map = [:]
 map[p1] = 45
 assert map[p2] == 45

Now that's cool.

Sonntag, 19. August 2012

Google Talk and Google Hangouts for Ubuntu

Google Talk is a browser plugin that lets you voice and video chat with friends and family from your browser. Install this plugin and logon to Gmail with your webcam and microphone attached to your computer, then initiate a chat with a friend or family member. It will try to connect to your webcam and enable video chat.

wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add
sudo sh -c 'echo "deb http://dl.google.com/linux/talkplugin/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get install google-talkplugin

Donnerstag, 12. Juli 2012

Tomcat Debug Logging

If ever encountered the problem, that you webapp was not coming up and all you see is

SEVERE: Error listenerStart

in the catalina.out. To shed some light on what is going on you can turn the logging on by dropping a logging.properties file into the WEB-INF/classes dir of your webapp and put these two lines inside:

org.apache.catalina.core.ContainerBase.[Catalina].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].handlers = java.util.logging.ConsoleHandler

Mittwoch, 27. Juni 2012

Logging Config for Grails 2.0

Finally I developed a good logging config. It debug logs your classes to development.log, grails stuff info logging to grails.log. Test logging goes into test.log and for production it logs nothing to the console (= catalina.out) and info logging to a daily rolling logfile.
import org.apache.log4j.*
environments {
  development {
    log4j = {
      appenders {
        file name: 'grailsfile', file: 'target/grails.log', layout: pattern(conversionPattern: "[%d{ISO8601}]\t%p\t%c{2}\t%m%n")
        file name: 'rootlog', file: 'target/root.log', layout: pattern(conversionPattern: "[%d{ISO8601}]\t%p\t%c{2}\t%m%n")
        file name: 'devfile', file: 'target/development.log', layout: pattern(conversionPattern: "[%d{ISO8601}]\t%p\t%c{2}\t%m%n")
      }
      root { error 'stdout', 'rootlog' }
      info additivity: false, grailsfile: 'org.codehaus.groovy.grails, com.orientechnologies'//.commons'
      all additivity: false, devfile: [
        'grails.app.controllers.my.package',
        'grails.app.domain.my.package',
        'grails.app.services.my.package',
        'grails.app.taglib.my.package',
        'grails.app.conf.my.package',
        'grails.app.filters.my.package',
        'my.package'
      ]
    }
  }

  test {
    log4j = {
      appenders {
        file name: 'grailsfile', file: 'target/grails.log', layout: pattern(conversionPattern: "[%d{ISO8601}]\t%p\t%c{2}\t%m%n")
        file name: 'rootlog', file: 'target/root.log', layout: pattern(conversionPattern: "[%d{ISO8601}]\t%p\t%c{2}\t%m%n")
        file name: 'testfile', file: 'target/test.log', layout: pattern(conversionPattern: "[%d{ISO8601}]\t%p\t%c{2}\t%m%n")
      }
      root { error 'stdout', 'rootlog' }
      info additivity: false, grailsfile: 'org.codehaus.groovy.grails'
      all additivity: false, testfile: [
        'grails.app.controllers.my.package',
        'grails.app.domain.my.package',
        'grails.app.services.my.package',
        'grails.app.taglib.my.package',
        'grails.app.conf.my.package',
        'grails.app.filters.my.package',
        'my.package'
      ]
    }
  }

  production {
    grails.logging.jul.usebridge = false
    log4j = {
      appenders {
        console name: 'console', layout: pattern(conversionPattern: "[%d{ISO8601}]\t%p\t%c{2}\t%m%n")
        appender new org.apache.log4j.DailyRollingFileAppender(
          name:"logfile", fileName:"./my.application.log",
          layout:pattern(conversionPattern: '[%d{ISO8601}]\t%p\t%c{2}\t%m%n')
        )
      }
      // set this to debug if debugging on a dev server
      info 'grails.app.controllers.my.package',
        'grails.app.domain.my.package',
        'grails.app.services.my.package',
        'grails.app.taglib.my.package',
        'grails.app.conf.my.package',
        'grails.app.filters.my.package',
        'my.package'
     
      info 'org.codehaus.groovy.grails.commons', 'com.orientechnologies'

      root {
        error 'logfile'
        additivity = true
      }
    }
  }
}