Monday, July 25, 2011

Orion PHP Support demo

If you're following Eclipse planet, you couldn't have missed Karol Gusak's weekly status reports about PHP support that's being built for Orion.



If you still haven't tried PHP in Orion yourself, here's a little demo now on YouTube that nicely shows syntax highlighting, content-assist as well as overall PHP experience in Orion. Click below to check it now.

Thursday, July 21, 2011

Making extensible GUI with org.eclipse.ui.menus

It's actually first time I had to make a custom part of GUI extensible. In an Eclipse forms editor like following, we wanted custom actions to come from various plugins:



Since eclipse APIs provides this sort of extensibility with their org.eclipse.ui.menus extension point, I looked at how to reuse that mechanism. It turns simple. All you need to do is, while creating the editable area, add:


final Composite parent = ... // that's the area we want to make extensible

ContributionManager contributionManager = new ContributionManager() {
public void update(boolean force) {
for (IContributionItem item : items) {
item.fill(parent);
}
}
};

IMenuService service = (IMenuService) getSite().getService(IMenuService.class);
contributionManager.add(new GroupMarker("testing"));
service.populateContributionManager(contributionManager, "toolbar:org.zend.editor1?after=testing");
contributionManager.update(false);


Now to contribute something to that area, you need to extend org.eclipse.ui.menus extension point:

<extension point="org.eclipse.ui.menus">
<menuContribution allPopups="false"
locationURI="toolbar:org.zend.editor1?after=testing">
… Your contributions here …
</menuContribution>
</extension>

So now, if you for example prepared some commands in advance, you can easily link them without any extra coding. Since I wanted some nice looking link, I used control contribution. It let's you create entirely custom widget.

See the end result:



Lessons learned:
1. When specifying locationURI, it's worth choosing 'toolbar', over 'menu' or others because only 'toolbar' locations support custom control contributions.
2. Only supported URI parameters are 'after', 'before' and 'endof'. When using different parameters, I'm not sure how (if at all) it will be handled and where exactly your contribution will be landed.
3. Not quite sure why, but all the existing docs that I have come accross, only say how to use menus extension point in standard places like view menubar, window toolbar, etc. Nothing about re-using whole mechanism..

Thursday, July 14, 2011

Starting and immediately using OSGi bundle: possible?

Lately I had this little thing to do: an OSGi bundle (SuperTool) comes with some other OSGi bundle (GreatSdk) included.
SuperTool depends on logic in GreatSdk so the first thing it needs to do during activation is to install GreatSdk and immediately after that start loading classes from GreatSdk.

At first thought it seems logical to make SuperTool-GreatSdk dependency optional, to let SuperTool install and start safely without GreatSdk. Once installed, during startup SuperTool should install GreatSdk and start using it, for example:


BundleActivator.start(BundleContext context) {
greatSdk = context.installBundle("file:///path/to/great.sdk_1.0.0.jar");
greatSdk.start();

GreatSdkStarter gss = new GreatSdkStarter(); // separate class in SuperTool that references some classes from GreatSdk
gss.start(); // creates some GreatSdk classes
}


Unfortunately this fails in gss.start() with ClassNotFoundException:


java.lang.ClassNotFoundException: greatSdk.Sdk
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:513)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at supertool.GreatSdkStarter.start(GreatSdkStarter.java:8)
at supertool.Activator.start(Activator.java:63)


What does work is reflectively creating GreatSdk class instance via obtained Bundle:


// again in superTool activator.start()
Class clazz = b.loadClass("greatSdk.Sdk");
Object ob = clazz.newInstance();


So problem seems to be in the SuperTool information about the world. It looks like SuperTool is not yet aware that greatSdk was installed in the meantime.

Another thing that works is refreshing SuperTool via OSGi console:


osgi> start superTool
// loads greatSdk, but fails with ClassNotFoundException for classes referenced in GreatSdk
java.lang.ClassNotFoundException: greatSdk.Sdk....
osgi> ss
,,,
1 ACTIVE greatSdk
2. RESOLVED superTool

osgi> refresh superTool // magic
osgi > start superTool


After the refresh, starting superTool again makes it properly see greatSdk. Unfortunately doing refresh from within superTool activator.start() doesn't work so sweet. PackageAdmin.refreshBundles(superTool) terminates successfully, but CNFE is still thrown.

What's other way to activate and immediately use optional dependencies in an OSGi bundle?


(Except 'don't do it' :-) )

Wednesday, July 13, 2011

Installing V8Cgi on Mac

V8CGI is a very thin Apache module encapsulating V8 - Google's JavaScript engine that's used e.g. in Google Chrome. Those concerned with NodeJS stability may consider V8CGI a better choice, thanks to stability provided by Apache base.

A short while ago, on DevMeetings.pl DevCamp we've been playing with V8CGI, RingoJS and Node. Thanks to good performance, intuitive and high quality APIs, V8CGI turned out to be the black horse of the whole event, although installing it on Macs was little tricky.

Readers with Windows and Linux should follow to V8CGI home page, where they can get precompiled Windows binary and learn how to install binary on Ubuntu.

Mac users, let's open terminal and try to build the V8 apache module ourselves.

Getting V8CGI to work is four steps:
1. Getting the source code
2. Building it
3. Configuration
4. Test drive

1. Getting the source code
When checking out sources from SVN, we actually need two packages V8 and V8CGI:
a) svn checkout http://v8cgi.googlecode.com/svn/trunk/ v8cgi
b) svn checkout http://v8.googlecode.com/svn/trunk/ v8

You should end up with two new directories: v8 and v8cgi. When downloading a ready package from V8CGI home page, V8 sources are already included.

2. Build V8 and V8CGI
We'll use scons - a software construction tool. A good way to get started with scons is:
scons -Q -h

It gets you a list of available build configuration options. Worth visiting when you hit a wall compilation errors.

Let's first build V8:

cd v8
scons library=shared arch=x64
sudo cp libv8.dylib /usr/lib/libv8.dylib

We need x64 arch, as that's default Mac's Apache architecture. As a result your newly built libv8.dylib should be now available in /usr/lib directory.

Now let's build V8CGI.

cd ../v8cgi
scons module=1 mysql=0 gd=0 apache_path=/usr/include/apache2/ apr_path=/usr/include/apr-1/

Note that I added some extra options (run scons -Q -h for list of all options):
mysql=0 - disabled mysql support, that is on by default. Not quite sure if all I need to enable this option is on my Mac, and I don't need mysql for now, so let's just disable it.
gd=0 - disabled image-processing library 'gd', that is on by default. Same as with mysql, let's try without gd for start.
apache_path and apr_path - that's the path to Apache header files. Necessary to build against our HTTP server.

For me this command ends up with following error:

Undefined symbols for architecture x86_64:
"_iconv_open", referenced from:
ByteStorage::transcode(char const*, char const*)in bytestorage.os
"_iconv", referenced from:
ByteStorage::transcode(char const*, char const*)in bytestorage.os
"_iconv_close", referenced from:
ByteStorage::transcode(char const*, char const*)in bytestorage.os
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
scons: *** [mod_v8cgi.dylib] Error 1
scons: building terminated because of errors.

Above error message says that 'iconv' library is missing for our architecture x86_64. Iconv is used for converting different character set encodings, like UTF to ISO, ISO to ASCII, etc. It's not critical part of V8CGI, specially if you only want to evaluate that technology.

For evaluation purposes, we could just rip out the iconv calls from v8cgi source code but let's build iconv ourselves. Create another directory "iconv" next to v8 and v8cgi and execute following steps there:

curl -O http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.11.tar.gz
tar -zxvf libiconv-1.11.tar.gz
cd libiconv-1.11
./configure
make
make install

Note that latest iconv library is 1.13.1. We're using 1.11, because that one is compatible with iconv version included by default on Mac. Building with 1.13 you will end up with following error when trying to start apache next time:

httpd: Syntax error on line 118 of /private/etc/apache2/httpd.conf:
Cannot load /usr/local/apache2/modules/mod_v8cgi.dylib into server:
dlopen(/usr/local/apache2/modules/mod_v8cgi.dylib, 10):
Library not loaded: /usr/local/lib/libiconv.2.dylib\n
Referenced from: /usr/local/apache2/modules/mod_v8cgi.dylib\n
Reason: Incompatible library version: mod_v8cgi.dylib requires version 8.0.0 or later, but libiconv.2.dylib provides version 7.0.0

Let's go back to v8cgi directory and continue it's build. We need two extra params to link our new iconv module:

scons module=1 mysql=0 gd=0 \
apache_path=/usr/include/apache2/ \
apr_path=/usr/include/apr-1/ \
libpath=/usr/local/lib cpppath=/usr/local/include

The build proceeds few steps forward and fails again with:

g++ -o mod_v8cgi.dylib -bundle -bundle_loader /usr/sbin/httpd src/common.os src/system.os src/cache.os src/gc.os src/app.os src/path.os src/lib/binary/bytestorage.os src/mod_v8cgi.os -L/Users/jacek/Downloads/aa/v8 -L/usr/local/lib -lv8 -lv8 -lapr-1 -laprutil-1
Undefined symbols for architecture x86_64:
"_libiconv_open", referenced from:
ByteStorage::transcode(char const*, char const*)in bytestorage.os
"_libiconv", referenced from:
ByteStorage::transcode(char const*, char const*)in bytestorage.os
"_libiconv_close", referenced from:
ByteStorage::transcode(char const*, char const*)in bytestorage.os
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
scons: *** [mod_v8cgi.dylib] Error 1
scons: building terminated because of errors.

This time, compilation of v8cgi library is almost done, but breaks on gluing everything together. Let's invoke the same command adding -liconv:

g++ -o mod_v8cgi.dylib -bundle -bundle_loader /usr/sbin/httpd src/common.os src/system.os \
src/cache.os src/gc.os src/app.os src/path.os src/lib/binary/bytestorage.os src/mod_v8cgi.os \
-L/Users/jacek/Downloads/aa/v8 -L/usr/local/lib -lv8 -lv8 -lapr-1 -laprutil-1 -liconv


And success! No errors and your mod_v8cgi.dylib is out there, ready to try.

Configuration
Configuration is pretty well described in v8cgi/INSTALL text file so I'll just copy it here:

sudo cp v8cgi.conf.posix /etc/v8cgi.conf


- configure /etc/v8cgi.config
sudo vi /etc/v8cgi.conf
require.paths.push('~/src/v8cgi/lib');


- configure the apache module:
sudo vi /etc/apache2/mods-available/v8cgi.load
* The only line in the file should be:
LoadModule v8cgi_module ~/src/v8cgi/mod_v8cgi.so
--
sudo vi /etc/apache2/mods-available/v8cgi.conf
* The only line in the file should be:
AddHandler v8cgi-script .sjs .ssjs .jst


Restart Apache and you're ready to go!

Tuesday, July 5, 2011

Search by multiple keys in CouchDB

While developing a simple Twitter clone on V8CGi + CouchDB stack, we faced an interesting problem.
We have a CouchDB database with users and messages. Each user has many followers and he'd like to see messages from all these
followers. So we need to query tweets database for all documents that have author belonging to the list.
In SQL it's something as simple as:

SELECT * FROM tweets WHERE author IN ("szymon", "wiktor", "marek") SORT BY timestamp;

In CouchDB it turned out to be an open issue https://issues.apache.org/jira/browse/COUCHDB-523

As far as I remember we ended up with running two separate queries. I'd be happy to hear how others solved this!