In this post I will describe how to develop and package an OSGi application so that it is Grog-ready.
Your applications will run in sandboxes based on the Eclipse Equinox framework with the following plug-ins installed:
- DS services
- ECF remote components
- ZooKeeper service location and discovery
For the application development part, follow the ECF remote OSGi DS Declarative Services guide. At the end of the development process you will have a fully configured OSGi application and you'll need to perform just a few more steps before being able to successfully deploy it on Grog.
IMPORTANT
Here are some things to remember:
- Configure your hosts file to correctly resolve IPs and hostnames otherwise nothing will work as ZooKeeper publishes and binds to services based on hostnames and not IPs when it is not configured with a static IP. You can track this issue on Jira, StackOverflow or the ECF forum. I'm still not sure if it's a bug or simply a missing feature
- The platform is still in a prototype state, so many features are missing, see below:
- Each service bundle can offer one and only one interface
- Each service bundle must be called exactly as the implemented interface
Obviously these issues are at the top of the "future developments" list.
Now, on to the bundles preparation. For the service:
- Create a folder called exactly as the interface offered and copy the plugins and configuration folders from where Eclipse exported your service application inside it. For example, if you implemented the com.acme.IFoo interface, call your folder com.acme.IFoo Note: this step will no longer be required as soon as I implement a better package name->services offered translation protocol.
- Go into the plugins directory and rename the org.eclipse.osgi_VERSION.jar to simply org.eclipse.osgi.jar
- Open you application jar file, extract the META-INF folder and put it under the application root folder. In our example you would end up having something like com.acme.IFoo/META-INF/MANIFEST.MF
- Edit the META-INF/MANIFEST.MF file and add this line: Bundle-Description: IMPLEMENTED_INTERFACE In our example you would put: Bundle-Description: com.acme.IFoo
- Edit the configuration/config.ini file and add @start to all bundles NOT fragment to be started automatically as soon as the frameworks goes up. You may skip this step if you already configured it with Eclipse. For example, following our guide, you would have something like this:
#Product Runtime Configuration File
eclipse.application=it.eng.test.remote.ds.helloservice.HelloServiceTest
osgi.bundles.defaultStartLevel=4
osgi.bundles=\
it.eng.test.remote.ds.hello,\
it.eng.test.remote.ds.helloservice@start,\
javax.transaction,\
org.apache.hadoop.zookeeper@start,\
org.apache.log4j@start,\
org.eclipse.core.contenttype@start,\
org.eclipse.core.jobs@start,\
org.eclipse.core.runtime@start,\
org.eclipse.core.runtime.compatibility.registry,\
org.eclipse.ecf@start,\
org.eclipse.ecf.discovery@start,\
org.eclipse.ecf.identity@start,\
org.eclipse.ecf.osgi.services.distribution@start,\
org.eclipse.ecf.osgi.services.remoteserviceadmin@start,\
org.eclipse.ecf.osgi.services.remoteserviceadmin.proxy@start,\
org.eclipse.ecf.provider@start,\
org.eclipse.ecf.provider.remoteservice@start,\
org.eclipse.ecf.provider.zookeeper@start,\
org.eclipse.ecf.remoteservice@start,\
org.eclipse.ecf.sharedobject@start,\
org.eclipse.ecf.ssl,\
org.eclipse.equinox.app@start,\
org.eclipse.equinox.common@2:start,\
org.eclipse.equinox.concurrent@start,\
org.eclipse.equinox.ds@2:start,\
org.eclipse.equinox.preferences@start,\
org.eclipse.equinox.registry@start,\
org.eclipse.equinox.util@start,\
org.eclipse.equinox.weaving.hook,\
org.eclipse.osgi.services@start,\
org.eclipse.osgi.services.remoteserviceadmin@start,\
org.eclipse.persistence.jpa.equinox.weaving
For the client, you can follow the same steps as for the service but:
- You can call the application folder however you like, as long as your application will only consume services and not offer them.
- Exactly the same.
- Ditto.
- Edit the META-INF/MANIFEST.MF file and add this line: Require-Bundle: REQUIRED_INTERFACE_1;...;REQUIRED_INTERFACE_N In our example you would put: Require-Bundle: com.acme.IFoo If your client relies on multiple interfaces, just add them one after another and separate them with a semicolon ";"
- Same as before. If you followed our guide you would end up with:
#Product Runtime Configuration File
eclipse.application=it.eng.test.remote.ds.helloconsumer.HelloConsumerTest
osgi.bundles.defaultStartLevel=4
osgi.bundles=it.eng.test.remote.ds.hello,\
it.eng.test.remote.ds.helloconsumer@start,\
javax.transaction,\
org.apache.hadoop.zookeeper@start,\
org.apache.log4j@start,\
org.eclipse.core.contenttype@start,\
org.eclipse.core.jobs@start,\
org.eclipse.core.runtime@start,\
org.eclipse.core.runtime.compatibility.registry,\
org.eclipse.ecf@start,\
org.eclipse.ecf.discovery@start,\
org.eclipse.ecf.identity@start,\
org.eclipse.ecf.osgi.services.distribution@start,\
org.eclipse.ecf.osgi.services.remoteserviceadmin@start,\
org.eclipse.ecf.osgi.services.remoteserviceadmin.proxy@start,\
org.eclipse.ecf.provider@start,\
org.eclipse.ecf.provider.remoteservice@start,\
org.eclipse.ecf.provider.zookeeper@start,\
org.eclipse.ecf.remoteservice@start,\
org.eclipse.ecf.sharedobject@start,\
org.eclipse.ecf.ssl,\
org.eclipse.equinox.app@start,\
org.eclipse.equinox.common@2:start,\
org.eclipse.equinox.concurrent@start,\
org.eclipse.equinox.ds@2:start,\
org.eclipse.equinox.preferences@start,\
org.eclipse.equinox.registry@start,\
org.eclipse.equinox.util@start,\
org.eclipse.equinox.weaving.hook,\
org.eclipse.osgi.services@start,\
org.eclipse.osgi.services.remoteserviceadmin@start,\
org.eclipse.persistence.jpa.equinox.weaving
If you are unsure, you can tell which bundles are fragments by test running your application. Open a terminal and browse to the plugins folder under your application folder, then type:
java -jar org.eclipse.osgi.jar -console -consoleLog -configuration ../configuration
The osgi prompt should appear; now type:
ss
and you should be presented with the list of all installed bundles, their ID, their status and name. If you browse through all bundle names, you will notice that some bundles have a caption after their name. It will be Fragments=FRAGMENT_ID if that bundle HAS FRAGMENT_ID as a fragment and Master=MASTER_ID if the bundle IS a fragment of MASTER_ID.
Now just compress the application folders as .zip and you're done.
If you want you may add the following entries to the MANIFEST.MF file too:
- Require-OS: OS_NAME Note: different Linux distributions will identify themselves simply by "Linux" (without quotes) while Windows versions will include the version name e.g.: Windows XP, Windows Vista, etc.
- Require-Arch: ARCH_TYPE Note: Windows will use the form of x86 while Linux will use the full i386
- Require-RAM: FREE_RAM - the amount of minimum actually free available RAM (sometimes the actual free available RAM is less than the amount displayed by system monitoring tools) needed to run the application in MB e.g.:128
- Require-Hz: PROCESSOR_SPEED - in Hz e.g.: 1000
- Require-Cores: PROCESSOR_CORES - integer e.g.: 2
If any of those requirements is not met, the application will be rejected and not started.
No comments:
Post a Comment
With great power comes great responsibility