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.

Jupyter Kernel for Java9