-
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
andgit 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
The second thing we need to do is to configure admin user. Here is mine, registered for the host I just defined
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
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.
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.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.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.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
.Resources
- Groovy regexes
- Groovy one-liners
- Using String.replaceAll method
Footnotes
- This example is for demonstration purposes only. In real program you would just use
Properties.load
method. - The regex is simplified. If you want the real one, take a look at Jeffrey Friedl’s example.
- Again, in reality you would find snapshots using
mvn dependency:resolve | grep SNAPSHOT
command. - 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:
-
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