• Get started with ejabberd

    Installation

    Before installing ejabberd make sure you have Erlang environment set up. Run the following command and verify the output

    $ erl -version
    Erlang (ASYNC_THREADS,HIPE) (BEAM) emulator version 5.10.1
    

    I used to install ejabberd with apt-get command, which is convenient but always several versions behind. That’s why I switched to building from sources. All scripts below are assumed to be run under ejabberd user.

    First, create a directory where all ejabberd versions will be installed, if it does not exist yet

    $ sudo mkdir /opt/ejabberd
    $ sudo chown -R ejabberd /opt/ejabberd
    

    Download the sources

    $ cd
    $ git clone git@github.com:processone/ejabberd.git
    $ cd ejabberd
    

    Select version you want to install by executing git branch -a and git tag --list commands. Let assume we want to install version 2.1.12 from branch 2.1.x

    $ git checkout 2.1.x
    $ cd src
    

    The next step is optional. If you are going to integrate ejabberd with RabbitMQ, you need to download the source of rabbitmq-xmpp module

    $ wget https://raw.github.com/ndpar/rabbitmq-xmpp/rabbitmq3/src/mod_rabbitmq.erl
    $ wget https://raw.github.com/ndpar/rabbitmq-xmpp/rabbitmq3/src/rabbit.hrl
    

    Now we are ready to install ejabberd. To see all available configuration options, run ./configure --help.

    $ ./configure --prefix=/opt/ejabberd/ejabberd-2.1.12 --enable-user=ejabberd
    $ make
    $ make install
    $ cd /opt/ejabberd
    $ ln -s ejabberd-2.1.12 ejabberd
    

    Configuration

    Ejabberd comes with reasonable default configuration. Only two lines need to be changed to make it work in your environment.

    Open /opt/ejabberd/ejabberd/etc/ejabberd/ejabberd.cfg file and find SERVED HOSTNAMES section. By default Ejabberd is configured for localhost only. Change it to your machine’s DNS name. Here is what I have in my config

    /opt/ejabberd/ejabberd/etc/ejabberd/ejabberd.cfg
    %%%' SERVED HOSTNAMES
    {hosts, ["jabber.ndpar.com"]}.

    The second thing we need to do is to configure admin user. Here is mine, registered for the host I just defined

    /opt/ejabberd/ejabberd/etc/ejabberd/ejabberd.cfg
    %%%' ACCESS CONTROL LISTS
    {acl, admin, {user, "andrey", "jabber.ndpar.com"}}.

    Save the config file and start the server

    $ /opt/ejabberd/ejabberd/sbin/ejabberdctl start
    

    You can quickly check the log file to see if the server has been started successfully

    $ less /opt/ejabberd/ejabberd/var/log/ejabberd/ejabberd.log
    

    If it wasn’t, you might want to enable debug logs

    /opt/ejabberd/ejabberd/etc/ejabberd/ejabberd.cfg
    %%%' DEBUGGING
    {loglevel, 5}.

    and restart the server to see more details

    $ /opt/ejabberd/ejabberd/sbin/ejabberdctl restart
    

    Registering users

    The first (admin) user has to be registered in command line

    $ cd /opt/ejabberd/ejabberd/sbin
    $ ./ejabberdctl register andrey jabber.ndpar.com ******
    

    This user is the same as admin you configured in the previous section. If you go to localhost:5280/admin in the browser, you should be able to login with the same password you registered the user

    Now you are ready to add newly created account to your Jabber client. In Adium, for example, go to File -> Add Acount -> Jabber and provide server hostname/IP, JID and password.

    To really enjoy IM you need more users on your server. The best part here is that you can create new users just from your Jabber client. Simply go to File -> your ejabberd account -> Add User

    For other available options please consult official documentation.

  • State Machine in Erlang

    There is some sort of confusion in the object-oriented community about functional languages. How is it possible to implement stateful application if the language has no concept of state? It turns out that it’s actually quite possible, although the solution is completely deferent from what we see in the OO realm. In Erlang, for example, state can be implemented by using process message passing and tail recursion. This approach is so elegant that after you’ve learned it, the OO way of doing this looks unnatural. The code below is the Erlang implementation of Uncle Bob’s FSM example. Look at it. Isn’t that code clean and expressive? It looks almost like DSL but it’s actually regular Erlang syntax.

    -module(turnstile).
    -export([start/0]).
    -export([coin/0, pass/0]).
    -export([init/0]).
    start() -> register(turnstile, spawn(?MODULE, init, [])).
    % Initial state
    init() -> locked().
    % Events
    coin() -> turnstile ! coin.
    pass() -> turnstile ! pass.
    % States and transitions
    locked() ->
    receive
    pass ->
    alarm(),
    locked();
    coin ->
    unlock(),
    unlocked()
    end.
    unlocked() ->
    receive
    pass ->
    lock(),
    locked();
    coin ->
    thankyou(),
    unlocked()
    end.
    % Actions
    alarm() -> io:format("You shall not pass!~n").
    unlock() -> io:format("Unlocking...~n").
    lock() -> io:format("Locking...~n").
    thankyou() -> io:format("Thank you for donation~n").

    The idea behind this code is simple. Every state is implemented as a function that does two things: it listens for messages sent by other processes; when message is received the appropriate action is taken and one of the state-functions called recursively. Simple.

  • Parsing files using Groovy regex

    In my previous post I mentioned several ways of defining regular expressions in Groovy. Here I want to show how we can use Groovy regex to find the data in the files.

    Parsing properties file (simplified)1

    Data: each line in the file has the same structure; the entire line can be matched by single regex.

    Task: transform each line to the object.

    Solution: construct regex with capturing parentheses, apply it to each line, extract captured data.

    Demonstrates: File.eachLine method, matrix syntax of Matcher object.

    def properties = [:]
    new File('path/to/some.properties').eachLine { line ->
    if ((matcher = line =~ /^([^#=].*?)=(.+)$/)) {
    properties[matcher[0][1]] = matcher[0][2]
    }
    }
    println properties

    Parsing CSV files (simplified)2

    Data: each line in the file has the same structure; the line consists of the blocks separated by some character sequence.

    Task: transform each line to the list of objects.

    Solution: construct regex with capturing parentheses, parse each line with the regex in a loop extracting captured data.

    Demonstrates: ~// Pattern defenition, Matcher.group method, \G regex meta-sequence.

    def regex = ~/\G(?:^|,)(?:"([^"]*+)"|([^",]*+))/
    new File('path/to/file.csv').eachLine { line ->
    def fields = []
    def matcher = regex.matcher(line)
    while (matcher.find()) {
    fields << (matcher.group(1) ?: matcher.group(2))
    }
    println fields
    }

    Finding snapshot dependencies in the POM (simplified)3

    Data: file contains blocks with known boundaries (possibly spanning multiple lines).

    Task: extract the blocks satisfying some criteria.

    Solution: read the entire file into the string, construct regex with capturing parentheses, apply the regex to the string in a loop.

    Demonstrates: File.text property, list syntaxt of Matcher object, named capture, global \x regex modifier, local \s regex modifier.

    def pom = new File('path/to/pom.xml').text
    def matcher = pom =~ $/(?x)
    <dependency> \s*
    <groupId>([^<]+)</groupId> \s*
    <artifactId>([^<]+)</artifactId> \s*
    <version>(.+?-SNAPSHOT)</version> (?s:.*?)
    </dependency>
    /$
    matcher.each { matched, groupId, artifactId, version ->
    println "$groupId:$artifactId:$version"
    }

    Finding stacktraces in the log

    Data: file contains entries each of which starts with the same pattern and can span multiple lines. Typical example is log4j log files:

    2009-10-16 15:32:12,157 DEBUG [com.ndpar.web.RequestProcessor] Loading user
    2009-10-16 15:32:13,258 ERROR [com.ndpar.web.UserController] id to load is required for loading
    java.lang.IllegalArgumentException: id to load is required for loading
         at org.hibernate.event.LoadEvent.(LoadEvent.java:74)
         at org.hibernate.event.LoadEvent.(LoadEvent.java:56)
         at org.hibernate.impl.SessionImpl.get(SessionImpl.java:839)
         at org.hibernate.impl.SessionImpl.get(SessionImpl.java:835)
         at org.springframework.orm.hibernate3.HibernateTemplate$1.doInHibernate(HibernateTemplate.java:531)
         at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
         at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
         at org.springframework.orm.hibernate3.HibernateTemplate.get(HibernateTemplate.java:525)
         at org.springframework.orm.hibernate3.HibernateTemplate.get(HibernateTemplate.java:519)
         at com.ndpar.dao.UserManager.getUser(UserManager.java:90)
         ... 62 more
    2009-10-16 15:32:14,659 DEBUG [com.ndpar.jms.MessageListener] Received message:
         ... multi-line message ...
    2009-10-16 15:32:15,169 INFO  [com.ndpar.dao.UserManager] User: ...
    

    Task: find entries satisfying some criteria.

    Solution: read the entire file into the string4, construct regex with capturing parentheses and lookahead, split the string into entries, loop through the result and apply criteria to each entry.

    Demonstrates: regex interpolation, combined global regex modifiers \s and \m.

    def log = new File('path/to/your.log').text
    def logLineStart = /^\d{4}-\d{2}-\d{2}/
    def splitter = log =~ $/(?xms)
    ( ${logLineStart} .*?)
    (?= ${logLineStart} | \Z)
    /$
    splitter.each { matched, entry ->
    if (entry =~ /(?m)^(?:\t| {8})at/) println entry
    }

    Resources

    Footnotes

    1. This example is for demonstration purposes only. In real program you would just use Properties.load method.
    2. The regex is simplified. If you want the real one, take a look at Jeffrey Friedl’s example.
    3. Again, in reality you would find snapshots using mvn dependency:resolve | grep SNAPSHOT command.
    4. This approach won’t work for big files. Take a look at this script for practical solution.
  • Groovy regular expressions

    Because of the compact syntax regular expressions in Groovy are more readable than in Java. Here is how Jeffrey Friedl’s [example][1] looks in Groovy:

    def subDomain = '(?i:[a-z0-9]|[a-z0-9][-a-z0-9]*[a-z0-9])' // simple regex in single quotes
    def topDomains = $/ </div></div>
    (?x-i : com \b # you can put whitespaces and comments
    | edu \b # inside regex in eXtended mode
    | biz \b
    | in(?:t|fo) \b # backslash is not escaped
    | mil \b # in dollar-slash strings
    | net \b
    | org \b
    | [a-z][a-z] \b
    )/$</span>
    def hostname = /(?:${subDomain}\.)+${topDomains}/ // variable substitution in slashy string
    def NOT_IN = /;\"'<>()\[\]{}\s\x7F-\xFF/ // backslash is not escaped in slashy strings
    def NOT_END = /!.,?/
    def ANYWHERE = /[^${NOT_IN}${NOT_END}]/
    def EMBEDDED = /[$NOT_END]/ // you can ommit {} around var name
    def urlPath = "/$ANYWHERE*($EMBEDDED+$ANYWHERE+)*"
    def url =
    """(?x: </div></div>
    # you have to escape backslash in multi-line double quotes
    \\b
    # match the hostname part
    (
    (?: ftp | http s? ): // [-\\w]+(\\.\\w[-\\w]*)+
    |
    $hostname
    )
    # allow optional port
    (?: :\\d+ )?
    # rest of url is optional, and begins with /
    (?: $urlPath )?
    )"""</span>
    assert 'http://www.google.com/search?rls=en&q=regex&ie=UTF-8&oe=UTF-8' ==~ url
    assert 'pages.github.io' ==~ url
    </pre></div></figure> As you can see, there are several notations, and for every subexpression you can choose the one that is most expressive. ### Resources - Martin Fowler on [composed regexes][2] - [Introducing dollar-slash][3] notation into Groovy - [Mastering Regular Expressions][4] — the best regex book - Groovy [Pattern][5] and [Matcher][6] classes [1]: http://regex.info/listing.cgi?ed=3&p=208 [2]: http://martinfowler.com/bliki/ComposedRegex.html [3]: http://jira.codehaus.org/browse/GROOVY-2701 [4]: http://regex.info/ [5]: http://mrhaki.blogspot.com/2009/09/groovy-goodness-using-regular.html [6]: http://mrhaki.blogspot.com/2009/09/groovy-goodness-matchers-for-regular.html
  • Split commits in Git

    $ git log # copy commit_id
    $ git rebase -i <commit_id>^ # choose edit
    $ git reset HEAD^
    $ git add -i
        # loop through files; patch or update
        $ git ci
    $ git rebase --continue