tag:blogger.com,1999:blog-25282456472724151222024-03-19T10:50:32.429+01:00Phil on developmentMy thoughts and ideas about software development in the Java and C++ realmUnknownnoreply@blogger.comBlogger16125tag:blogger.com,1999:blog-2528245647272415122.post-30529563239794997762010-02-20T16:05:00.004+01:002010-02-21T00:30:09.954+01:00CopyTo...Pastebin (and others) Plug-In for Eclipse<h2>The situation</h2>
<p>
Do you hang out in IRC channels often? And do you use pastebin.com or other services to show the users snippets of your source code that illustrates a problem you have? Then you no longer need to switch between your Eclipse IDE, a webbrowser and the IRC chat window.
<h2>A small solution that can save time</h2>
<p>
I have finished today the <a href="http://pke.github.com/CopyTo/">first alpha version</a> of a small Eclipse Plugin that adds a new menu and toolbar button to the Eclipse Workbench.
<p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://content.screencast.com/users/philk/folders/Jing/media/877a491f-33b9-4617-bd1a-62c747119053/2010-02-20_1413_copyto_popup_menu.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 408px; height: 221px;" src="http://content.screencast.com/users/philk/folders/Jing/media/877a491f-33b9-4617-bd1a-62c747119053/2010-02-20_1413_copyto_popup_menu.png" alt="" border="0" /></a>
<p>
In its basic version it allows you to click any resource in the Package/Project Explorer and copies the content of the resource to the pastebin service of your choice. I have created some default configurations for the most used ones. The one working most stable is "pastebin.com". "Codepad.org" is experimental and "pastebin.ca" returns invalid URLs in its JSON response. I have contacted the author of the service already. They merely serve as samples and I am sure most users will just use "pastebin.com". And if you choose to only install one "Target", like "pastebin.com" then there will be no submenu but you can directly select "Copy to pastebin.com" as shown below:
<p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://content.screencast.com/users/philk/folders/Jing/media/f45d86c0-9386-405b-b850-074869d631e6/2010-02-20_1615_copyto_single_target.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 155px; height: 141px;" src="http://content.screencast.com/users/philk/folders/Jing/media/f45d86c0-9386-405b-b850-074869d631e6/2010-02-20_1615_copyto_single_target.png" alt="" border="0" /></a>
<p>
The targets are configurable in the preferences and are persisted in your Eclipse configuration location. That means you do not have to re-configure the targets for each workspace (a feature I would wish for a lot of Eclipse options to be the default).
<p>
You can also install the "CopyTo JDT" feature which allows you to copy Java methods or classes from the Outline view, the source editor or the Package Explorer. For "pastebin.com" this will also enable Java syntax highlighting. Since the whole plugin code is available at github others could contribute specialized modules for Ruby, PHP, etc.
<p>
After the selected content was sent to the target and the target returned a valid redirection URL (or JSON response, that contains a URL) there are several actions possible. The default action is the "Copy to clipboard" action which is supplied by default.
<p>
You can install additional "PasteTo" actions like for direct pasting into your favorite IRC client. <br/>
I have implemented support for Eclipse ECF (IRC) Chats (newest <a href="http://www.eclipse.org/ecf">ECF</a> 3.2 required) and some experimental for my favorite IRC client that comes with <a href="http://www.miranda-im.org">Miranda-IM</a> for Windows. You can see that in action in the <a href="http://www.screencast.com/t/NmZiNjBiN">video</a> below:
<p>
<object id="scPlayer" height="856" width="1206"> <param name="movie" value="http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/jingh264player.swf"> <param name="quality" value="high"> <param name="bgcolor" value="#FFFFFF"> <param name="flashVars" value="thumb=http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/FirstFrame.jpg&containerwidth=1206&containerheight=856&content=http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/2010-02-20_1229_copyto_action_selection.mp4"> <param name="allowFullScreen" value="true"> <param name="scale" value="showall"> <param name="allowScriptAccess" value="always"> <param name="base" value="http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/"> <embed src="http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/jingh264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/FirstFrame.jpg&containerwidth=1206&containerheight=856&content=http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/2010-02-20_1229_copyto_action_selection.mp4" allowfullscreen="true" base="http://content.screencast.com/users/philk/folders/Jing/media/ac4820b9-0759-403e-94e2-cd3350f7f824/" scale="showall" height="428" width="603"></embed> </object>
<p>
Of course having many actions will slow down your workflow so there will be a mechanism to select a default action and display the dialog only if you hold down the "CTRL" key. If there is only one action available, then no dialog will be displayed. And for the "Copy to clipboard" action you can disable the initial warning it gives you when the clipboard contains (probably) valuable data.
<p>
Unfortunately there is no way to get the "CopyTo" menu at a consistent place in popups and main menu. That's because some popup menus do not provide anchors or group-markers. And sometimes the group marker is below the seperator (Text editor popup). If anyone has an idea how to solve that placement problem he can say or change the source :)
<h2>Test it out</h2>
<p>
I am already using the plugin in my daily Eclipse life and if you want to give it a test run you can add the Update URL <a href="http://pke.github.com/CopyTo/update/">http://pke.github.com/CopyTo/update/</a> to your Eclipse Installation. Don't forget to select at least the main feature and the "pastebin.com target".
The update manager will warn you that the features are not signed but you can safely ignore the message (if you trust my code :)
You need to restart the workbench to get the pastebin.com configuration visible to "CopyTo". That's currently an <a href="http://github.com/pke/CopyTo/issues#issue/1">known issue</a>.
</p>
<p>
I would like to hear from you, especially if you have suggestions for the workflow.
</p>Unknownnoreply@blogger.com9tag:blogger.com,1999:blog-2528245647272415122.post-48858910056077122082010-02-13T09:08:00.007+01:002010-02-13T11:17:55.168+01:00ServiceRunnable - Easier use of OSGi service trackers<h3>The situation</h3>
Sometimes you cannot use the beauty of DS (ie. in Eclipse Workbench classes, that are instantiated by the Workbench) and have to revert back to the next best thing in the OSGi world when working with services. The <span style="font-family:courier new;">ServiceTracker</span>.
If you want to use a certain service in your command handlers <span style="font-family:courier new;">execute</span> method you would have to create a service tracker, query it for the service, and call the services method like this:
<pre>
// Somewhere in your code
private static final ServiceTracker tracker = new ServiceTracker(
FramworkUtil.getBundle(MyClass.class,
EventAdmin.class.getName(),
null) {
{ open(); }
};
Object execute(ExecutionEvent event) {
EventAdmin eventAdmin = (EventAdmin)tracker.getService();
if (eventAdmin != null) {
eventAdmin.postEvent(new Event("EVENT/TOPIC", (Map)null));
}
return null;
}
</pre>
Or lets say you have a service that returns a collection of items:
<pre>
Collection<Car> listAllCars() {
CarService carService = (CarService)carServiceTracker.getService();
if (carService != null) {
return carService.findAll();
}
return Collections.emptyList();
}
</pre>
As you can see, there is always boyer-plate code involved (and I am already using a shortcut to open the tracker) including null checking and we have not even looked on fall-back code, that should be executed if the service is not available. Let's say we want to log something with the OSGi <span style="font-family: courier new;">LogService</span> but if its not available we will just print to the standard output stream.
<pre>
public static void log(int level, Throwable t, String message, Object... args) {
final String text = String.format(message, args);
LogService logService = (LogService)tracker.getService();
if (logService != null) {
logService.log(level, text, t);
} else {
System.out.println(text);
}
}
</pre>
Again we would have to create the the service tracker and check if the service is available. What, if we could do that all in one call?
<h3>Introducing Trackers</h3>
We could have a small helper class "<span style="font-family: courier new;">Trackers</span>" that creates service trackers for use automatically and executes a piece of code depending on the availability of the requested service. From the JDK we all know the Runnable interface. We will just take the idea a step further and give its run method a parameter, much like Eclipse's <span style="font-family: courier new;">ParameterizedRunnable</span>. But instead of doing it the Java 1.4 way we use generics like this:
<pre>
public interface ServiceRunnable<T> {
void run(T service);
}
</pre>
The code in the <span style="font-family: courier new;">run()</span> method is only executed if there is a Service that publishes itself with the type "<span style="font-family: courier new;">T</span>". Our helpers class static method would look like this:
<pre>
public final class Trackers {
public static <T> void run(Class<T> serviceClass, ServiceRunnable<T> runnable) {
T service = getService(serviceClass);
if (service != null) {
runnable.run(service);
}
}
}
</pre>
And we would call it like this:
<pre>
Trackers.run(EventAdmin.class, new ServiceRunnable<EventAdmin>() {
void run(EventAdmin service) {
service.postEvent(new Event("EVENT/TOPIC", (Map)null));
}
});
</pre>
<h3>Who tracks the services?</h3>
Above you saw the not further explained call to "<span style="font-family: courier new;">getService(serviceClass)</span>". That's where <span style="font-family: courier new;">Trackers</span> fetches the service. And in case there is no tracker for it yet, it will create one for this service.
It keeps a map of ServiceTracker, on for each service class you request.
<pre>
private static <T> T getService(final Class<T> serviceClass) {
ServiceTracker tracker = trackers.get(serviceClass);
if (null == tracker) {
tracker = createTracker(serviceClass);
trackers.put(serviceClass, tracker);
}
// Safe to cast here, since OSGi already checks the returned service.
return (T)tracker.getService();
}
</pre>
Creating the tracker is pretty standard:
<pre>
private static <T> ServiceTracker createTracker(final Class<T> serviceClass) {
ServiceTracker tracker = new ServiceTracker(
FrameworkUtil.getBundle(Trackers.class).getBundleContext(),
serviceClass.getName(),
null);
tracker.open();
return tracker;
}
</pre>
<h3>Some Sugar</h3>
Remember our sample about the car listings? Rewriting it using the new <span style="font-family: courier new;">Trackers</span> class it would like this:
<pre>
Collection<Car> listAllCars() {
Collection<Car> cars = Collections.emptyList();
Trackers.run(CarService.class, new ServiceRunnable<CarService> {
void run(CarService service) {
cars = service.findAll();
}
});
return cars;
}
</pre>
Looks ok, but can be improved. It would be nice if we could return a value from <span style="font-family: courier new;">Trackers.run()</span> so that our code would look like this:
<pre>
Collection<car> listAllCars() {
return Trackers.run(CarService.class, new ServiceRunnable<CarService, Collection<Car>> {
Collection<Car> run(CarService service) {
return service.findAll();
}
});
}
</pre>
This can be done by changing the run method as follows:
<pre>
public static <T, R> R run(Class<T> serviceClass, ServiceRunnable<T, R> runnable) {
final T service = getService(serviceClass);
if (service != null) {
return runnable.run(service);
}
return null;
}
</pre>
It would take into account a user specified return value. If no service was found the <span style="font-family: courier new;">run</span> method would now return null. So to fulfill our API contract of before (returning an empty list and not null) the final method would be:
<pre>
Collection<Car> listAllCars() {
Collection<Car> cars = Trackers.run(CarService.class, new ServiceRunnable<CarService, Collection<Car>> {
Collection<Car> run(CarService service) {
return service.findAll();
}
});
return cars != null ? cars : Collections.emptyList();
}
</pre>
This could further be improved if we would have a fall-back facility.
<pre>
public interface ServiceRunnableFallback<T, R> extends ServiceRunnable<T, R> {
R run();
}
</pre>
This simply introduces a new method that has no parameter but the same return value as the base interface. The Trackers class will use this interface if the service is not available:
<pre>
if (service != null) {
return runnable.run(service);
} else if (runnable instanceof ServiceRunnableFallback<?,?>) {
return ((ServiceRunnableFallback<T, R>) runnable).run();
}
</pre>
The car listing sample would then change to:
<pre>
Collection<car> listAllCars() {
return Trackers.run(CarService.class, new ServiceRunnableFallback<CarService, Collection<Car> > {
Collection<Car> run(CarService service) {
return service.findAll();
}
Collection<Car> run() {
return Collections.emptyList();
}
});
}
</pre>
Of course this is such a common use case, that we can create an abstract class for that, that will take the default return value in case the service is not available as a constructor argument:
<pre>
public abstract class DefaultServiceRunnable<T, R> implements ServiceRunnableFallback<T, R> {
private final R defaultReturn;
public DefaultServiceRunnable(final R defaultReturn) {
this.defaultReturn = defaultReturn;
}
public final R run() {
return defaultReturn;
}
}
</pre>
And voilá, the final car listing example:
<pre>
Collection<Car> listAllCars() {
return Trackers.run(CarService.class, new DefaultServiceRunnable<CarService, Collection<Car>>(Collections.EMPTY_LIST) {
Collection<Car> run(CarService service) {
return service.findAll();
}
});
}
</pre>
Now, the logging example from above does not return anything, so it would be nice if the code could be further simplified.
We create another abstract class that will implement the ServiceRunnableFallback methods for us and just return null:
<pre>
public abstract class SimpleServiceRunnable<T> implements ServiceRunnableFallback<T, Object> {
public final Object run(final T service) {
doRun(service);
return null;
}
public final Object run() {
doRun();
return null;
}
protected void doRun() {
}
protected abstract void doRun(T service);
}
</pre>
Note that this class marks the run(T) and run() as final so no subclass can override them but must doRun(T) instead. The abstract class has an empty body for doRun() in the case that the service is not available.
With that in place the logging example could be re-written like this:
<pre>
public static void log(int level, Throwable t, String message, Object... args) {
final String text = String.format(message, args);
Trackers.run(LogService.class, new SimpleServiceRunnable<LogService>() {
protected void doRun(final LogService service) {
service.log(level, text, t);
}
protected void doRun() {
System.out.println(text);
}
});
}
</pre>
I will upload the full source code to github soon, but to get you started here is full code of the Trackers class:
<pre>
public final class Trackers {
private static final Map<Class<?>, ServiceTracker> trackers = new HashMap<Class<?>, ServiceTracker>();
public static <T, R> R run(Class<T> serviceClass, ServiceRunnable<T, R> runnable) {
final T service = getService(serviceClass);
if (service != null) {
return runnable.run(service);
} else if (runnable instanceof ServiceRunnableFallback<T, R>) {
return ((ServiceRunnableFallback<T, R>) runnable).run();
}
return null;
}
private static <T> T getService(Class<T> serviceClass) {
ServiceTracker tracker = trackers.get(serviceClass);
if (null == tracker) {
tracker = createTracker(serviceClass);
trackers.put(serviceClass, tracker);
}
return serviceClass.cast(tracker.getService());
}
private static <T> ServiceTracker createTracker(Class<T> serviceClass) {
return new ServiceTracker(FrameworkUtil.getBundle(Trackers.class)
.getBundleContext(), serviceClass.getName(), null) {
{
open();
}
};
}
private Trackers() {
}
}
</pre>
The interfaces are all fully mentioned here, it'ss just a matter of copy&paste until everything is up on github.
As always the code mentioned on this blog is licensed under EPL 1.0, so feel free to use and enhance it.Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-2528245647272415122.post-86601752558363269992010-02-09T17:10:00.013+01:002010-02-09T19:51:33.723+01:00OSGi Clipboard Monitor for Java (on Windows using JNA)<p>
<i>
Before you read on you should be familiar with <a href="https://jna.dev.java.net/">JNA</a> and OSGi as I will make heavy use of it in this posting.</i>
</p>
<h3>Preface</h3>
<p>
For my <a href="http://philondev.blogspot.com/2010/02/copytopastebin-and-others-plug-in-for.html">CopyTo</a> Eclipse plugin's preference page I wanted to enable the "Paste" button for label/URL combinations only if there is some text in the clipboard (and that text can be converted to a "CopyTo" target). So I would need to monitor the content of the systems clipboard.
</p>
<h3>SWT to the rescue! ... not!</h3>
<p>
So I checked if <span style="font-family:courier new;">SWT</span> can already help me here. There should be a <span style="font-family:courier new;">Clipboard.addListener</span> method that would allow me to register a listener with the clipboard and let <span style="font-family:courier new;">SWT</span> notify me about changed clipboard content. Unfortunately there is no such functionality in <span style="font-family:courier new;">SWT</span>. And I would soon know why that is ;)
</p>
<h3>The long way... using a Windows Clipboard "Viewer"</h3>
<p>
Since I am developing on a Windows machine, I fired up the Windows SDK help to see what it offers in regard to the clipboard. There is a <a style="font-family: courier new;" href="http://msdn.microsoft.com/en-us/library/ms649052%28VS.85%29.aspx">SetClipboardViewer</a> function that in a somewhat awkward way let your window become part of the clipboard viewer chain. Windows will then send 2 specific messages to this windows message proc to inform it about clipboard changes (<a href="http://msdn.microsoft.com/en-us/library/ms649025%28VS.85%29.aspx">WM_DRAWCLIPBOARD</a>) or changes in the clipboard viewer chain (<a href="http://msdn.microsoft.com/en-us/library/ms649019%28VS.85%29.aspx">WM_CHANGECBCHAIN</a> , if someone else calls <span style="font-family:courier new;">SetClipboardViewer</span>).
</p>
<p>
The first thing that bugged me was, that I do not have a window that I could give to the function and that could receive messages from Windows. Then, I remembered my old Win32 coding days in C++ and that one can create a hidden window just for messages. Instead of creating my own window class for that I decided to use an existing one. The "<span style="font-family:courier new;">STATIC</span>" window class does not need a lot of resources and does not receive a lot of messages so its the perfect candidate. We will just create an invisible instance of such window using <span style="font-family:courier new;">JNA</span>:<p>
<pre>viewer = User32.INSTANCE.CreateWindowEx(0, "STATIC", "", 0, 0, 0, 0, 0, null, 0, 0, null);</pre></p>
<p>
Then we <span style="font-weight: bold;">register</span> the window with the <span style="font-weight: bold;">clipboard viewer</span> chain according to the API specs:</p>
<pre>nextViewer = User32.INSTANCE.SetClipboardViewer(viewer);</pre>
<p>
The next thing to do is to redirect all messages to a <span style="font-weight: bold;">custom window proc</span> instead of the default one of the "<span style="font-family:courier new;">STATIC</span>" window class. This is called "subclassing" in Windows and in a sense is something like class subclassing in the Java world. Only on a "message only" basis.</p>
<p>
Our new window proc will handle the two clipboard related messages and redirect the other messages to the original window proc of the "<span style="font-family:courier new;">STATIC</span>" window class.</p>
<pre>User32.INSTANCE.SetWindowLong(viewer, User32.GWL_WNDPROC, this.ourProc);</pre>
<p>
Please note that <span style="font-family:courier new;">ourProc</span> is a member field, so that the Java GC will not remove its reference and JNA would no longer be able to send messages to our callback!</p>
<p>
Thats how the callback looks like:</p>
<p>
<pre>
class OurProc implements WNDPROC {
public int callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case User32.WM_CHANGECBCHAIN:
// If the next window is closing, repair the chain.
if (nextViewer.toNative().equals(wParam.toNative())) {
nextViewer = new HWND(Pointer.createConstant(lParam.longValue()));
} // Otherwise, pass the message to the next link.
else if (nextViewer != null) {
User32.INSTANCE.SendMessage(nextViewer, uMsg, wParam, lParam);
}
return 0;
case User32.WM_DRAWCLIPBOARD:
try {
onChange(new ClipboardEvent(this));
} finally {
User32.INSTANCE.SendMessage(nextViewer, uMsg, wParam, lParam);
}
return 0;
case User32.WM_DESTROY:
User32.INSTANCE.ChangeClipboardChain(viewer, nextViewer);
break;
}
return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam);
}
</pre>
</p>
<p>
That's pretty much the code from the Windows SDK help for programming a Clipboard Viewer. There is some strange chain repairing code included. Speaking of bad API design. How easily could that break, if one programmer gets it wrong?
</p>
<h3>Polling the message queue without wasting CPU cycles</h3>
<p>
Now, for the sub-classed static window to receive any messages we need to poll the message queue. In Windows you can only poll your own threads message queue. And, important to know, Windows only creates a message queue if a thread creates a window or calls one of the message queue related functions like <a href="http://msdn.microsoft.com/en-us/library/ms644936%28VS.85%29.aspx">GetMessage </a>or <a href="http://msdn.microsoft.com/en-us/library/ms644943%28VS.85%29.aspx">PeekMessage</a>.
So a simple message poller in our threads run() method would look like this:
</p>
<pre>
while (User32.INSTANCE.GetMessage(msg, null, 0, 0)>0) {
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
</pre>
<p>
However, GetMessage is a blocking call and so our Thread would consume all the available CPU cycles it could get until a new message arrives in the queue. That's certainly not what we want. Instead we have to create more sophisticated message queue polling logic. We also want to be able to end our clipboard monitor at any given time. We do that by signaling a special Win32 kernel event object. The <a href="http://msdn.microsoft.com/en-us/library/ms684242%28VS.85%29.aspx">MsgWaitForMultipleObjects</a> allows us to wait for message to arrive in the queue as well as events that get signaled. So our new message polling loop that cost (almost) no CPU cycles looks like this:
<pre>
final HANDLE handles[] = { event };
while (true) {
int result = User32.INSTANCE.MsgWaitForMultipleObjects(handles.length, handles, false, Kernel32.INFINITE, User32.QS_ALLINPUT);
if (result == Kernel32.WAIT_OBJECT_0) {
User32.INSTANCE.DestroyWindow(viewer);
return;
}
if (result != Kernel32.WAIT_OBJECT_0 + handles.length) {
// Serious problem, end the thread's run() method!
break;
}
while (User32.INSTANCE.PeekMessage(msg, null, 0, 0, User32.PM_REMOVE)) {
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
}
</pre>
<p>
Please note that we poll all messages out of the queue until there are no more left and only then return to another round of <span style="font-family:courier new;">MsgWaitForMultipleObjects </span>until our halt event is signaled.
</p>
<p>
That's it about the gory details of implementing such a "viewer" in Windows (without displaying anything).
The hard thing to figure out was, that all user level related calls had to be made from the thread that will read out the message queue.
</p>
<p>
Why Microsoft decided to put the responsibility of a chain into the hands of the programmer is beyond me. Clearly bad API design.
</p>
<h3>Adding some spin - OSGi services</h3>
<p>
Of course when programming in Java I will always use OSGi whenever possible. The Clipboard Monitor is no exception. Granted, the whole code can be used without OSGi too. But then you would have to implement a kind of listener management yourself. That's up to the reader of this entry and I welcome everyone to contribute a plain old Java implementation of <a href="http://github.com/pke/clipboard.monitor/blob/master/clipboard.monitor.windows/src/clipboard/monitor/windows/AbstractWindowsClipboardMonitor.java"><span style="font-family:courier new;">AbstractWindowsClipboardMonitor</span></a> that integrates hand crafted listener management instead of using the OSGi service registry.
</p>
<p>
So there is a monitor component that will consume ClipboardListener services registered in the system and inform them about changes in the clipboard.
</p>
<h3>Listener that publishes an event using the EventAdmin</h3>
<p>
Now we can have a fairly simple listener that publishes an event on every clipboard change:
<pre>
public class EventAdminClipboardListener implements ClipboardListener {
private static final String TOPIC = "clipboard/monitor/event"; //$NON-NLS-1$
private final AtomicReference<eventadmin> ref = new AtomicReference<eventadmin>();
protected void bind(EventAdmin eventAdmin) {
ref.set(eventAdmin);
}
protected void unbind(EventAdmin eventAdmin) {
ref.compareAndSet(eventAdmin, null);
}
public void onEvent(ClipboardEvent event) {
EventAdmin eventAdmin = ref.get();
if (eventAdmin != null) {
eventAdmin.postEvent(new Event(TOPIC, (Map) null));
}
}
}
</pre>
<p>
Pretty simple.
</p>
<h3>The SWT Clipboard Listener service</h3>
<p>
Then we have this listener service that will examine the content of the clipboard and use the OSGi EventAdmin to publish specialized events with topics describing the content of the clipboard. EventHandler services can so easily react on specific changes in the clipboard.
The following event topics are currently implemented:
</p><ul>
<li>clipboard/monitor/swt/TEXT</li>
<li>clipboard/monitor/swt/URL</li>
<li>clipboard/monitor/swt/IMAGE</li>
<li>clipboard/monitor/swt/RTF</li>
<li>clipboard/monitor/swt/HTML</li>
<li>clipboard/monitor/swt/FILE</li>
</ul>
<p>
So you could register an EventHandler that reacts on changes in the clipboard, and only if the new clipboard content contains (also) text. Your EventHandler service would register with the topic set to "<span style="font-family:courier new;">clipboard/monitor/swt/TEXT</span>". The beauty of this componentized approach is that you do not even have to know that there is a clipboard monitor installed and running in the system. You have no dependencies on it. You simply register for events of a specific topic and get informed about changes. You can then use SWT to read out the clipboard.
</p>
<h3>Conclusion</h3>
<p>
I hope this rather lengthy posting gave you another clue what can be done using clean OSGi component design. And maybe some of you can even put the components to some use in your own projects. It's all licensed under EPL 1.0 so feel free to use the code.
<p><a href="http://screencast.com/t/NDU1NmFhOD">Here</a> you can watch a little video demonstration (if you cannot see the video below).</p>
<p>
<object id="scPlayer" width="578" height="460"> <param name="movie" value="http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/jingh264player.swf"></param> <param name="quality" value="high"></param> <param name="bgcolor" value="#FFFFFF"></param> <param name="flashVars" value="thumb=http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/FirstFrame.jpg&containerwidth=578&containerheight=460&content=http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/2010-02-09_1947_blog_clipboard_monitor_demo.mp4"></param> <param name="allowFullScreen" value="true"></param> <param name="scale" value="showall"></param> <param name="allowScriptAccess" value="always"></param> <param name="base" value="http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/"></param> <embed src="http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="578" height="460" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/FirstFrame.jpg&containerwidth=578&containerheight=460&content=http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/2010-02-09_1947_blog_clipboard_monitor_demo.mp4" allowFullScreen="true" base="http://content.screencast.com/users/philk/folders/Jing/media/f195f101-d804-443f-80ef-8b5c611cd867/" scale="showall"></embed> </object>
</p>
<h3>Code at GitHub</h3>
<p>
You are invited to check out the full source code over at <a href="http://github.com/pke/clipboard.monitor">GitHub</a> and you are invited to fork/clone and contribute, if you want. Maybe someone can add a GTK/Linux clipboard viewer?
</p>Unknownnoreply@blogger.com13tag:blogger.com,1999:blog-2528245647272415122.post-73820066265588543462010-02-05T22:40:00.005+01:002010-02-05T22:50:19.920+01:00P2 error messages are useless - for users and for me as a programmerI handed out the update site URL of my "copyto" Plug-in to a friend and when he wanted to install it, p2 threw this message at him:
<blockquote>Cannot complete the install because one or more required items could not be found.
Software being installed: codepad.org support 0.1.0.201002050243 (eclipseutils.ui.copyto.codepad.feature.feature.group 0.1.0.201002050243)
Missing requirement: eclipseutils.ui.copyto 0.1.0.201002050243 requires 'package org.eclipse.core.runtime.preferences 3.3.0' but it could not be found
Cannot satisfy dependency:
From: codepad.org support 0.1.0.201002050243 (eclipseutils.ui.copyto.codepad.feature.feature.group 0.1.0.201002050243)
To: eclipseutils.ui.copyto 0.0.0</blockquote>
I would guess that there is at least <span style="font-weight:bold;">one</span> package with the name "org.eclipse.core.runtime.preferences" installed and it would be very helpful if p2 prints out the available versions of that package. That would have made it easier for me to recognize, that 3.3.0 is obviously an Eclipse 3.6 package (I am using the I-Build as my target).
Beside that, this error message displayed to a non-programmer is equally useless. It's filled with cryptic numbers and too much information the average user cannot understand. Heck, I do not even understand it and then it's also missing crucial information for me as a programmer.
I <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=302010">filed a bug</a> to get at least the required information into the error message.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2528245647272415122.post-51120608281193125752010-02-05T11:43:00.004+01:002010-02-05T12:05:43.447+01:00CopyTo...Pastebin (and others) Plug-In for EclipseI am currently working on a small Plug-In that some of you might find useful (especially if you are hanging out in IRC a lot). The plugin allows you to select resources, classes or methods in Java projects and posts them to your favorite pastebin. After that it provides the URL of the pastebin entry in your clipboard so you can easily send it to others.
<a href="http://content.screencast.com/users/philk/folders/Blog/media/e1654251-1735-49d8-84f5-5efb27cec463/2010-02-05_1146_blog_copyto_preview.png"><img class="embeddedObject" src="http://content.screencast.com/users/philk/folders/Blog/media/e1654251-1735-49d8-84f5-5efb27cec463/2010-02-05_1146_blog_copyto_preview.png" width="497" height="629" border="0" /></a>
This <a href="http://www.screencast.com/t/MmJjM2Jj">little video </a>demonstrates this:
<object id="scPlayer" height="820" width="1026"> <param name="movie" value="http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/jingh264player.swf"> <param name="quality" value="high"> <param name="bgcolor" value="#FFFFFF"> <param name="flashVars" value="thumb=http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/FirstFrame.jpg&containerwidth=1026&containerheight=820&content=http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/2010-02-05_1142_blog_copyto_preview.mp4"> <param name="allowFullScreen" value="true"> <param name="scale" value="showall"> <param name="allowScriptAccess" value="always"> <param name="base" value="http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/"> <embed src="http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/jingh264player.swf" quality="high" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="always" flashvars="thumb=http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/FirstFrame.jpg&containerwidth=1026&containerheight=820&content=http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/2010-02-05_1142_blog_copyto_preview.mp4" allowfullscreen="true" base="http://content.screencast.com/users/philk/folders/Blog/media/f26b8f28-165d-49d7-9d65-3f51594e21e6/" scale="showall" height="820" width="1026"></embed> </object>
Some pastebins allow the user to specify additional options when posting. This will be covered when the user helds down the "CTRL" while selecting the menu entry. A dialog is then display where the user can adjust such options. Likewise he could change the content type of the pasted text, if the automatic detection failed.
The Plug-In will be released under EPL 1.0 and the source will be up at github.
Now, if anyone of you have a nicer name for the Plug-In, I would like to replace the rather generic "CopyTo" (Pasty?).
The Plug-In is very easily extensible with new pastebin providers. In fact all current providers are supplied via Fragement-Bundles that basically just add their menuContribution the the CopyTo menu.
There is support for the usual redirect based pastebins, as well as ones that send back JSON. Additional response handlers can be easily plugged in (SOAP *yikes*) and additional JSON helpers, that extract the new location URL component from a JSON response are queried using the Eclipse IAdapterManager.
Currently there is only support for copying JDT elements (Classes, Methods) but other sources of "Copyable" content can be also plugged in via Adapters.
I also plan to provide a "History" view of pastes that allows you to copy the URL again into the clipboard at any time.Unknownnoreply@blogger.com7tag:blogger.com,1999:blog-2528245647272415122.post-74029433710251728942010-02-04T12:43:00.002+01:002010-02-04T13:31:19.069+01:00Use ID on the extension element or as an attribute?I wonder whats the best approach to give an extension a unique ID.
There are two ways to do that:
<ol><li>Use the ID already present on each extension element</li><li>Create an "id" attribute in a child-element of the extension</li></ol>I am currently working on a "CopyTo" extension for the Eclipse Workbench, that allows to quickly copy Java classes or method bodies to your favorite pastebin site and puts the URL of the created entry into the clipboard. For some pastebin providers there is post-processing needed that one should be able to plug-in via extensions.
So I have the "<span style="font-family: courier new;">eclipseutils.ui.copyto</span>" Extension Point that should provide the following:
<ol><li>Allow to specify a response handler</li><li>Allow to describe parameter configurations, that the user can edit prior the request is sent</li></ol>Should I have 2 EPs for that: "<span style="font-family: courier new;">eclipseutils.ui.copyto.responseHandlers</span>" and "<span style="font-family: courier new;">eclipseutils.ui.copyto.paramInfos</span>"? Or one "<span style="font-family: courier new;">eclipseutils.ui.copyto.extensions</span>" with sub-elements "responseHandlers" and "paramInfos"?
Each "CopyTo" is contributed via menuContribution that uses the "<span style="font-family: courier new;">eclipseutils.ui.copyto</span>" command. One of the command parameters is "<span style="font-family: courier new;">id</span>" which is used to look up extensions provided for that menuContribution. I guess the quickest way to fetch an extension for a specific "id" is to ask the <span style="font-family: courier new;">IExtensionRegistry</span> for an <span style="font-family: courier new;">IExtension </span>with a specific ID. That would mean you have to set the ID on the extension itself. Otherwise I would have to query all <span style="font-family: courier new;">IConfigurationElement</span>s and parse it for the "id" attribute.
How you design your extensions also depends if others should be able to contribute to them later. The product splashscreen is a good example of late bindings. You describe the splashscreen somewhere and later reference it in a binding with a specific product.
Any thoughts?Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2528245647272415122.post-51786787819234177082010-02-04T09:19:00.004+01:002010-02-04T11:50:54.565+01:00Enterprise OSGi does not make JPA more dynamicI just browsed the draft version of the new OSGi specs for the enterprise. I was especially interested in how they want to address the JPA related problems. They have not chosen a fundamentally different path than I've been doing JPA development in OSGi for 2 years now. Difference is, they propose a new interface (PersistenceUnitProvider) to be registered for each persistence unit while I was just registering an EntiyManagerFactory with the "pu-name" service property. So every interested service could directly bind to a specific EntityManagerFactory and create its EntityManager from it. So far so good.
I was surprised however, that the OSGi specs do not address the main issue with JPA. It's static. You can not add/remove entities dynamically. It was never designed that way and the OSGi enterprise will not solve that issue. You still have to specify all entities up front in the dreaded persistence.xml. Yet, the more OSGi way would be to skip that file altogether, have the name of the persistence unit name as service property (unit.name) of the PersistenceUnitProvider and let the PUP consume entity beans (exported as java.lang.Object services) with their "unit.name" specifying their target unit. The PersistenceUnitProvider would then have to parse the beans annotations and incorporate it into its EntityManagers.
I am aware of the big problems that can bring with it. What if there are currently transactions running? Does removing an entity from the system also mean to clean up the database? The JPA implementation would have to rebuild its internal state and caches on entity changes. I had hopes the OSGi enterprise spec would address those issues of non-dynamically of current JPA implementations.
So even with this new spec, not much is going to change how I program JPA. It will still not be possible to add new business logic to a running OSGi system without touching the persistence.xml.Unknownnoreply@blogger.com7tag:blogger.com,1999:blog-2528245647272415122.post-21084630350128048142010-01-23T11:08:00.009+01:002010-01-23T19:24:55.456+01:00Adding actions to Eclipse console commandsThis article assumes you know what Declarative Services (DS) are and have a basic understanding of OSGi.
<h2>Introduction</h2>There is one big problem with the Eclipse console commands. You can have only one command with a specific name. That's of course the case in all consoles known to me. However in most consoles the commands express by their name what they actually do. Now in Eclipse we have good commands like "<span style="font-family: courier new;">ss</span>" for a quick overview of the currently known bundles in the system. Then there are the framework commands like "<span style="font-family: courier new;">launch</span>", "<span style="font-family: courier new;">shutdown</span>" and "<span style="font-family: courier new;">exit</span>" which fairly behave like you would expect them by their name. But do you know what the "<span style="font-family: courier new;">list</span>", "<span style="font-family: courier new;">ls</span>" or "<span style="font-family: courier new;">enable</span>", "<span style="font-family: courier new;">en</span>" commands do? Well, they come from the "Service Component Runtime" (SCR) bundle.
<pre>list/ls [-c] [bundle id] - Lists all components; add -c to display the complete info for each component;
enable/en <component> - Enables the specified component;
</component></pre>So when you load the SCR bundle the command "<span style="font-family: courier new;">list</span>" will be taken. And it will list components. A better name would have been "<span style="font-family: courier new;">listcomponents</span>". An even better approach would have been, if the Eclipse command framework was initially planned to have commands that can be extended by actions. Because then we would have a "<span style="font-family: courier new;">list</span>" command that could be extended by actions. We would have "<span style="font-family: courier new;">list components</span>", "<span style="font-family: courier new;">list bundles</span>" and "<span style="font-family: courier new;">list services</span>". There would be much less namespace clutter and a tighter set of commands. But since we cannot create a new "<span style="font-family: courier new;">list</span>" command, as SCR occupies it already, we have to go a slightly different way.
<h2>What are command actions?</h2>Command actions are a way to group commands and redirect the concrete execution to an action. So for the SCR I would like to suggest the following command:
component
This command would have several actions:
<span style="font-family: courier new;">list,enable,disable,info</span>
and for the sake of completeness the short versions of the original SCR commands as actions:
<span style="font-family: courier new;">ls,en,dis,i</span>
A command action is an OSGi services, that can dynamically extend an existing command. Its service interface is really simple:
<pre>
public interface CommandAction {
void execute(CommandActionContext context) throws Exception;
}
</pre>
The action gets in a context that allows it to query execution parameters that the user typed in the command line. It also allows the action to print text on the console.
<pre>
public interface CommandActionContext {
String getArgument(int index);
boolean hasOption(String name);
boolean isVerbose();
void print(String text);
void println(String text);
}
</pre>
A sample action would look like this:
<pre>
public class FileCopyAction implements CommandAction {
void execute(CommandActionContext context) throws Exception {
String from = context.getArgument(0);
String to = context.getArgument(1);
if (from == null || to == null) {
throw new IllegalArgumentException("You must specify from and to arguments");
}
// Copy code here...
}
}
</pre>
Its OSGi DS definition would look like this:
<pre>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.example.commands.file.CopyAction">
<implementation class="org.example.commands.file.CopyAction"/>
<service>
<provide interface="org.eclipse.osgi.framework.console.action.CommandAction"/>
</service>
<property name="command" type="String" value="file"/>
<property name="action" type="String" value="copy"/>
</scr:component>
</pre>
Now we need a way to bring a command and its actions together. This is implemented in an abstract class that implements the standard Equinox <span style="font-family: courier new;">CommandProvider</span>. It also parses the command line and prints help. It takes the first argument from the command line and searches an action that matches the argument. It then calls the found actions execute method with the rest of the command line neatly seperated into arguments and options (that start with "-" or "--"). It also catches any exception that the action may throw during its execution.
If the action throws an <span style="font-family: courier new;">IllegalArgumentException</span>, our command implementation will print help for the command.
If we want to introduce a new command "file" all we have to do is to create a small subclass from the abstract base class "<a href="http://github.com/pke/eclipse_helpers/raw/master/org.eclipse.osgi.framework.console.action/src/org/eclipse/osgi/framework/console/action/ActionCommand.java"><span style="font-family: courier new;">ActionCommand</span></a>".
<pre>
public class FileCommand extends ActionCommand {
public void _file(CommandInterpreter ci) {
execute("file", ci);
}
}
</pre>
Per definition, to create a command in Eclipse Equinox we have to have a public method beginning with an underscore. So there is a small duplication of names here, since our <a href="http://github.com/pke/eclipse_helpers/raw/master/org.eclipse.osgi.framework.console.action/src/org/eclipse/osgi/framework/console/action/ActionCommand.java">ActionCommand </a>baseclass does not know the name of the method its called from, we have to hand it in as first parameter to the execute method.
Somewhere we would also have to define the file command itself. Its published as a CommandProvider.
<pre>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.example.commands.file">
<implementation class="org.example.commands.file.FileCommand"/>
<service>
<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference cardinality="1..n" interface="org.eclipse.osgi.framework.console.action.CommandAction" name="CommandAction" policy="static" target="(command=file)"/>
</scr:component>
</pre>
Please note, that this command component will only be instantiated if there is at least one CommandAction service registered that has its "command" property set to "file" and is therefor providing an action for our command.
See the example file copy action in "action" (It does not really copy a file):
<object width="344" height="240"> <param name="movie" value="http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/jingh264player.swf"></param> <param name="quality" value="high"></param> <param name="bgcolor" value="#FFFFFF"></param> <param name="flashVars" value="thumb=http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/FirstFrame.jpg&containerwidth=344&containerheight=240&content=http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/2010-01-23_1914_blog_command_actions_example.mp4"></param> <param name="allowFullScreen" value="true"></param> <param name="scale" value="showall"></param> <param name="allowScriptAccess" value="always"></param> <param name="base" value="http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/"></param> <embed src="http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="344" height="240" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/FirstFrame.jpg&containerwidth=344&containerheight=240&content=http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/2010-01-23_1914_blog_command_actions_example.mp4" allowFullScreen="true" base="http://content.screencast.com/users/philk/folders/Blog/media/9aad1287-08ee-46a4-afa4-2e969ecdc5ad/" scale="showall"></embed> </object><br/>
That's all. Happy extending your own commands. And maybe this will find its way back into the Equinox code and we can finally have one global "list" command with lots of actions.
<p>
The code is available at <a href="http://github.com/pke/eclipse_helpers">git</a>.
</p>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2528245647272415122.post-44926931401789550632010-01-12T16:52:00.007+01:002010-01-12T17:49:14.317+01:00Notification ListenersTo let other components in the system know about displayed notifications we use the White-Board-Pattern to consume listener services in our <span style="font-family:courier new;">NotificationServiceImpl</span> class.
A listener for notifications has a very easy interface:
<pre>
public interface NotificationListener extends EventListener {
void onEvent(NotificationEvent event);
}
</pre>
It extends the default Java (empty) <span style="font-family:courier new;">EventListener</span> base interface and contains a single method. This single method and its associated event object allows us to extend the kind of events we can publish without changing the interface for each new event like "Show" or "Hide".
For now we will only publish "Show" events. But if in the future we decide to also notify listeners about the close/hide of a notification popup we would have to add another method to the interface "<span style="font-family:courier new;">onHide</span>" and breaking the API somehow.
Using an event object we can put the type of the event inside the event object and the client would then have to decide what to do for each event type. It would still only implement a single method "<span style="font-family:courier new;">onEvent</span>" instead of having to implement a new method for each new event type such as "<span style="font-family:courier new;">onShow</span>" or "<span style="font-family:courier new;">onHide</span>".
The event object itself looks like this:
<pre>public class NotificationEvent extends EventObject {
private static final long serialVersionUID = -8633958140848611658L;
private Notification notification;
private NotificationEventType type;
public NotificationEvent(NotificationService source, Notification notification, NotificationEventType type) {
super(source);
this.notification = notification;
this.type = type;
}
public Notification getNotification() {
return notification;
}
public NotificationEventType getType() {
return type;
}
}
</pre>
The event type is an <span style="font-family:courier new;">enum</span>:
<pre>public enum NotificationEventType {
Show
}
</pre>
The NotificationServiceImpl is only slightly changed:
<pre>
Object listeners[] = context.locateServices("NotificationListener"); //$NON-NLS-1$
if (listeners != null) {
NotificationEvent event = new NotificationEvent(this, notification, NotificationEventType.Show);
for (Object listener : listeners) {
try {
((NotificationListener)listener).onEvent(event);
} catch (Throwable e) {
}
}
}
</pre>
Right before we display the notification we get all the NotificationListener registered in the OSGi system and (safely) call their onEvent method. There are several ways to get the list of currently registered NotificationListener services. One way is to use the BundleContext.getServiceReferences(String, String) method. But this would involve getting the service object ourself and not forget to "unget" it also. Another way is to use a ServiceTracker. But since our implementation already is a Component with bindings we can just add a new binding to our service component definition XML:
<pre><reference cardinality="0..n" interface="ui.notification.NotificationListener" name="NotificationListener" policy="dynamic"/>
</pre>
We then use the ComponentContext object to get an array of services that could be bound to "NotificationListener" (as named in the component XML).
This context we get from OSGi in a new protected method:
<pre>protected void activate(ComponentContext context) {
this.context = context;
}
</pre>That's all for notifying listeners about notification display.
We can now create a simple new bundle that will register a NotificationListener into the system and simply <span style="font-family: courier new;">System.out.println</span> the notifications data.
<pre>
public class SysoutNotificationListener implements NotificationListener {
public void onEvent(NotificationEvent event) {
if (event.getType() == NotificationEventType.Show) {
System.out.println(event.getNotification().getTitle() + ": " //$NON-NLS-1$
+ event.getNotification().getMessage());
}
}
}
</pre>
Its component definition would look like this:
<pre>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ui.notification.listener.sysout">
<implementation class="ui.notification.listener.sysout.internal.SysoutNotificationListener"/>
<service>
<provide interface="ui.notification.NotificationListener"/>
</service>
</scr:component>
</pre>
Pretty simple. Here is what the result looks like:
<object width="430" height="282"> <param name="movie" value="http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/jingh264player.swf"></param> <param name="quality" value="high"></param> <param name="bgcolor" value="#FFFFFF"></param> <param name="flashVars" value="thumb=http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/FirstFrame.jpg&containerwidth=430&containerheight=282&content=http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/2010-01-12_1744_notifcations_listener.mp4"></param> <param name="allowFullScreen" value="true"></param> <param name="scale" value="showall"></param> <param name="allowScriptAccess" value="always"></param> <param name="base" value="http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/"></param> <embed src="http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="430" height="282" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/FirstFrame.jpg&containerwidth=430&containerheight=282&content=http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/2010-01-12_1744_notifcations_listener.mp4" allowFullScreen="true" base="http://content.screencast.com/users/philk/folders/Blog/media/a077fdca-aef7-4132-8d76-a1ac77b01c9d/" scale="showall"></embed> </object>
Listeners could also be used to log a history of notifications in various ways. In the next chapter of this series we will develop a View for Eclipse RCP apps that logs a history of notifications in a table.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2528245647272415122.post-88699748595442536742009-12-18T22:09:00.008+01:002009-12-21T17:18:39.079+01:00Monitoring OutputDebugString on Windows systems from an OSGi component using JNARecently I needed to create a small DLL to call some functions on a Windows Mobile device attached to the desktop Windows PC. Inside my DLL I made heavy use of the <span style="font-family:courier new;">kernel32.dll</span> <a href="http://msdn.microsoft.com/en-us/library/aa363362%28VS.85%29.aspx">OutputDebugString</a> Win32 API to send text to an attached debugger or <a href="http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx">Debug View</a>.
Since I was programming in Java, I would have liked to have all the log messages appear in the Java console and end up in the log file created by slf4j.
<h2>How does OutputDebugString work?</h2>
Basically it writes its data to a shared memory section of kernel32.dll. Everybody can try to read this memory out at any time. You just need to know how the name of this memory block is and can get a direct memory pointer to it. I will not go into the details of that now, you can lookup the required methods in the MSDN yourself.
So at first we need to open the existing filemapping with the name "<span style="font-family:courier new;">DBWIN_BUFFER</span>" using <span style="font-family:courier new;">CreateFileMapping</span>. Windows allocates 4096 bytes for the shared buffer. We then just map this shared buffer to a real memory location using <span style="font-family:courier new;">MapViewOfFile</span>. Using JNA thats pretty easy to do:
<pre>
HANDLE sharedFile = Kernel32.INSTANCE.CreateFileMapping(W32API.INVALID_HANDLE_VALUE, null, Kernel32.PAGE_READWRITE, 0, 4096, DBWIN_BUFFER_SHARED_FILE);
HANDLE sharedMemory = Kernel32.INSTANCE.MapViewOfFile(this.sharedFile, Kernel32.SECTION_MAP_READ, 0, 0, 4096);
</pre>
I added those prototypes to the already existing JNA Kernel32 package:
<pre>
int PAGE_READONLY = 0x02;
int PAGE_READWRITE = 0x04;
int PAGE_WRITECOPY = 0x08;
int PAGE_EXECUTE = 0x10;
int PAGE_EXECUTE_READ = 0x20;
int PAGE_EXECUTE_READWRITE = 0x40;
HANDLE CreateFileMapping(HANDLE hFile, SECURITY_ATTRIBUTES lpAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, String lpName);
int SECTION_QUERY = 0x0001;
int SECTION_MAP_WRITE = 0x0002;
int SECTION_MAP_READ = 0x0004;
int SECTION_MAP_EXECUTE = 0x0008;
int SECTION_EXTEND_SIZE = 0x0010;
Pointer MapViewOfFile(HANDLE hFileMappingObject, int dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, int dwNumberOfBytesToMap);
boolean UnmapViewOfFile(Pointer lpBaseAddress);
</pre>
Now we basically have everything ready to start reading from that buffer. The first 4 bytes (32-bit DWORD) is the process ID of the process that wrote the text using OutputDebugString. The following bytes are the actual debug message as an ANSI string.
Now, to tell kernel32 that we are interested in reading out this memory, we should inform it. Otherwise kernel32 would not write anything to this memory, if nobody is about to read it. For that purpose there is a named Win32 event that we need to signal. Its name is "DBWIN_BUFFER_READY". We create it using those new Kernel32 JNA mappings:
<pre>
HANDLE CreateEvent(SECURITY_ATTRIBUTES lpEventAttributes, boolean bManualReset, boolean bInitialState, String lpName);
boolean SetEvent(HANDLE hEvent);
boolean PulseEvent(HANDLE hEvent);
</pre>
Now lets create the mentioned event:
<pre>
bufferReadyEvent = Kernel32.INSTANCE.CreateEvent(null, false, false, DBWIN_BUFFER_READY_EVENT);
</pre>
When we signal this event, kernel32 will start to write data into the shared memory if some process calls <span style="font-family:courier new;">OutputDebugString</span>. In an infinite loop would could now read the memory out but that would read always the last written text that might not have changed since the last time we checked.
Windows helps us to get informed when new text has been written to the shared memory. It signals this with the named event "<span style="font-family:courier new;">DBWIN_DATA_READY</span>". Now we can be a very good citizen and use the Win32 <span style="font-family:courier new;">WaitForSingleObject</span> to wait for this event to be signaled.
<pre>
while (run) {
// Say that we are interested in receiving data ready events
Kernel32.INSTANCE.SetEvent(this.bufferReadyEvent);
final int ret = Kernel32.INSTANCE.WaitForSingleObject(this.dataReadyEvent, Kernel32.INFINITE);
if (!run) {
break;
}
if (ret == 0) { // WAIT_OBJECT_0
final int pid = this.sharedMemory.getInt(0);
final String text = this.sharedMemory.getString(4, false);
}
}
</pre>
<h2>Creating a monitor thread</h2>
We can implement this whole functionality as a Thread and hand it in an OSGi <span style="font-family:courier new;">LogService</span> to log the catched debug message with the OSGi environment.
<pre>
package outputdebugstring.monitor.internal;
import org.osgi.service.log.LogService;
import com.sun.jna.Pointer;
import com.sun.jna.examples.win32.Kernel32;
import com.sun.jna.examples.win32.W32API;
import com.sun.jna.examples.win32.W32API.HANDLE;
class OutputDebugStringThread extends Thread {
private static final String DBWIN_BUFFER_SHARED_FILE = "DBWIN_BUFFER"; //$NON-NLS-1$
private static final String DBWIN_DATA_READY_EVENT = "DBWIN_DATA_READY"; //$NON-NLS-1$
private static final String DBWIN_BUFFER_READY_EVENT = "DBWIN_BUFFER_READY"; //$NON-NLS-1$
private final HANDLE bufferReadyEvent;
private final HANDLE dataReadyEvent;
private final HANDLE sharedFile;
private final Pointer sharedMemory;
private final LogService log;
private volatile boolean run = true;
public OutputDebugStringThread(final LogService log) {
super("OutputDebugString monitor"); //$NON-NLS-1$
setDaemon(true);
this.log = log;
this.bufferReadyEvent = Kernel32.INSTANCE.CreateEvent(null, false, false, DBWIN_BUFFER_READY_EVENT);
this.dataReadyEvent = Kernel32.INSTANCE.CreateEvent(null, false, false, DBWIN_DATA_READY_EVENT);
this.sharedFile = Kernel32.INSTANCE.CreateFileMapping(W32API.INVALID_HANDLE_VALUE, null,
Kernel32.PAGE_READWRITE, 0, 4096, DBWIN_BUFFER_SHARED_FILE);
this.sharedMemory = Kernel32.INSTANCE.MapViewOfFile(this.sharedFile, Kernel32.SECTION_MAP_READ, 0, 0, 4096);
}
@Override
public void run() {
try {
while (this.run) {
// Say that we are interested in receiving data ready events
Kernel32.INSTANCE.SetEvent(this.bufferReadyEvent);
final int ret = Kernel32.INSTANCE.WaitForSingleObject(this.dataReadyEvent, Kernel32.INFINITE);
if (!this.run) {
break;
}
if (ret == 0) { // WAIT_OBJECT_0
final int pid = this.sharedMemory.getInt(0);
final String text = this.sharedMemory.getString(4, false);
this.log.log(LogService.LOG_DEBUG, String.format("[%d] %s", pid, text)); //$NON-NLS-1$
}
}
} finally {
if (this.sharedMemory != null) {
Kernel32.INSTANCE.UnmapViewOfFile(this.sharedMemory);
}
if (!W32API.INVALID_HANDLE_VALUE.equals(this.sharedFile)) {
Kernel32.INSTANCE.CloseHandle(this.sharedFile);
}
if (!W32API.INVALID_HANDLE_VALUE.equals(this.bufferReadyEvent)) {
Kernel32.INSTANCE.CloseHandle(this.bufferReadyEvent);
}
if (!W32API.INVALID_HANDLE_VALUE.equals(this.dataReadyEvent)) {
Kernel32.INSTANCE.CloseHandle(this.dataReadyEvent);
}
}
}
/**
* Our very own implementation that simply notifies the thread to stop by sending an event it is waiting for.
*/
@Override
public void interrupt() {
this.run = false;
Kernel32.INSTANCE.PulseEvent(this.dataReadyEvent);
}
}
</pre>
As you can see I have overwritten the <span style="font-family:courier new;">interrupt()</span> method of Thread to implement a custom interruption using the volatile variable "<span style="font-family:courier new;">run</span>". We then pulse the <span style="font-family:courier new;">dataReadyEvent</span> to make the <span style="font-family:courier new;">WaitForSingleObject</span> wake up and immediately check the run variable to stop running.
<h2>Creating an OSGi component</h2>
Now that we have the (almost OGSi independent) thread to catch Windows debug messages we can wrap it in a simple OSGi component that will also give the thread the LogService it needs. A better solution would be however to have the Thread just call a simple Listener method to report the debug message event. That way it would have no dependency on OSGi.
<p>
The service component would be as simple as this:
</p><pre>
public class MonitorComponent {
private OutputDebugStringThread thread;
protected void deactivate() {
if (this.thread != null) {
this.thread.interrupt();
}
}
protected void bind(final LogService log) {
this.thread = new OutputDebugStringThread(log);
this.thread.start();
}
}
</pre>
And the corresponding DS component XML file
<pre>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="outputdebugstring.MonitorComponent">
<implementation class="outputdebugstring.monitor.internal.MonitorComponent"/>
<reference bind="bind" cardinality="1..1" interface="org.osgi.service.log.LogService" name="LogService" policy="static"/>
</scr:component>
</pre>
As you can see we dynamically bind to the OSGi LogService and our component will be only activated when there is at least one LogService available. This saves our component from instantiating itself if there is nothing to log to.
<h2>Extensions</h2>
The component could also facilitate the OSGi EventAdmin and send an event:
<span style="font-family:courier new;">event.topic = win32/OutputDebugString</span>
<span style="font-family:courier new;">ods.pid = the process ID</span>
<span style="font-family:courier new;">ods.text = the text</span>
<p>
Note: It seems that inside the mapped file all texts are stored in the ANSI character set and not in Unicode (UTF-16) even when a process called <span style="font-family:courier new;">OutputDebugStringW</span>.
</p>
<p>
Sourcecode is up at <a href="http://github.com/pke/OutputDebugString-Monitor">github</a> now.
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2528245647272415122.post-40222561341605936312009-12-17T15:09:00.005+01:002009-12-17T16:48:16.621+01:00Displaying OSGi bundle informations in the Windows ExplorerI am currently working on a small Windows Shell Extension that will help to get a quick overview on all the OSGi bundles in the currently browsed folder.
<p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNz51vk6H2WIcJZCsl3JyEOFimFeCkcwSh2A7n_wlDm9IbfeAyKRcIAn3r-OLNyJ_922n4S7cVWOtA4fDESW1iJn_Mpmvor4-eGn7uQm2hCrWpQAYitwsdra4ofDHNJSV5rZmSMqZrmQim/s1600-h/2009-12-17_1643_osgi_shell_extensions_icons.png"><img style="cursor:pointer; cursor:hand;width: 320px; height: 174px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNz51vk6H2WIcJZCsl3JyEOFimFeCkcwSh2A7n_wlDm9IbfeAyKRcIAn3r-OLNyJ_922n4S7cVWOtA4fDESW1iJn_Mpmvor4-eGn7uQm2hCrWpQAYitwsdra4ofDHNJSV5rZmSMqZrmQim/s320/2009-12-17_1643_osgi_shell_extensions_icons.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5416232279429976050" /></a><br/>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilIpBI9lFPw8ZZZ08kaVVuqxMzXChdXQH09nWv5QsFB-5MbVuqbsWIO-THboZXc3YVqi_KD5I-NuxOekVZTGNtOsdZvd5PZLNgpvB5It7YH9ZODCJEKpQ1u5RBFp86tIT1YH5LkMaS8DNC/s1600-h/2009-12-17_1508_osgi_shell_extensions_categories.png"><img style="cursor: pointer; width: 320px; height: 181px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilIpBI9lFPw8ZZZ08kaVVuqxMzXChdXQH09nWv5QsFB-5MbVuqbsWIO-THboZXc3YVqi_KD5I-NuxOekVZTGNtOsdZvd5PZLNgpvB5It7YH9ZODCJEKpQ1u5RBFp86tIT1YH5LkMaS8DNC/s320/2009-12-17_1508_osgi_shell_extensions_categories.png" alt="" id="BLOGGER_PHOTO_ID_5416210838707886418" border="0" /></a></br>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1cMT3dEhu9hknOKGD0pc8XvuwdNDHI35qnt-UZprirT10M1dAfd9thDomwzIyW22o47ydx42iiAhV8CbFJwEsVQqdaGzG9d-7d6d8A97UZJ7NOax7KHmenbM_h7KHpC8pA88AwqBIWUO-/s1600-h/2009-12-17_1508_osgi_shell_extensions.png"><img style="cursor: pointer; width: 320px; height: 230px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1cMT3dEhu9hknOKGD0pc8XvuwdNDHI35qnt-UZprirT10M1dAfd9thDomwzIyW22o47ydx42iiAhV8CbFJwEsVQqdaGzG9d-7d6d8A97UZJ7NOax7KHmenbM_h7KHpC8pA88AwqBIWUO-/s320/2009-12-17_1508_osgi_shell_extensions.png" alt="" id="BLOGGER_PHOTO_ID_5416210832209791346" border="0" /></a>
</p>
<p>
The following features will be supported:
<ul><li>Detail columns for all bundle headers</li><li>Additional Property sheet for bundle files and unpacked bundle folders</li><li>Overlay icons to display various informations: if the bundle has Service Components, is a fragment or a normal bundle
</li><li>Tooltips with the most important bundle headers</li></ul>The extension can already read out the default Bunde-l10n. However there is no support for reading out the l10n matching the current Windows locale yet.
In the future I plan to support Windows Search 4 and Vista and allow them to find bundles based on their OSGi manifest.
I will upload the extension soon to github and everybody is invited to provide feedback.
The source package will include documented classes and unit-tests (using googletest) maybe I will create a small tutorial about this later.
</p>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2528245647272415122.post-26624552956362220682009-12-16T09:28:00.012+01:002010-01-12T17:48:51.464+01:00Notification FrameworkIn this series of tutorials I will describe a small, extensible notification framework for JFace/Eclipse applications. I will make heavy use of OSGi services and Eclipse Extensions. So before you continue to read, I suggest you make yourself familiar with those concepts to be able to follow the series.
<ol><li><a href="#intro">Basic Notification Service</a></li><li><a href="http://philondev.blogspot.com/2010/01/notification-listeners.html">Notify listeners about notifications</a></li><li>Showing all notifications in a view</li><li>Notifications via OSGi EventAdmin</li><li>Adding links to notifications</li><li>Let the notify console command quote "The Big Lebowski" from the IMDB with links
</li><li>Declarative colour customization for Notifications</li><li>Add preferences which notifications should be shown
</li><li>Showing notifications after a "copy" command was executed</li></ol>
There is <a href="http://github.com/pke/Notifications">git repository</a> accompanied with this tutorial series.
You can clone it directly from <a href="git://github.com/pke/Notifications.git">git://github.com/pke/Notifications.git</a>
<h2 id="intro">Inspiration</h2>
The inspiration for using notifications in my own programs came from Mylyn that shows neat little notifications upon changes in the watched buglists. I was further inspired by the great blog post over at Hexapixel: <a href="http://hexapixel.com/2009/06/30/creating-a-notification-popup-widget">Creating a Notification Popup Widget</a>. We will use this widget as the base of this tutorial series.
<h2>Creating the service</h2>First we create a simple service interface for our NotificationService. Its intentionally simple and does not contain any query methods to enumerate notifications or such. It simply provides a method to show a single notification. But as you will see in the course of this series that's enough to drive a powerful notification system.
So the interface will look like this:
<pre>public interface NotifyService {
/**
* Shows a notification. Re-arranges already visible notifications.
*
* @param notification
*/
void show(Notification notification);
}
</pre>
For the Notification interface itself we will use JFace's IMessageProvider as a base as it provides already a message text and type for our notification. All that is left is a title. So our Notification interface looks pretty simple too:
<pre>interface Notification extends IMessageProvider {
/**
* @return the title of this notification or <code>null</code> if none.
*/
String getTitle();
}
</pre>
Thats basically all we need for a simple notification. As the base for the implementation of our Notification Service we will use Hexapixel's code for now. That makes the implementation of the NotificationService really simple:
<pre>public void show(final Notification notification) {
if (notification != null) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
NotificationType type;
switch (notification.getMessageType()) {
case IMessageProvider.WARNING:
type = NotificationType.WARN;
break;
case IMessageProvider.ERROR:
type = NotificationType.ERROR;
break;
default:
type = NotificationType.INFO;
break;
}
NotifierDialog.notify(notification.getTitle(), notification.getMessage(), type);
}
});
}
}
</pre>
I only modified the original NotifierDialog class so that it no longer requires an active shell for operating. There is one more little thing we also need to do, to actually see the notification on screen. We need a thread that polls the SWT message loop. This is usually done for us when we run inside the Eclipse workbench, but since we are going to test this notification framework in an OSGi environment (for now) we need a thread that polls the SWT message loop for us. The code is also inside the NotificationService component implementation:
<pre>Runnable runnable = new Runnable() {
public void run() {
while (!Display.getDefault().isDisposed()) {
if (!Display.getDefault().readAndDispatch()) {
Display.getDefault().sleep();
}
}
}
};
new Thread(runnable, "SWT").start();
</pre>
<h2>Equinox Console Command to show notifications</h2>
Basically we have everything in place now to show notifications programmatically. We can have other components use our notification service to display messages. So we will create a console command for the Equinox OSGi console and implement a simple CommandProvider. It will expose the command "notify" to the Equinox console if you start the OSGi configuration with the "-console" command.
The notify command will take at least one parameter, which will be the notifications message. If you specify another parameter, then this will become the notifications title. Otherwise a default title is choosen.
<pre>public class NotifyCommand implements CommandProvider {
NotificationService service;
protected void activate(ComponentContext context) {
service = (NotificationService) context.locateService("NotificationService");
}
public void _notify(CommandInterpreter ci) {
final String message = ci.nextArgument();
if (null == message) {
ci.println("You need to specify a message");
return;
}
String title = ci.nextArgument();
if (title == null) {
title = "Notification";
}
final String finalTitle = title;
service.show(new Notification() {
public String getTitle() {
return finalTitle;
}
public String getMessage() {
return message;
}
public int getMessageType() {
return IMessageProvider.INFORMATION;
}
});
}
public String getHelp() {
return "--- Notification ---\n\tnotify message [title]";
}
}
</pre>
<h2>Create the component definitions</h2>
All that is left to make those 2 services run as Declerative Services is to create the required component XML files in /OSGI-INF/.
For the NotificationService it looks like this:
<pre><?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ui.notification.NotificationService">
<implementation class="ui.notification.internal.NotificationServiceImpl"/>
<service>
<provide interface="ui.notification.NotificationService"/>
</service>
</scr:component>
</pre>
And for the NotifyCommand it looks like this:
<pre><?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ui.notification.NotifyCommand">
<implementation class="ui.notification.command.internal.NotifyCommand"/>
<service>
<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference cardinality="1..1" interface="ui.notification.NotificationService" name="NotificationService" policy="static"/>
</scr:component>
</pre>
<h2>Run configuration</h2>
To run this we create an OSGi run configuration and add the following bundles to it:
<ul>
<li>ui.notification</li>
<li>ui.notification.command</li>
<li>org.eclipse.osgi</li>
<li>org.eclipse.osgi.services</li>
<li>org.eclipse.equinox.ds</li>
<li>org.eclipse.equinox.util</li>
<li>org.eclipse.equinox.common</li>
<li>org.eclipse.core.commands</li>
<li>org.eclipse.swt</li>
<li>org.eclipse.swt.win32.win32.x86</li>
<li>org.eclipse.jface</li>
</ul>
Make sure the <span style="font-family: courier new;">org.eclipse.equinox.ds</span> bundle is started, as well as our two ui.notification* bundles.
If we start the configuration now, we will be able to type:
<span style="font-family: courier new;">notify "Hello World"</span>
and see a notification coming up at the right bottom of our primary screen as seen in this video:
<object width="512" height="242"> <param name="movie" value="http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/jingh264player.swf"></param> <param name="quality" value="high"></param> <param name="bgcolor" value="#FFFFFF"></param> <param name="flashVars" value="thumb=http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/FirstFrame.jpg&containerwidth=512&containerheight=242&content=http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/2009-12-16_1200_notification_first_command.mp4"></param> <param name="allowFullScreen" value="true"></param> <param name="scale" value="showall"></param> <param name="allowScriptAccess" value="always"></param> <param name="base" value="http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/"></param> <embed src="http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="512" height="242" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/FirstFrame.jpg&containerwidth=512&containerheight=242&content=http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/2009-12-16_1200_notification_first_command.mp4" allowFullScreen="true" base="http://content.screencast.com/users/philk/folders/Blog/media/a60d01e9-3e4d-489e-b890-b910f1a64eb9/" scale="showall"></embed> </object>
That's all for now. Stay tuned for the next part where we will notify listener services about notifications using the White-Board pattern. Feedback is always welcome, especially about how to poll the SWT message loop in OSGi apps.
<h2 id="source">Source:</h2>
Check out the source code at <a href="http://github.com/pke/Notifications">github</a> or clone directly from <a href="git://github.com/pke/Notifications.git">git://github.com/pke/Notifications.git</a>Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-2528245647272415122.post-60962944018981952132009-12-15T22:51:00.009+01:002009-12-22T01:30:07.887+01:00Toggle Commands that toggle other contributions<h2>Introduction</h2>
This is a follow up to <a href="http://blog.eclipse-tips.com/2009/03/commands-part-6-toggle-radio-menu.html">Commands Part 6: Toggle & Radio menu contributions</a> of fellow blogger <a href="http://blog.eclipse-tips.com/">Prakash G.R.</a>. He described how to use command toggle and radio states. Here I will show you how to drive other contributions in the Eclipse Workbench using a toggle command.
<h2>What we want to achieve</h2>
I needed to show another toolbar button when a certain toggle command was executed. Imagine something like "Show clock" that will show or hide a little clock in the worbench window status bar.
Such contribution can be easily added using a <span style="font-family:courier new;">menuContribution</span> for the trim area. First create a toolbar in the trim area and then contribute controls/commands to this toolbar also using the <span style="font-family:courier new;">menuContribution</span> extension point.
Since we want the clock contribution
<pre>
<menucontribution locationuri="toolbar:mytoolbar">
<control class="test.ui.clocl.internal.ClockControlContribution" id="test.ui.clock">
<visiblewhen checkenabled="false">
<with variable="activeWorkbenchWindow">
<test args="test.ui.clock.ToggleCommand"
forcepluginactivation="true"
property="org.eclipse.core.commands.toggle"
value="true"/>
</with>
</visiblewhen>
</control>
</menucontribution>
</pre>
That will create a toolbar contribution that is only visible when the <span style="font-family:courier new;">test.ui.clock.ToggleCommand</span> is in the "<span style="font-family:courier new;">true</span>" state, when its checked.
Lets define the command:
<pre>
<command defaulthandler="org.eclipse.core.commands.extender.ToggleCommandHandler" id="test.ui.clock.ToggleCommand" name="Show clock">
<state
class="org.eclipse.ui.handlers.RegistryToggleState:true"
id="org.eclipse.ui.commands.toggleState">
</state>
</command>
</pre>
How this command works and what the state is you have already read in Prakash's blog entry. The default handler for this command does a little more than the one in the latter mentioned blog entry. It is defined like this:
<pre>
/**
* Generic command that toggles the executed command and re-evaluates property testers for the
* <code>org.eclipse.core.commands.toggle</code> property.
*
*/
public class ToggleCommandHandler extends AbstractHandler {
public Object execute(final ExecutionEvent event) throws ExecutionException {
HandlerUtil.toggleCommandState(event.getCommand());
final IWorkbenchWindow ww = HandlerUtil.getActiveWorkbenchWindowChecked(event);
final IEvaluationService service = (IEvaluationService) ww.getService(IEvaluationService.class);
if (service != null) {
service.requestEvaluation("org.eclipse.core.commands.toggle");
}
return null;
}
}
</pre>
<h2>How to toggle the visibility of the clock contribution</h2>
The connection between toggling the command and making the clock contribution visible is hidden in a property tester, that the clock contribution uses:
<pre>
public class CommandsPropertyTester extends PropertyTester {
public static final String NAMESPACE = "org.eclipse.core.commands"; //$NON-NLS-1$
public static final String PROPERTY_BASE = NAMESPACE + '.';
public static final String TOGGLE_PROPERTY_NAME = "toggle"; //$NON-NLS-1$
public static final String TOGGLE_PROPERTY = PROPERTY_BASE + TOGGLE_PROPERTY_NAME;
public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) {
if (receiver instanceof IServiceLocator && args.length == 1 && args[0] instanceof String) {
final IServiceLocator locator = (IServiceLocator) receiver;
if (TOGGLE_PROPERTY_NAME.equals(property)) {
final String commandId = args[0].toString();
final ICommandService commandService = (ICommandService)locator.getService(ICommandService.class);
final Command command = commandService.getCommand(commandId);
final State state = command.getState(RegistryToggleState.STATE_ID);
if (state != null) {
return state.getValue().equals(expectedValue);
}
}
}
return false;
}
}
</pre>
It is defined in plugin.xml like this:
<pre>
<propertytester
class="org.eclipse.core.commands.extender.internal.CommandsPropertyTester"
id="org.eclipse.core.expressions.testers.CommandsPropertyTester"
namespace="org.eclipse.core.commands"
properties="toggle"
type="org.eclipse.ui.services.IServiceLocator"/>
</pre>
That means we define a new property for the namespace "<span style="font-family:courier new;">org.eclipse.core.command</span>" and the property is named "toggle". It will operate on<span style="font-family:courier new;"> IServiceLocator</span> variables. Such variable that is an <span style="font-family:courier new;">IServiceLocator</span> is the "<span style="font-family:courier new;">activeWorkbenchWindow</span>" variable. Now you should understand the <span style="font-family:courier new;">visibleWhen</span> expression of the clock contribution. It should be only visible when the toggle for the clock toggle command is "true". The re-evaluation of the property testers is triggered by the generic <span style="font-family:courier new;">ToggleCommand</span>.
<h2>A little tip at the end</h2>
If you put the <span style="font-family:courier new;">ToggleCommand</span> and property tester in a seperate bundle for easier re-use in all your projects and other bundles make sure you either start the bundle at the beginning or set the "test" expressions "<span style="font-family:courier new;">forcePluginActivation</span>" to true to let the Eclipse expression framework activate the bundle for you. Otherwise the property tester is completly ignored and the clock would be always visible.
<h2>Bonus</h2>
Since the state of the toggle is preserved in an instance preference value, the visibility of all associated contributions that use the property tester to check for the toggle state of the command is as well.
Of course you can also reverse the test expression for your contributions if you have a toggle command that says something like "Hide clock".Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2528245647272415122.post-70359806735473465642009-12-13T10:31:00.002+01:002009-12-13T11:56:57.186+01:00Using JNA to query power status on Windows CE device - with a crash<h2>Introduction</h2>
I am using the wonderful JNA library to use the Microsoft Remote API (RAPI) to access Windows Mobile Devices on Windows desktops. It allows you to connect to an attached mobile device using ActiveSync. This works all wonderfully easy thanks to the JNA library. I do not need to write any JNI code anymore.
The RAPI offers a method to query the power status of the device which is somewhat limited. It does not return more detailed information about the battery type or voltage. There is a function available in the WinCE devices own libraries (coredll.dll) that allows me to query such informations (<a href="http://msdn.microsoft.com/en-us/library/aa931066.aspx">GetSystemPowerStatusEx2</a>).
<h2>How to call methods directly on the device</h2>To call a method on the device that is not exposed by RAPI itself, you can use the <a href="http://msdn.microsoft.com/en-us/library/aa917422.aspx">CeRapiInvoke</a> function. So I implemented the following function according to the RAPI specs:
<pre>
EXTERN_C int __declspec(dllexport) GetPowerInfos(DWORD cbInput, BYTE* pInput, DWORD* pcbOutput, BYTE** ppOutput, LPVOID pStream) {
*pcbOutput = sizeof(SYSTEM_POWER_STATUS_EX2);
*ppOutput = (SYSTEM_POWER_STATUS_EX2*)LocalAlloc(LPTR, *pcbOutput);
return GetSystemPowerStatusEx2(*ppOutput, *pcbOutput, FALSE);
}
</pre>
The spec requires to LocalAlloc the memory you return. The caller of CeRapiInvoke must then LocalFree the output memory. Now, you may wonder how that can work?
<h2>Memory management in CeRapiInvoke</h2>
The way I understand how it works is like this:
For the <span style="font-family: courier new;">pInput </span>parameter you have to call LocalAlloc on the Windows machine and CeRapiInvoke will copy the content of this memory block into a newly created WindowsCE readable block of memory and hand it over to <span style="font-family: courier new;">GetPowerInfos</span> function as pInput. It is of course not the same memory pointer that I handed in on the Win32 side, it just contains the same data as I handed in. <span style="font-family: courier new;">CeRapiInvoke</span> also calls <span style="font-family: courier new;">LocalFree</span> on the <span style="font-family: courier new;">pInput</span> that I handed in.
The same way around with the <span style="font-family: courier new;">ppOutput</span> parameter. I have to allocate it using <span style="font-family: courier new;">LocalAlloc</span> on the WindowsCE device. <span style="font-family: courier new;">CeRapiInvoke</span> will then copy the content of my returned buffer into a desktop process accessible block of memory that it allocates with <span style="font-family: courier new;">LocalAlloc</span> on the Windows machine. I, the caller of <span style="font-family: courier new;">CeRapiInvoke</span> am then responsible for calling <span style="font-family: courier new;">LocalFree</span> on the <span style="font-family: courier new;">ppOutput</span> that <span style="font-family: courier new;">CeRapiInvoke</span> created for me.
Thats the theory. Lets see how to get the returned ppOutput into the Java world using JNA.
<h2>Calling CeRapiInvoke from Java using JNA</h2>
We define this prototype in our JNA library interface for RAPI.
<pre>
public interface Rapi extends W32API {
static Rapi instance = (Rapi) Native.loadLibrary("rapi", Rapi.class, DEFAULT_OPTIONS); //$NON-NLS-1$
HRESULT CeRapiInvoke(String dllPath, String functionName, int cbInput, Pointer pInput, IntByReference outBuffer, PointerByReference outBufferSize, PointerByReference ppIRAPIStream, int dwReserved);
}
</pre>
We also declare the SYSTEM_POWER_STATUS_EX2 structure:
<pre>
static class SystemPowerStatusEx extends Structure {
public SystemPowerStatusEx() {
}
protected SystemPowerStatusEx(final Pointer p) {
super(p);
}
public byte ACLineStatus;
public byte BatteryFlag;
public byte BatteryLifePercent;
public byte Reserved1;
public int BatteryLifeTime;
public int BatteryFullLifeTime;
public byte Reserved2;
public byte BackupBatteryFlag;
public byte BackupBatteryLifePercent;
public byte Reserved3;
public int BackupBatteryLifeTime;
public int BackupBatteryFullLifeTime;
}
class SystemPowerStateEx2 extends Structure {
public SystemPowerStateEx2(final Pointer p) {
super(p);
read();
}
public SystemPowerStatusEx base;
public int BatteryVoltage;
public int BatteryCurrent;
public int BatteryAverageCurrent;
public int BatteryAverageInterval;
public int BatterymAHourConsumed;
public int BatteryTemperature;
public int BackupBatteryVoltage;
public byte BatteryChemistry;
}
</pre>
Now we can call our DLLs exported function:
<pre>
final PointerByReference outBuffer = new PointerByReference();
try {
final IntByReference outBufferSize = new IntByReference();
Rapi.instance.CeRapiInvoke("powerex.dll", "GetPowerInfos", 0, null, outBufferSize, outBuffer, null, 0);
return new SystemPowerStateEx2(outBuffer.getValue());
} finally {
Kernel32.INSTANCE.LocalFree(outBuffer.getValue());
}
</pre>
This code has been simplified and usually contains return value checking and error handling. However it returns the power infos we would suspect. I also ommited the initialization of RAPI here.
<h2>The LocalFree crash problem</h2>
Calling this in a loop will eventually lead to an Access Violation and a crash of the VM. If I comment out the LocalFree call in the finally block, the program runs for hours. But it then leaks memory of course. I have played with different output parameters, pointer handling and more. Without finding a solution to the crashes.
Enabling JNAs own VM crash protected reveals, that it sometimes causes an Access Violation inside the native code. It almost seems like the native code overwrites some memory internally. Most likely inside RAPI itself.
However calling the same remote function from a C++ Win32 program in a loop does not cause any memory corruption or crash.
I hope someone of the community has maybe an idea whats going on here? If not, you got at least a short introduction on how to use JNA and the Microsoft RAPI ;)Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2528245647272415122.post-56996810283360988862009-12-07T16:30:00.000+01:002009-12-07T18:06:33.779+01:00Allow contributions to Forms<h2>Introduction</h2>
Each Form has a toolbar associated with it, as you probably already know.
You can get it by calling <span style="font-family:courier new;">form.getToolBarManager()</span>.
Once you got the manager you can add your own contribution items or (legacy) actions to it. But what if you could allow other bundles/developers to add contributions to your forms toolbar too? There exists already an extension point that allows adding of contributions to menus and toolbars. You most likely used it already to customize your popup menus or your RCP applications main menu.
<h2>How to implement</h2>
The<span style="font-family:courier new;"> menuConstribution</span> extension point works in conjunction with the <span style="font-family:courier new;">IMenuService</span>. This service allows you to put matching contributions into any <span style="font-family:courier new;">ContributionManager</span>. It respects the current workbench evaluation state so contributions with expressions are carefully evaluated before they are added to the <span style="font-family:courier new;">ContributionManager</span>. The menu service also takes care of enabling the contributions and manages their visibility dynamically. Basically all that you already know from addin contributions to the various Eclipse menus and toolbars.
To get the contributions you are interested in, you first have to decide on a menu URI schema that identifies contributions for your form. We should follow the Eclipse Schema and define "<span style="font-family:courier new;">form:</span>" as our new schema and the following parameter is the ID of the form. The ID can be anything and you as a programmer decide for each form that you create what its ID should be. A common way I use is, if the form is embedded into a <span style="font-family:courier new;">ViewPart</span>, to use the <span style="font-family:courier new;">ViewPart.getSite().getId()</span> method. So I would call
<pre class="brush:java">
menuService.populateContributionManager(toolbarManager, "form:"+getSite().getId());
</pre>
<h2>Cleanup</h2>
You have to remember to release the contributions when your form is disposed or otherwise the IMenuService will continue to track your contributions and waste time as well as resources. So be a good contribution citizen and call
<span style="font-family:courier new;">menuService.releaseContributions(toolbarManager)</span>
and also <span style="font-family:courier new;">toolbarManager.dispose()</span>to allow it to clean up its resources.
I recommend using a <span style="font-family:courier new;">DisposeListener</span> on the form to perform the cleanup.
<h2>Extension: Allow contributions to any form</h2>
Much like you can add contributions to the global popup menu using the "<span style="font-family:courier new;">popup:org.eclipse.ui.popup.any</span>" we can define our new "<span style="font-family:courier new;">form:org.eclipse.ui.form.any</span>" URI that allows contributions to be added to each forms toolbar.
<pre class="brush:java">
ContributionHelper.contributeTo(toolbarManager, "form:" + getSite().getId(), "form:org.eclipse.ui.form.any");
</pre>
<pre class="brush:xml">
<extension point="org.eclipse.ui.menus">
<menucontribution locationuri="form:org.examples.ui.PickersView">
<command commandid="org.eclipse.ui.newWizard" icon="icons/e16/picker_add.png" style="">
<parameter name="newWizardId" value="org.example.ui.NewPickerWizard">
</parameter>
</command>
</menucontribution>
</extension>
</pre>
<pre class="brush:java">
/**
* Adds menu contributions to a {@link ContributionManager} using the
* {@link IMenuService}.
*
* @param contributionManager
* @param locations
* The format is the Menu API URI format.
*/
public static void contributeTo(final ContributionManager contributionManager, final String... locations) {
final IMenuService menuService = (IMenuService)PlatformUI.getWorkbench().getService(IMenuService.class);
for (final String location : locations) {
menuService.populateContributionManager(contributionManager, location);
}
contributionManager.update(false);
}
</pre>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2528245647272415122.post-89892019349392745242009-07-23T14:41:00.012+02:002009-07-23T16:29:13.410+02:00How to replace the default JFace message iconsWe all know the standard JFace icons very well. They appear in Dialogs, Wizards and Forms.<br/>
<img style="width: 16px; height: 16px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIWrluhh_KCRBaLdAL4EYpp6CZ3XNZiSLv53X3sVmobqCoUDCPjKJB72c9uOO_P_QBUWkPQcrB7huCY4GaL54OO2cgVkVkOoeQtInzYw2wvXmptX4A8vs8n9K8Hb8lL641_yeYCWgAMK3f/s200/message_warning.gif" alt="" id="BLOGGER_PHOTO_ID_5361635900609027986" border="0" /><img style="width: 16px; height: 16px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjbeCsoP6UnSFH7elSGPl2eDXkFsybpUewrD1ZaUaFdPfYda7CIumY9IP0WDArcW9j6-1lJ1B60HsdNoTnyyO658HEgMp-3P1APdRkExoe6wyZ5h0SJiwhzCFSOefsk6i_h-F7D74F7rDx/s200/message_info.gif" alt="" id="BLOGGER_PHOTO_ID_5361635898838717394" border="0" /><img style="width: 16px; height: 16px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbWUg_4xL4LEDA72LuOrdDd6zmbsgUtlmMExvR3AzLARcOW-b-FVr0P_5qrzy3FF38ehunY3_FOwEAdDIko18uOPWav0799kYQDvfhxTmAmsjPaIhvP2XQHMH_A4a4yle_hTj5e-syQTAn/s200/message_error.gif" alt="" id="BLOGGER_PHOTO_ID_5361635894974271074" border="0" />
<br/>
And in a form they look like this:
<br/>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://content.screencast.com/users/philk/folders/Jing/media/b2d5cbb7-ea1e-4f77-9a23-3e6203f55175/Message_info_icon_old.png"><img style="cursor: pointer; width: 354px; height: 98px;" src="http://content.screencast.com/users/philk/folders/Jing/media/b2d5cbb7-ea1e-4f77-9a23-3e6203f55175/Message_info_icon_old.png" alt="" border="0" /></a>
<br/>
Now, there is a quick and easy way to replace them with your own icons if you like.
<br/>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://content.screencast.com/users/philk/folders/Jing/media/6e5f5d6e-d050-40ce-bcac-b4d32456920b/form_with_new_icon.png"><img style="cursor: pointer; width: 355px; height: 98px;" src="http://content.screencast.com/users/philk/folders/Jing/media/6e5f5d6e-d050-40ce-bcac-b4d32456920b/form_with_new_icon.png" alt="" border="0" /></a>
<br/>
You just have to create a Fragment bundle and set <span style="font-family:courier new;">org.eclipse.jface</span> as its <span style="font-weight: bold;">Bundle-Host</span>. In your fragment bundle you include the icons you want to replace in the following folder structure:
<br/>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://content.screencast.com/users/philk/folders/Jing/media/2a399417-4af0-46fb-8672-fd3f8af62fc2/2009-07-23_1516.png"><img style="cursor: pointer; width: 206px; height: 254px;" src="http://content.screencast.com/users/philk/folders/Jing/media/2a399417-4af0-46fb-8672-fd3f8af62fc2/2009-07-23_1516.png" alt="" border="0" /></a>
<div style="text-align: left;">Don't forget to add the icons folder and all of its subfolder and content into your <span style="font-family:courier new;">build.properties</span> file:
<pre>
bin.includes = META-INF/,\
.,\
OSGI-INF/,\
icons/
</pre>
</div>
<span style="font-weight: bold;">Interesting fact</span>: You can replace the JFace icons with PNGs too. You can just rename them to have the .GIF extensions. The image file loader of SWT does not care about the extension but analyses the content of the file.Unknownnoreply@blogger.com3