Saturday, November 6, 2010

Uhh we have color: Running a legacy app on eclipse e4

I came back from ESE with lots of inspiration. So I couldn't stop and had to try our RCP application on e4 for the first time.

I had a little fight in getting everything up, the e4 sources are missing in the M3 download (theres a bug for that) and you have to install the tooling seperately. So I just pointed e4 to my workspace, switched the target platform and tried to launch. Oh, yes now we need an application model.

Setting up the application model for a legacy app seems to be not well documented, I didn't know at all what elements I would need as I was starting from zero. So I had a look at the example e4 app and stripped down the e4xmi to my needs.

<?xml version="1.0" encoding="ASCII"?>
<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_lYit4OjtEd-nIcCsQMihjw" elementId="de.eiswind.mango.client">
  <children xsi:type="basic:TrimmedWindow" xmi:id="_lWJrwOjuEd-nIcCsQMihjw" elementId="de.eiswind.mango.client.mainWindow" label="Buchmanager" iconURI="platform:/plugin/de.eiswind.mango.client.core/icons/mango.gif" width="1024" height="768">
    <children xsi:type="advanced:PerspectiveStack" xmi:id="_bXMvVejuEd-nIcCsQMihjw"/>
    <mainMenu xmi:id="_xpyAkOjuEd-nIcCsQMihjw" elementId="menu:org.eclipse.ui.main.menu"/>
    <trimBars xmi:id="_CnxywOjvEd-nIcCsQMihjw">
      <children xsi:type="menu:ToolBar" xmi:id="_DF-xsOjvEd-nIcCsQMihjw" elementId="toolbar:org.eclipse.ui.main.toolbar"/>
    </trimBars>
  </children>
  <addons elementId="MinMax Addon" contributionURI="platform:/plugin/org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.minmax.MinMaxAddon"/>
  <addons elementId="DnD Addon" contributionURI="platform:/plugin/org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.dndaddon.DnDAddon"/>
  <addons elementId="Cleanup Addon" contributionURI="platform:/plugin/org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.cleanupaddon.CleanupAddon"/>
</application:Application>

--27.02.2011 this xmi is a little buggy. Try the LegacyIDe.e4xmi from the platform plugin instead.

You basically need a menu and toolbar hook, and a perspective stack. the addons are needed to get the usual behaviour on views and editors for resizing.

Some things didn't work from scratch with my perpectives, but I received patches in almost no time when I reported the bugs to the e4 team. Still one issue open, but I think that will get fixed soon, too.

Finally I stole some eclipse css file and added the theme extension point to my app.
So now my app looks a little more "sexy" in terms of colors and styling. I could get used to it.

Did I mention that I didn't change a single line of the 3.6 based code ? The compatibility is great.

Monday, November 1, 2010

Porting to virgo - seeing some light

Some weeks ago I started some experimental stuff and tried to port our server to Eclipse Virgo. The code was based on spring configuration mainly, so I thought that I should be able to handle this.

Today I can connect with the client and most services are working fine. But if it has one drawback, it is that I had to build most of the library bundles on my own. And we use a hell of a lot of libraries. Hibernate is still not really OSGi-friendly as are other frameworks. Today a had a fight with JasperReports, which used to cause some headache even without OSGi, but with some drawbacks I finally can run our reports on virgo now.

I still must have an evil jar that wants org.apache.xerces as default instead of com.sun.org... I thought I had removed all the xerces jars that come with frameworks here and there, and I cannot see what I have overseen today. I made my way round by setting system properties to the jre implementation which luckily made it work. (I needed at least a simple succes today)

Setting up the bundles correctly caused me some headaches over the last weeks. I had the hell of ExtendedClassNotFoundException, learned a lot about who is using whom in my jars. Some things appaered a little surprising to me as I had to import javax.sql for example in many bundles. I would have guessed that those jre packages are visible by default. But maybe someone explains the reason for this to me one day.

One thing that still annoys me is that virgo tooling for eclipse doesn't support PDE bundles. So I have the PDE and the Spring bundle project nature on some of my shared bundles (i.e. bundles that client and server need both for communication) which is really painful and error prone. Kai Toedter opened an enhancement request on this today.

But all in all its working, still have to do some refactorings on formerly static code that used to be called from main, but its not to far to go. Did not find a true showstopper up to now. When all is done I need to work out a proper Installer that will migrate an exisiting configuration into virgo, but that seems to be not to complicated as virgo con pick up existing property files when I put them in the repo.

Now for today I have two different versions of lucene running in parallel, next step I could throw in a current poi instead of that one jasper report uses.

But most of all I'm looking forward to the ease of deployment on my customers sites in the near future. The day they all will have virgo installed, upgrading the whole thing will simply mean uploading a new release to central virgo and p2 repositories. I still have to think my way to the strategy (what about errors on schema upgrades ? I see them at least at one customer at each new release, customer have data you can't think of in advance) but all in all I'm very happy about that.

I'll be talking about the update scenario in detail at ESE on Wednesday afternoon, so come and talk to me if this is something you are into !

Friday, October 22, 2010

What if we had EMF persistence on Datanucleus

One thing that keeps me away from EMF is that I'm so used to hibernate persistence and good old java beans. You may rant on that. But I have a look at Teneo and CDO from time to time, things keep getting better.

But think of if we had something like CDO running on Datanucleus ? It will give us the power we need for EMF in the cloud. Theres support for googles app engine and the new VMForce PAAS will be running Datanucleus to. I would defintively be thinking about using VMForce if I had a EMF persistence solution like CDO running inside.

If I only had more time... Maybe theres something like this out there and I just haven't heard of it ?

Friday, October 15, 2010

Technology implications on architecture and design

I have been in love with eclipse for a while because I love the architecture and I got used to the productiveness working on the platform.

I remember coaching an architect on RCP technology a while ago. He had several ideas what he wanted to do, came up with UI wireframe sketches and asked me how to do this and that. From his sketches I guessed that he had no idea about the technology he was going to use. He wanted to have widgets that don't exists in SWT/JFace and many other things I refuse to remember exactly.

Thats what I so often hated : Having no clue about technology, paying big money for a consultant to solve their problems.

Technology has always implications on architecture and design of an application. But so many times those who decide on technology don't have a clue about what they're deciding on.

If you don't have someone with a "masters degree" in mastering your technology keep away from it.

I see so many projects suffering from code and architecture smells simply because a lack of mastership.

As Ed Merks told me: Never stop striving for leadership and quality.

Sunday, October 10, 2010

First hops on Eclipse Virgo

My server has alwas been a monolith with an embedded jetty, mostly configured with spring and a whole bunch of libraries, hibernate, jackrabbit, embedded derby, jasperreports and so on. tons of jars to handle.

For a long time I wished I had chosen OSGi from the beginning, but now came the new hibernate search release that depends on a late lucene version that will be supported by jackrabbit sometime but not now. So no time to wait, OSGi I'm coming. Sick of the jar hell I thought about setting up my own OSGi runtime with equinox and jetty, but why build your own when there is virgo (aka Spring dm Server) available.

So as always after weeks of thinking, making migration plans for the existing server installations in my head, I downloaded virgo on friday night for the first time. I tried the sample to get at least a grip and started to build some library bundles (tried to keep it simple, so mostly large bundles) and copied my sources into some new folders that would be easy to kick if I won't succeed.

First I had to step back on Galilieo, as the Spring Tools Suite builds for Helios gave me the hell of errors and error dialogs popping all the way up. Back on Galilieo I found that I have to get a milestone build of the tools suit to get support for virgo. Getting used to the tooling... The Spring tools hold the Bundle Manifest in the src folder, which is a pain as i have to share one bundle with my RCP client the as used from PDE tooling has META-INF in the project root. Some folks already complained about that. Its really a pain.

Now I could get used to develop the server on Galileo, what means I have to do client development in a different eclipse instance as I depend on 3.6 for the p2 hell of changes that have been going on.

After about 20 aching hours of fixing import and export bundle headers and a truly sleepless night I saw Virgo at least trying to launch my server.

Now I am still fighting to run hibernate. I had to make some hacks on virgos manifests to install jpa2 and I had to install spring 3.0.4 as 3.0.0 that comes with virgo has some bugs regarding JPA2 and hibernate. I opened some forum threads today and I hope that I can get some useful input on classloading issues.

I see some light today.

Monday, October 4, 2010

EMF and GWT in the Cloud

Thanks to  Ed Merks who pointed me to http://wiki.eclipse.org/EMF/GWT today.
I just had to try this and lets say I am overwhelmed. This is what you need for GWT development, I will forget about JPA and DTO's.

Just had to re-post as its simply the thing I always missed.

Sunday, September 19, 2010

Loading ResourceBundles with Jasper Reports - MissingResourceException

If you stumbled across a MissingResourceException while internationalizing your Jasper Report (I had the heck of a time with it) try constructing an URLClassloader that points to the dir of your resource files and pass that Classloader by parameter to the report. Everything is fine now :)

Tuesday, August 31, 2010

Building websites with Joomla

I'm a software engineer, not a web designer. But I found it quite easy to build two websites with Joomla last week. So to say I used an open template with some modifications, PHP is easy to understand I guess. Only to magae these css styles for the joomla template made me sick sometimes. The sites are both german, if you want to have a look go to:
Eiswind Software and Buchmanager Verlagssoftware

Monday, August 16, 2010

Going smooth with p2

I have to admit that I really had a hard time making p2 do what I wanted it to do. But all the fight was worth it in the end.  From the last buchmanager release (www.buchmanager.com) on I was able to push out silent client updates whenever I needed to do some minor fixes. No need to inform users to get a new version of the client anymore, as they would pull the updates magically on startup. I now started dreaming of updating the server in the same manner, but as this always goes with database changes it will be a greater effort. So I keep that in mind when the userbase grows in the future this is something to think of seriously.

Sunday, May 30, 2010

Managing enterprise clients with p2 query api

In my last post I left some quite angry words to the p2 team, I hope they will forgive me. After some more days of intense research I finally made p2 do what I want to. And you might want to notice that I'm quite happy about that.

Our system (It's german,  Buchmanager) is a client server architecture with hibernate/spring on the backend and a remote RCP Client. Our customers have a strong demand for automated updates, as users are forced to sync their client on server updates.

The Problem: Client and server have to match and we cannot know what server version the customer is running.

The Solution: p2 queries.
At Workbench startup the client asks the server for the required client version numbers. Then we make a p2 Query with a VersionRange (as qualifier may indicate a compatible update)

IQueryResult matches = queryable.query( QueryUtil.createIUQuery("de.eiswind.mango.client.core.mango",new VersionRange(Version.createOSGi(major, minor, micro), true, Version.createOSGi(major, minor, micro + 1), false)), new NullProgressMonitor());
Thereby we ask the repository to give us "product" IUs only matching the servers requirements. Then we use the high level api UpdateOperation to resolve an update for us. As there may be updates for a higher (=newer) server version available, we use "setSelectedUpdates" to Update only to the compatible client. this is quite easy using the equals & compareTo on Update & Version classes.

I have to note that we had to remove the p2 ui bundles completely, as they would have still offered the _wrong_ update to the user. I guess that could be changed using a Policy, but that is work to come when we feel a need for a ui.

Follow me on http://twitter.com/thomas_kratz

Tuesday, May 25, 2010

p2 is powerful, but still a nightmare to me

I started my first steps with p2 for our RCP app on eclipse 3.4, I remember I finally had some working stuff after some fights. But then came the 3.5 release and everything had changed. I found so many changes in the api that I got frustrated and throwed the whole thing away. Now that with 3.6 the API will become stable, I gave/give it another try. I found some tutorials and last but not least the examples on the p2 wiki. First to say, the examples did not work without some tweaking. I have some special requirements, as I need to make sure of the version that gets upgraded to ( The users client has to be compatible with the customers installed server version,  so I cannot update to the newest version in many cases). In general p2 seems to be made for that, and I still would prefer to have p2 over some local webstart deployment as I could push out minor fixes to my clients transparently. But on the other hand I prefer to use mainstream technology, and although so many eclipse users use p2 for a while, developers seem to find it hard to adopt it. I read many posts of people that gave up on p2, and guess I spent 5 days already on it and it still doesn't work. Its time consuming hence you can't test it in hosted mode, so its always at least a 5 to 6 minute build, sometimes evenlonger if I have to wait for my 1Mbit upstream to publish a repository change. I got help from one developer on the p2 mailing list, but my last questions remain unanswered. If you look in the p2 forum section, there are only a handful of posts and most of them are unanswered too. I guess p2 has made some progress, but documentation is still poor and looking at the traffic I see on the mailing list, I think the p2 dev team hasn't got that they have to help people adopt this othwerwise great technology in order to make it a success. I can fully understand many people wishing back for the old UpdateManager and telling you not to use p2. But if you look at it for some time you can only guess its power and I would like to see that it gets adopted by more people than now. The community has to be built and I wish I could see some more effort there.

Monday, May 17, 2010

Having a hard time with p2.data.area

I knew it won't be easy, but I guess it shouldnt be that hard to set up p2 updates for my app. I spend 2 and a half days now on it and its still not working ( apart from some issues that I hope to get help from the p2 dev team). One thing that took me hours to find was that I had set the osgi.configuration.area to the user.home directory. pde build adds then a line p2.data.area=@config/../p2 to the config.ini. That makes the platform not see the preferences generated from the p2.inf and therefore it didn't see my repositories. I really didn't see this for hours of failing.

Saturday, May 15, 2010

PDE build ate my feature

Having my way back to p2 after it should be stable now, I started off building a repository for my product, thats made up of three features. However one of the features was mising in the repository for a reason I don't know. I double checked everything and ended up moving the plugins from the missing feature to one of the features that where working. Thats no prblem as I always wnated to do that, but I wonder if anyone elde has seen this before and could tell me a reason.

Sunday, May 9, 2010

The power of messaging

I've written some posts about messaging in enterprise eclipse applications. Yesterday I made another quick hack thats really beautiful to me. In our app we have lots of ValueLists that make up the selections in the combos. These lists are customizable, so they may change. Up to now you had to restart the client to make the changes take effect as the lists were once fetched from the server at workbench startup.

Now I made a simple change, if I get an update to a list from the server, i send an invalidate message to all online clients through xmpp (did I mention we use apache vysper as xmpp host ?) the client then simple removes the list from its storage and next time its needed it will get fetched from the server with its new state.

Took me 15 minutes to implement the whole thing and now the lists in the client are always up-to-date.
Nice :) This could make up a whole client side caching mechanism if needed.

Tuesday, March 30, 2010

Install an Eclipse based App - what's the best way to go ?

Going commercial (I had to do this) some things have changed for me. One thing is that I have to provide commercial quality support. Every now and then (more often than I like) I have a user that cannot run my Eclipse based app and most of the times I do not get concrete feedback on the reasons, be it that the user doesn't understand or is not willing to invest some time to run the demo. What impression do I leave there, if a user downloads my demo and it simply does not work ? I'm currently providing the app as a plain old eclipse zip file. One thing users do with it, is extract it over the old installation. Sh... One other problem I find is that the app need at least Java 5 to run, and sometimes there isn't java installed at all. One time some admin changed the jvm on a linux box back to kaffe 1.4 for unknown reasons. As it worked before, we simply had no idea and the kaffe error message was so unknown to me. I now think of using an installer and ship the client with a bundled jre. that makes some more megabytes, but I guess it could improve the overall experience.

What I want to know is: how do you build your distributions ?

PS: Forgot to tell that it needs to be cross - platform ...

Monday, March 29, 2010

Eclipse is hard to learn - what I think e4 should learn

I've been developing RCP apps for a while now. I'm not to deep into modeling (what seems to be the hype these days), I focus on ordinary user intefaces and solid business backends. I have been teaching RCP programming for a while, but now I'm back into coding full time.

I do not think I know every secret of the platform, but I am able to build useable applications, I made some progress with RAP and RIENA lately, which I both seem to like.

Teaching RCP programming reminded me always of what it was to me, at least a really hard learning curve. So many times it seemed to be guesswork when something didn't work as expected, a single typo in plugin.xml and the view doesnt show up, forgot the icon for an editor, the editor doesnt show and its all up to you and your google skills to solve the problem. So in the meantime e4 is coming up, what I like is the idea of dependency injection, what I have to get used to, is that modeling is there now, too. But what I truly think should be there is a clear diagnosis option. One should be able to get a clear answer to "why it doesnt work". Even if I think of the OSGI output if there is something wrong in the bundles dependencies. Last time I had a wrong version number in a plugin. It once again was pure guesswork to find the error.

Coding for over 20 years gave me many dislikes, and these days I really wonder how I will manage to do this for the next 20 years. I love coding, and I think that RCP is truly a powerful platform. But it should make some more noise in terms of predictability and it should be easier to understand. I've been teaching old dogs and youngsters and all of them had these moments of "why must this be so complicated".

e4 should be easier to learn and understand, thats what I think should be the primary goal. It must be an attractive platform to developers, no matter what level of experience they have. Every Newbie can learn to to some VBA code with Microsoft Access and even though it has its limitations, thats what eclipse should be too. Easy too learn and with a clear message on the reason of failure.

Last time I had a user report a bug that entries in a table got duplicated when he tried to use my dialog. It was just that I did'nt call TableViewer.cancelEditing in some special usage scenarios. A TableViewer  is an all over present interface element. Even after years of using it, I simply didn't know of the necessity to call cancelEditing. When its so hard for me, with so many years of coding, and a true motivation behind it, how does this appear to the newbie ?

Thursday, March 11, 2010

SWT: Drop an Outlook Email

I wanted to drop an outlook email to my RCP application and as always I asked google to help me. You don't find much on this, an older post was
http://www.eclipse.org/forums/index.php?t=msg&&th=147516&goto=464661

That got me startet. The damn it didn't work, I asked on the forum again and the answer made confusion even greater:

http://www.eclipse.org/forums/index.php?t=rview&goto=519397#msg_519397

gladly my wife gladly does some more windows thingy's with c# and with her help and a c# example i found out that i have to make an os call to get the type of the transfer that may change with every boot.

public static int registerType() {
// Look name up in the registry
// If name is not in registry, add it and return assigned value.
// If name already exists in registry, return its assigned value
TCHAR chFormatName = new TCHAR(0, "FileContents", true);
return OS.RegisterClipboardFormat(chFormatName);
}
Then at least the stuff from the first post started to do something, i could get an IStorage and enumerate over the STATSTG's

public Object nativeToJava(TransferData transferData) {

IDataObject idata = new IDataObject(transferData.pIDataObject);
idata.AddRef();
FORMATETC formatetc = new FORMATETC();

STGMEDIUM stgmedium = new STGMEDIUM();
formatetc.cfFormat = type;
formatetc.lindex = 0;
formatetc.ptd = 0;
formatetc.tymed = 4 | 8 | 1;
formatetc.dwAspect = COM.DVASPECT_CONTENT;
transferData.result = getData(idata, formatetc, stgmedium);
idata.Release();
if (transferData.result != COM.S_OK) {
System.out.println("Fehler" + transferData.result);
return null;
}

if ((stgmedium.tymed & 8) == 8) {
// IStorage
IStorage storage = new IStorage(stgmedium.unionField);
storage.AddRef();
long[] x = new long[1];
long ret = storage.EnumElements(0, 0, 0, x);

IEnumSTATSTG enumSTATSTG = new IEnumSTATSTG(x[0]);
enumSTATSTG.AddRef();
STATSTG[] data = new STATSTG[0];
// Loop over enumerator
long rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, STATSTG.sizeof);
int[] pceltFetched = new int[1];
enumSTATSTG.Reset();
while (enumSTATSTG.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
STATSTG statstg = new STATSTG();
COM.MoveMemory(statstg, rgelt, STATSTG.sizeof);
STATSTG[] newData = new STATSTG[data.length + 1];
System.arraycopy(data, 0, newData, 0, data.length);
newData[data.length] = statstg;
data = newData;
}
OS.GlobalFree(rgelt);

enumSTATSTG.Release();

// do something with STATSTG[]

but i still did not know what the heck to do with these objects. I started to search again and finally found an example in the eclipse OleClient:

private byte[] readStream(IStorage storage, String stream) {
boolean success = false;

long[] address = new long[1];
// Look for a CONTENTS stream
if (storage.OpenStream(stream, 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) {
IStream tempContents = new IStream(address[0]);
tempContents.AddRef();

try {
ByteArrayOutputStream w = new ByteArrayOutputStream();

int increment = 1024 * 4;
long pv = COM.CoTaskMemAlloc(increment);
int[] pcbWritten = new int[1];
while (tempContents.Read(pv, increment, pcbWritten) == COM.S_OK && pcbWritten[0] > 0) {
byte[] buffer = new byte[pcbWritten[0]];
OS.MoveMemory(buffer, pv, pcbWritten[0]);
w.write(buffer);
success = true;
}
COM.CoTaskMemFree(pv);

w.close();
return w.toByteArray();
} catch (IOException err) {
} finally {

tempContents.Release();
}

}
return null;
}

now with that I can read Streams from the IStorage. What streams there are is in the STATSTG's

// do something with STATSTG[]
Map result = new HashMap();
for (STATSTG s : data) {
String stream = getString(s.pwcsName);
result.put(stream, readStream(storage, stream));
}

storage.Release();
return result;
There we are. The IStorage contains the data in the .msg Format that I return in some strange way via the Map. I don't know how to get the .msg in one piece, but at least with some informations from

http://www.fileformat.info/format/outlookmsg/

I can now extract the contents of the message and push it to jackrabbit ;) The code in these examples is for x86_64, you may need some ints for the adresses on 32bit windows.

Friday, March 5, 2010

Customize your index with hibernate search 3.2

Today I got my hands on a recent snapshot build of hibernate search 3.2. The main thing I'm interested there is the programmatic configuration of the search index, a feature that I have been waiting for a long time.

http://in.relation.to/Bloggers/HibernateSearch32ProgrammaticMappingAPI

Every now and then I have requests from users to add field xy to the searchable index. Now I can build an extension to enable my users to add fields by themselves to the index. With some introspection this should be not so hard to build. What I still have to think about is how to make that useable, because we have quite complex object graphs that need to be explored. Guess that will go in a Tree.

I think of reading the configuration from XML, because at configuration time of the EntityManagerFactory I would have to make plain sql connections and thinking of the tree based nature of the thingy xml seems to be the right choice. Maybe build some pojos and serialize them with JAXB.

The pain will be that I need to enable the admins to restart the server by request. Now that goes only through a script (or the tanuki service adapter on windows). I need to recreate the whole index if the configuration has changed, that will take some time. But I don't see how this can be done a less painless way.

Can't wait to find some time to implement that.

Sunday, February 28, 2010

Eclipse Enterprise: Not so optimistic locking - a simple approach with XMPP

We work an a rather small enterprise app with a "Plain Old" Eclipse RCP Client. Due to some constraints our domain model is based on Pojos (Java Beans) that are persisted with a hibernate backend. In the meantime I look on those who use EMF/CDO/Riena with somehow jealous eyes, because of all the nice things they can do, but we cant do so easily. Since we don't have much concurrency, we rely on hibernates optimistic locking strategies to avoid conflicts. That means if two users work on the same entity, the one who saves early wins, the other one looses his changes and gets an OptimisticLock Exception. Thats sometimes annoying for the users. So I did a simple "not so optimistic" locking approach today that cost me less than half a day to implement for the whole thing. Our server communication -in terms of services- relies on Spring's HttpInvoker so far (keep it simple) but we cannot do callbacks to the client with that technology. We tried different ideas to solve that issue starting from JMS to finally ending with an XMPP based messaging solution. Every client sets up a permanent XMPP connection to the server over wich we can send messages to whatever party we want. With XMPP we can even see who is online for free. Now every time we open an editor we send a simple XMPP Message to the server that stores a unique id and the userId of the entity in a simple HashMap. If two users open the same entity, they both get a warning message about a potential conflict. With a simple PartListener on the client we know when an editor gets closed, send an unlock message and notify the other user(s) about the unlock. Thats what we get with about three hours of work. Never thought it would that simple. I become more and more a fan of XMPP Messaging.

Outlook:
What we could do now is register an hibernate "onPersist" event listener and send a message to the other parties that the object has changed on the server, so that they could refresh their editor content. Maybe thats something for the next weekend session.

PS: Some hours later...

I build an abstract base class for my Editors that does the following:


public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
super.init(site, input);
Object entityFromInput = getEntityFromInput(input);
EntityPacketFilter filter = new EntityPacketFilter(entityFromInput);
Activator.getDefault().getXmppConnection().addPacketListener(this,filter);
LockHelper.sendLockMessage(entityFromInput, true);
site.getPage().addPartListener(LockPartListener.instance);


}


The Editor sends a lock message on init, and registers a Partlistener to send an unlock on close; It adds itself as a PacketListener to the XMPP Connection. The hibernate PostUpdateEvenListener sends an Update Stanza which goes to:



EntityChangedDialog dlg = 
new EntityChangedDialog(AbstractLockingFormEditor.this);
int ret = dlg.open();
if (ret == Dialog.CANCEL) {
 PlatformUI.getWorkbench().getActiveWorkbenchWindow()
  .getActivePage().closeEditor(AbstractLockingFormEditor.this,   
  false);
  return;
}
// reload from db
IEditorInput newInput = EntityEditorManager.getInstance()
 .createInputForEntity(dlg.getEntityClass(),dlg.getEntityId());
setInput(newInput);
rebind() // rebuild databinding;
firePropertyChange(EditorPart.PROP_INPUT);
dirty = false;
setDirty(false);
firePropertyChange(EditorPart.PROP_DIRTY);


That's it. No more Optimistic Lock Exceptions from today.

Friday, February 26, 2010

XMPP Server Apache Vysper

For those who are in trouble with the GPLv3 license of openfire and other XMPP servers, I found a subproject of Apache Mina called Vysper which aims to implement an XMPP Server under an Apache License. It is still  not released yet, I just build a snapshot with maven and started off to play with it. It seems easy to provide your own extensions (I need to connect to my users database) and it works fine with the smack client api. There come InMemory and JCR (jackrabbit) storage adapters with it, no support for jdbc storage right now. I guess I will go with InMemory because I don't need persistence over Server restart right now. You can find the project here: http://mina.apache.org/vysper/

Sunday, February 21, 2010

Auditing with hibernate envers

I used the weekend to play around with hibernate envers. Envers is a framework that enables you to audit your database changes with hibernate. It was really easy to setup, just add the jar and set some configuration parameters. You have to add the envers listeners to your EntityManagerFactory and from then on every entity annotated with @Audited stores all changes in a seperate audit table. Envers enables you to look at each revision of your entity and track back your complete history. Since Envers stores eachs revision completely, I wrote some code to make a diff on my entities. That was quite tricky, because of my entities equals and hashcode methods compare id and version. Since different revisions have different versions I could not rely on that to work. But with some "frickeling" I made it work in a day. I now can show the change history of my Objects, you can even see the user that made the changes (a little spring aspect sets a threadlocal on the envers audit listener).


Envers will be part of hibernate 3.5, and as I have seen so many tricky auditing solutions before, I guess it could become a standard for hibernate auditing issues.

Monday, January 18, 2010

Spring DM & Hibernate on RAP: The classloading hell

In the meantime I set up a RAP application with a hibernate backend that will be integrated through spring DM. Since the hibernate libraries are not bundle-ified I went throught the overall known classloading hell. I had trouble with the Spring LocalContainerEntityManagerFactoryBean, that did not find my persistence unit, although I found some different posts suggesting that it should work. I changed



persistenceXmlLocation to classpath:META-INF/persistence.xml



so it looks in my bundle and there it is. With the default setting "classpath*:META-INF..." it simply seemed to find the file, but couldn't find my persistence units. 


Has anyone made the same experiences ?


I'm looking forward to work with the osgi-ified spring services in the app now.

Wednesday, January 13, 2010

Strange behaviour of while on linux

Last night I had I strange fight with java on linux. I tried to unzip a zip archive with java.util.zip with something like

zipEntry = zipStream.getNextEntry();
while(zipEntry!=null){
   // unzip
   zipEntry==zipStream.getNextEntry();
} // end while

This worked like a charm on windows but on linux the vm left the while loop, although, proveable, zipEntry was not null.

I changed the loop to

while ( (zipEntry=zipStream.getNextEntry()) != null)

and now it works on linux too. I feel completely confused about this behaviour. Maybe I should open a bug, as I can reproduce it with a large zip stream. In the meantime I learned a lot about encoding troubles with zip archives, and that the ant zip task doesn't use util.zip but it's own implementation that doesnt encode filenames with UTF-8 on windows like util.zip does.

Saturday, January 9, 2010

SSH on Android

Recently I downloaded ConnectBot on my android phone. I now can login to my online server from everywhere I have a mobile network connection. Just for the sake that I have to restart jetty for some strange reasons once again.

Friday, January 1, 2010

My first real RAP application

Over the christmas holidays I found some time to build my first real app with RAP. It took my two days to set up a little webshop, that is bound to our buchmanager backend (its a now commercial app for the german book producer market). As our customers have all relevant information about their products already in our database, I always thought it would be nice to integrate a webshop based on this information. I was completely surprised in how little time I could build this application (took me two days coding, another hard day spent on deploying the app). You can have a look at it on http://www.buchmanager.com (sorry but it's in german only for now) You can select from different categories and do a text search (has a hibernate search/lucene backend). I didn't spent much time on themeing and reused a theme from the examples with my own logo in it. Once again I was completely surprised how fast I could develop a nice ajax frontend, the backend only needed some extensions to store the orders you can make in the shop. Things I am not so happy with are that I have to run two instances of eclipse most of the time, as our "usual" eclipse RCP client needs a different target platform. I wonder if eclipse could build against multiple target platforms in the same workspace one time. I really had a hard time deploying the application. We have an embedded jetty already present in our backend, so I wanted to build a war file I could simply put on our embedded jetty. But tooling is poor there and the ConigfIniCreator that comes with the example deployment scenario left out org.eclipse.equinox.servletbridge.extensionbundle from the list of bundles to start. The BridgeServlet then gave me a simple 404, digging in the code told me that it couldn't reach its delegate servlet, but gave me no idea about what's missing. Luckily I had an example build of a Hello World app that worked before and there I found the missing entry. To all the RAP engineers, tooling can be improved. I spent a whole day to fix this. But now I have a nice new feature in our book management application. Just waiting for hibernate search 3.2 which promises to make the index dynamically configurable (now its hard coded in annotations). RAP is way cool if you know have to do RCP code, that's my overall conclusion.

Jupyter Kernel for Java9