Creating Zimbra Server Extensions Quickstart
I’m currently investigating on how to create a Zimbra server extension. In case you didn’t know already, Zimbra is a great groupware system, that can easily replace your Microsoft Exchange server. More about Zimbra can be found here: [[http://www.zimbra.com]].
What I’m thinking about is a Zimbra server handler, that can communicate with backend ERP systems to update client data. But that’s something for the future.
As I’m not the great Java guy around, I fiddled around with the correct options and classpaths and stuff to create a very simple server extension, that just outputs a funny string when you call it using a web browser. And for your entertainment and as a reminder for myself, I made this blog post.
Some information on this can be found in Vishal Mahajan’s old blog post available [[http://blog.zimbra.com/blog/archives/2010/04/extending-zimbra-with-server-extensions.html|here]].
What we’re going to do is create an extension that outputs a string into our browser when calling a Zimbra-specific URL.
So, for Java misfits like me, let’s start by creating the following directory structure:
* TestExtension
* build
* dist
* src
* conf
* build: Output directory for the java compiler
* dist: Output directory for the JAR-file
* src: The source directory structure (see below)
* conf: Place for a manifest-file the way Zimbra wants it
To start the easy way: Vishal mentioned something about a jar manifest file, that needs to have some information about our extension. A „jar manifest file“ is something like a configuration file, that sits inside a jar file. And a „jar-file“ is a zip file of compiled java files in a specific directory structure.
So I created a file MANIFEST.MF in the conf directory consisting only of this line:
Zimbra-Extension-Class: de.dieploegers.TestExtension
About the right-hand side there: That’s the name of our test extension. In Java terms, this is the Java class „TestExtension“ in the package „de.dieploegers“. So we create the following directory structure under the „src“-directory:
* de
* dieploegers
Now onto the code. We create a file called „TestExtension.java“ below „src/de/dieploegers“.
In this file, we first have to tell Java in which package we are:
package de.dieploegers;
Then we have to import some classes, so that we have everything we need:
import com.zimbra.cs.extension.ZimbraExtension;
import com.zimbra.cs.extension.ExtensionDispatcherServlet;
import com.zimbra.common.service.ServiceException;
Now, trying to develop a useful server extension, you definitely need some basic Java knowledge, that I won’t teach you here. Google a bit, there are lots of good java tutorials.
What do we import here?
* ZimbraExtension: That will be our class‘ parent.
* ExtensionDispatcherServlet: That’s a class that does the whole „HTTP-Connection to Servlet“-dispatching. Remember, that we wanted to do something once someone calls a specific URL.
* ServiceException: That’s a basic exception you can throw or catch in this whole Zimbra extension business
Again, following Vishal here, we need to make a class, that basically overwrites „init“ and „destroy“. That is fairly easy. But we want to gain control of a HTTP connection connecting at
So we register our own handler (that we have to develop further on) for these requests.
Our class looks like this:
public class TestExtension implements ZimbraExtension {
public void init() throws ServiceException {
ExtensionDispatcherServlet.register(this, new TestExtensionHandler());
}
public void destroy() {
ExtensionDispatcherServlet.unregister(this);
}
public String getName() {
return "TestExtension";
}
}
This is basically registering our handler in the „init“-method and unregistering it in the „destroy“-method. The „getName“-method is only there to know our extension’s name for logging purposes.
So now we only have to create our http handler. We switch over to a file called „TestExtensionHandler.java“.
There, again, add the package-statement and the following imports:
import com.zimbra.cs.extension.ZimbraExtension;
import com.zimbra.cs.extension.ExtensionHttpHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletException;
import java.io.IOException;
import com.zimbra.common.service.ServiceException;
Now, that’s a mouthful. Besides the ZimbraExtension and the Exceptions and basic classes we need for servlet programming like the javax.* and java.io.*-parts we import the „ExtensionHttpHandler“. We will implement this in our class.
The ExtensionHttpHandler basically needs three methods:
* getPath: In which path will our handler be active? That’s a path under the URL of our Zimbra server
* init: Initialisation of our class. Nothing special.
* doGet or doPost: That’s the work horses of our class. You can specify what to do, when a GET- or POST-request comes. We will only be using GET in this example.
So we override doGet, which needs to arguments: the request and the response.
The request really doesn’t matter in this example, but the response contains something called a „ServletOutputStream“. That’s the things we will see, when we call the URL. So writing to the ServletOutputStream will put something in our browser.
You can get the ServletOutputStream by calling the response-object’s method „getOutputStream“.
So our class looks like this:
public class TestExtensionHandler extends ExtensionHttpHandler {
public String getPath() {
return super.getPath() + "/testextension";
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException{
ServletOutputStream os = resp.getOutputStream();
os.print("TEEEST");
}
public void init (ZimbraExtension ext) throws ServiceException {
super.init(ext);
}
}
Now for the interesting part. (at least for me)
How do we compile and build this whole thing? Something Zimbra uses (and everybody else in the world) is called „ant“ and is an automated java building and deploying tool. Ant relies on a XML-file as a configuration.
But first, let’s think about, what we need to do:
* Compile our sources. We need to set a thing called „classpath“, that holds all the classes the java compiler needs to compile our sources.
* Make a jar-file out of the compiled sources
For this purpose we create a fairly simple (once you understood ant) file called build.xml in our root folder:
As you might recognize, I’ve downloaded the Zimbra source files using Perforce as described here: [[http://wiki.zimbra.com/wiki/Building_Zimbra_using_Perforce]]. That way under linux I have the Zimbra source files under /home/public/p4. (Which can’t be changed I think)
In the build file, there are many properties and two so-called „targets“. A „compile“-target, that does the whole compiling the source files and a „jar“-target, that creates a jar-file containing our created manifest-file. The properties hold references to some directories and jar-files coming with the Zimbra source files. We need those to compile our extension.
Before the next step you first have to build the ZimbraCommon and ZimbraServer sources. This is fairly easy by just going to ZimbraCommon and calling „ant“ and afterwards going to ZimbraServer and calling „ant“.
After that, just go to the root folder of our little example and call „ant“.
After ant is finished doing its thing, go to „dist“ and find a naughty jar-file there. Copy this file onto your zimbra-server. Create a directory for our extension at
/opt/zimbra/lib/ext/TestExtension
and put the jar-file there (you need to be root to do this). After that restart the mailbox-server by doing a
zmmailboxd restart
as the zimbra-user.
Once this is done (you can have a look at the /opt/zimbra/log/mailbox.log for details), start a browser and point it to:
http://
and you will see the string, that is in our TestExtensionHandler-class.
Nice. Now I only need to figure out, how to use these extensions from the admin console. If it's worthy, I will tell you about it later.
Calendar
M | D | M | D | F | S | S |
---|---|---|---|---|---|---|
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 |
Archive
- Januar 2024
- Dezember 2023
- April 2021
- März 2021
- September 2020
- Dezember 2019
- November 2019
- Oktober 2019
- Juli 2019
- Juni 2019
- Mai 2019
- April 2019
- März 2019
- September 2018
- August 2018
- Juli 2018
- März 2018
- Januar 2018
- Dezember 2017
- September 2017
- März 2017
- Februar 2017
- Januar 2017
- August 2016
- Mai 2016
- Dezember 2015
- November 2015
- August 2015
- März 2015
- Dezember 2014
- September 2014
- August 2014
- Juli 2014
- Februar 2014
- Oktober 2013
- September 2013
- August 2013
- Juli 2013
- Juni 2013
- Mai 2013
- April 2013
- November 2012
- Oktober 2012
- September 2012
- August 2012
- Juni 2012
- Mai 2012
- März 2012
- Februar 2012
- Januar 2012
- November 2011
- Juli 2011
- Juni 2011
- März 2011
- Februar 2011
- Januar 2011
- Dezember 2010
- November 2010
- April 2010
- Februar 2010