rich client 2.0

Updates for RCP Dummies - Restricting the Update-Manager


3. July 2007
Tom Seidel @ 09:50

box_software.pngThe Eclipse Update Mechanism is an essential feature for RCP development. Without the possibility to update content or business logic or to fix a bug after you have distributed your product, the RCP Framework wouldn’t be interesting. But the problem is the basic concept of Eclipse itself. It is developed as an open platform where you can plug into everything you want. For RCP-Development this is not practicable in the majority of the cases. You need a restricted management of updates where the user has no choices and no possibility to customize any parameter of an update. Unfortunately Eclipse’s Update-Manager can not be restricted out-of-the-box. In the following I will share my experience with modifying the org.eclipse.update.ui-Plugin.

Requirements

  • check for updates on startup
  • notify the user for pending updates
  • show all updates that are available
  • user can not add update sites
  • user can not choose any updates
  • user can not choose the target-location
  • update must be a “one-page” wizard
  • no dialog if the user wants to install updates
  • scheduled update properties can not be modified
Update Manager Eclipse Europa
Europa Update-Manager

Import Plugins into your workspace

The first step is to import the plugin as source-project (see picture). After that the plugin is listed as normal plugin project and is ready to get modified. In this case the modifications were limited to org.eclipse.update.internal.ui.wizards.InstallWizard2 and org.eclipse.update.internal.ui.wizards.ReviewPage.

Import the plug-in as source project
Import the plug-in as source project

The plugin org.eclipse.update.scheduler needed also some modifications: The dialog with the question to review found updates needed to be disabled. After these modifications the update-plugins were referenced in the common way.

Enabling automatic updates in your plugin_customization.ini

To enable automatic scheduled updates at start up add the following lines to your plugin_customization.ini

org.eclipse.update.ui/discoverySitesEnabled=true
org.eclipse.update.scheduler/enabled = true
org.eclipse.update.scheduler/schedule = on-startup
org.eclipse.update.scheduler/download = false
org.eclipse.update.core/org.eclipse.update.core.checkSignature = false

Restricting preference pages

The final step is to remove the property-page org.eclipse.update.internal.ui.preferences.MainPreferencePage and to add the plugin org.eclipse.net.ui to your plugin-dependencies so that the update is also accessible with a proxy.

Defining the feature and creating an Update-Site

The rest of the procedure does not differ from a regular feature-creation. It is strongly recommended to integrate the modified plugins to your feature, that you can also update these plug-ins. In most cases it is probably the best to bundle all required plugins to you feature or to an extra feature (you can also integrate the org.eclipse.rcp feature to your feature).

Example Application

I have written a simple RCP with a label. The update replaces the label. Particular attention must be paid to the update-manager (see picture).

The restricted update-manager
The restricted update-manager

Conclusion

Modifying the source code of platform plug-ins should always be the last resort. It is very difficult to merge further updates or bugfixes. And it’s not obvious if your modification will have side effects. However, in this case a modification was unavoidable and we could accomplish the requirements.

Downloads

Download the Update Example as RCP (13 Mbyte)
cvs_persp.gif CVS-Checkout (more info)

  • cvs_persp.gif de.spiritlink.update.feature
  • cvs_persp.gif de.spiritlink.update.rcp
  • cvs_persp.gif org.eclipse.update.scheduler
  • cvs_persp.gif org.eclipse.update.ui

13 Comments »

  1. Sounds like you just needed to get rid of the Update UI plugin, and write your own implementation that drove the update manager under the covers.

    Comment by Alex Blewitt — 3. July 2007 @ 11:53

  2. Exactly. But you don’t need to write your own, you just have to modify the given ui-plugin.

    Comment by Tom Seidel — 8. July 2007 @ 21:57

  3. I’m currently developing an RCP application. Is there a “best” way to internationalize the Update UI? I have created a UpdateUIPluginResources_fr_FR.properties in the org.eclipse.update.ui plugin but this will restrict me to update for a new version of org.eclipse.update.ui plugin, no? Could i put it in my RCP application, and how? Thanks

    Comment by Ben GAYON — 24. July 2007 @ 01:58

  4. I18n for the common eclipse plugins is already provided by eclipse. See http://download.eclipse.org/eclipse/downloads/drops/L-3.2.1_Language_Packs-200609210945/index.php

    Comment by Tom Seidel — 26. July 2007 @ 19:51

  5. How come that there is no “Software Updates” menu in your application? Isn’t it coming “together” with the org.eclipse.update.ui plug-in?

    And, in this case, how can you “tell” the application where to search for the new features if there is no feature installed when you run the application for the first time?

    Thanks!

    Comment by Florin Banica — 8. October 2008 @ 11:07

  6. P.S. How can I “tell” the application where NOT to look for new features? I would like my application to look ONLY on MY update site and forget about the Eclipse updates…

    Thanks again!

    Comment by Florin Banica — 8. October 2008 @ 11:11

  7. I get your source files from CVS but when I want to test your product by launching it form .product file, I get many errors. I’m under Eclipse 3.4.
    Here are the errors :

    !SESSION 2008-11-06 16:21:50.731 ———————————————–
    eclipse.buildId=unknown
    java.version=1.5.0_14
    java.vendor=Sun Microsystems Inc.
    BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=fr_FR
    Framework arguments: -product de.spiritlink.update.rcp.update_product
    Command-line arguments: -product de.spiritlink.update.rcp.update_product -data C:\Users\xavier.andre\Documents\Sources\workspace-plugins-3.4/../runtime-de.spiritlink.update.rcp.product -dev file:C:/Users/xavier.andre/Documents/Sources/workspace-plugins-3.4/.metadata/.plugins/org.eclipse.pde.core/de.spiritlink.update.rcp.product/dev.properties -os win32 -ws win32 -arch x86 -consoleLog

    !ENTRY org.eclipse.equinox.app 0 0 2008-11-06 16:21:52.120
    !MESSAGE Product de.spiritlink.update.rcp.update_product could not be found.

    !ENTRY org.eclipse.osgi 4 0 2008-11-06 16:21:52.167
    !MESSAGE Application error
    !STACK 1
    java.lang.RuntimeException: No application id has been found.
    at org.eclipse.equinox.internal.app.EclipseAppContainer.startDefaultApp(EclipseAppContainer.java:236)
    at org.eclipse.equinox.internal.app.MainApplicationLauncher.run(MainApplicationLauncher.java:29)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:382)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:549)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:504)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1236)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1212)

    !ENTRY org.eclipse.osgi 2 0 2008-11-06 16:21:52.214
    !MESSAGE One or more bundles are not resolved because the following root constraints are not resolved:
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.214
    !MESSAGE Bundle initial@reference:file:plugins/org.eclipse.core.net_1.1.0.I20080604.jar/ was not resolved.
    !SUBENTRY 2 org.eclipse.core.net 2 0 2008-11-06 16:21:52.214
    !MESSAGE Missing required bundle org.eclipse.equinox.security_[1.0.0,2.0.0).

    !ENTRY org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE The following is a complete list of bundles which are not resolved, see the prior log entry for the root cause if it exists:
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE Bundle initial@reference:file:../../Users/xavier.andre/Documents/Sources/workspace-plugins-3.4/de.spiritlink.update.rcp/ [2] was not resolved.
    !SUBENTRY 2 de.spiritlink.update.rcp 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.update.core_0.0.0.
    !SUBENTRY 2 de.spiritlink.update.rcp 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.update.scheduler_0.0.0.
    !SUBENTRY 2 de.spiritlink.update.rcp 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.update.ui_0.0.0.
    !SUBENTRY 2 de.spiritlink.update.rcp 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.ui.net_0.0.0.
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE Bundle initial@reference:file:plugins/org.eclipse.core.net_1.1.0.I20080604.jar/ [9] was not resolved.
    !SUBENTRY 2 org.eclipse.core.net 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.equinox.security_[1.0.0,2.0.0).
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE Bundle initial@reference:file:plugins/org.eclipse.ui.net_1.0.0.I20080605.jar/ [25] was not resolved.
    !SUBENTRY 2 org.eclipse.ui.net 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.core.net_[1.0.0,2.0.0).
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE Bundle initial@reference:file:../../Users/xavier.andre/Documents/Sources/workspace-plugins-3.4/org.eclipse.update.core/ [28] was not resolved.
    !SUBENTRY 2 org.eclipse.update.core 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.core.net_[1.0.0,2.0.0).
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE Bundle initial@reference:file:../../Users/xavier.andre/Documents/Sources/workspace-plugins-3.4/org.eclipse.update.core.win32/ [29] was not resolved.
    !SUBENTRY 2 org.eclipse.update.core.win32 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing host org.eclipse.update.core_[3.0.0,4.0.0).
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE Bundle initial@reference:file:plugins/org.eclipse.update.scheduler_3.2.100.v20080404.jar/ [30] was not resolved.
    !SUBENTRY 2 org.eclipse.update.scheduler 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.update.core_[3.1.0,4.0.0).
    !SUBENTRY 2 org.eclipse.update.scheduler 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.update.ui_[3.1.0,4.0.0).
    !SUBENTRY 1 org.eclipse.osgi 2 0 2008-11-06 16:21:52.229
    !MESSAGE Bundle initial@reference:file:plugins/org.eclipse.update.ui_3.2.100.v20080318.jar/ [31] was not resolved.
    !SUBENTRY 2 org.eclipse.update.ui 2 0 2008-11-06 16:21:52.229
    !MESSAGE Missing required bundle org.eclipse.update.core_[3.1.0,4.0.0).

    Could you help to make it working under Eclipse 3.4 please ?
    Thanks in advance !

    Comment by Xavier André — 6. November 2008 @ 17:22

  8. The product file was developed with 3.3, to resolve the missing dependencies, open the product file, change to the “Configuration”-Tab and use the “Add required Plug-Ins” button.

    Comment by Tom Seidel — 6. November 2008 @ 17:49

  9. OK, I tried to do it, but now I get this exception :

    !SESSION 2008-11-10 13:45:07.788 ———————————————–
    eclipse.buildId=unknown
    java.version=1.6.0_07
    java.vendor=Sun Microsystems Inc.
    BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=fr_FR
    Framework arguments: -product de.spiritlink.update.rcp.update_product
    Command-line arguments: -product de.spiritlink.update.rcp.update_product -data C:\Users\xavier.andre\Documents\Sources\workspace-rcp-3.4/../runtime-de.spiritlink.update.rcp.product -dev file:C:/Users/xavier.andre/Documents/Sources/workspace-rcp-3.4/.metadata/.plugins/org.eclipse.pde.core/de.spiritlink.update.rcp.product/dev.properties -os win32 -ws win32 -arch x86 -consoleLog

    !ENTRY org.eclipse.osgi 2 0 2008-11-10 13:45:09.406
    !MESSAGE The activator de.spiritlink.update.rcp.Activator for bundle de.spiritlink.update.rcp is invalid
    !STACK 0
    org.osgi.framework.BundleException: The activator de.spiritlink.update.rcp.Activator for bundle de.spiritlink.update.rcp is invalid
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:146)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:980)
    at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:265)
    at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:400)
    at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:234)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1274)
    at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:160)
    at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:867)
    at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
    at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:188)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:386)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:549)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:504)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1236)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1212)
    Caused by: java.lang.ClassNotFoundException: de.spiritlink.update.rcp.Activator
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:481)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:397)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:385)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:87)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:313)
    at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:139)
    … 23 more
    Root exception:
    java.lang.ClassNotFoundException: de.spiritlink.update.rcp.Activator
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:481)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:397)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:385)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:87)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:313)
    at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:139)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:980)
    at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:265)
    at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:400)
    at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:234)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1274)
    at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:160)
    at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:867)
    at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
    at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:188)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:386)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:549)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:504)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1236)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1212)

    !ENTRY org.eclipse.osgi 4 0 2008-11-10 13:45:09.426
    !MESSAGE Application error
    !STACK 1
    org.eclipse.core.runtime.CoreException: Plug-in de.spiritlink.update.rcp was unable to load class de.spiritlink.update.rcp.Application.
    at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.throwException(RegistryStrategyOSGI.java:180)
    at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:162)
    at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:867)
    at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
    at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:188)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:386)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:549)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:504)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1236)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1212)
    Caused by: java.lang.ClassNotFoundException: de.spiritlink.update.rcp.Application
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:481)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:397)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:385)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:87)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:313)
    at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1274)
    at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:160)
    … 16 more

    How can not it be able to find the activator class ?

    Comment by Xavier André — 10. November 2008 @ 14:46

  10. Here are the difference into the .product file once I updated the dependancies :

    Thanks.

    Comment by Xavier André — 10. November 2008 @ 14:48

  11. I tried , it can find the feature but can not update. and the error info:
    ——————————————-
    Invalid combination
    The current configuration cantains errors and this operation can have unpredictable results.
    [Details]Resulting configuration does not contain the platform.
    ——————————————-
    where is the problem?

    Comment by ccat — 29. April 2009 @ 05:35

  12. @ccat

    Have you set up a target platform with the feature 1.0 and the plugins that are required to run this rcp application?

    Comment by Tom Seidel — 29. April 2009 @ 10:01

  13. Hi Tom!

    I tried to download sources from the given CVS server, but my Tortoise cannot connect to the host (I cannot ping it).

    Can you tell me, if IP changed, or how to get the sources? Thanks a lot!

    Comment by Blaise — 16. June 2009 @ 16:21

RSS feed for comments on this post. TrackBack URI

Leave a comment

Powered by WordPress