code.pst » tech musings and code posts |
|
Spring DM OSGi demo appSeptember 28th, 2009 by rahulAs you will see Spring DM makes life much simpler! It manages all “OSGi aware” pieces of the application for you and you can rid of the Activators. The bundles we need now are similar as before. I will prefix “spring” to the artifactId just so its easier. The shared service: We don’t need to change anything in shared so just use the older one as-is. Creating a service implementation: The public class ComplexServiceImpl implements ComplexService { public String doSomething() { return "Hello from Version 1!"; } } To register the service we now use the OSGi extender provided by Spring DM. All we need to do is create some XML configs. <?xml version="1.0" encoding="UTF-8"?> <beans ..... > <!-- Create bean --> <bean id="complexService" class="com.irahul.spring.complexapp.ComplexServiceImpl"/> <!-- register service --> <osgi:service ref="complexService" interface="com.irahul.shared.ComplexService" /> </beans> Creating the servlet: In Spring world we just create the handler and then wire it up using XML. public class MyHandler implements Servlet { private HttpService httpService; private List<ComplexService> complexServices; public void setHttpService(HttpService httpService){ this.httpService = httpService; } public void setComplexServices(List<ComplexService> complexServices) { this.complexServices = complexServices; } //ideally this should be externalized. Have a manager listen for servlets but keeping it simple public void init() throws Exception{ httpService.registerServlet("/", this, null, null); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { //we may have discovered more than 1 service if(complexServices==null|| complexServices.size()==0){ response.getOutputStream().print("No Service found!"); } else{ //there are 1...n services, pick one //using a random pick response.getOutputStream().print(complexServices.get( new Random().nextInt(complexServices.size())).doSomething()); } } .... } Configuring it: <?xml version="1.0" encoding="UTF-8"?> <beans ..... > <!-- Reference list of services in OSGi --> <osgi:list id="complexServiceList" interface="com.irahul.shared.ComplexService" cardinality="0..N"/> <!-- Reference to Http Service --> <osgi:reference id="httpService" interface="org.osgi.service.http.HttpService"/> <!-- Create handler --> <bean id="myHandler" class="com.irahul.spring.http.handler.MyHandler" init-method="init"> <property name="complexServices" ref="complexServiceList"/> <property name="httpService" ref="httpService"/> </bean> </beans> Running in Eclipse Equinox: Use the following config.ini
That is it, see you at code-camp! Tags: spring DM Running demo in Eclipse EquinoxSeptember 24th, 2009 by rahulRunning in Eclipse Equinox: Look up basic instructions on equinox quickstart. Add the following to your config.ini file (note two versions of the same complexapp):
Testing it out: Start Equinox with rahul@lappy /cygdrive/c/osgidemo/runtime osgi> http.handler started! <-- osgi prompt osgi> ss Framework is launched. id State Bundle osgi> bundle 5 osgi> bundle 6 osgi> bundle 7 osgi> stop 6 osgi> stop 7 osgi> ss Framework is launched. id State Bundle osgi> bundle 5 osgi> You can access the handler registered at http://localhost. Open it in a browser and hit refresh a few times, you should see a different message as a random service is picked! Then as you stop/start the complexapp bundles you can expect to see different messages. Next: Spring Dynamic Modules (SpringDM) implementation for this same demo app Tags: eclipse, equinox Pure Java OSGi demo implementationSeptember 24th, 2009 by rahulTo interface with OSGi we need a handle to the .... <Bundle-Activator>com.irahul.http.handler.Activator</Bundle-Activator> .... The shared service: The interface for the shared service is one simple method .... String doSomething(); .... Creating a service implementation: The public class Activator implements BundleActivator{ public void start(BundleContext context) throws Exception { //register the complex service impl context.registerService("com.irahul.shared.ComplexService", new ComplexService(){ public String doSomething() { return "Hello from Version 1!"; } }, null); } ..... } The service is implemented and registered with the bundle context. Creating the servlet: This is done by implementing the public class MyHandler implements Servlet { private List<ComplexService> complexServices = new ArrayList<ComplexService>(); public synchronized void addComplexService(ComplexService service) { if(service==null)return; complexServices.add(service); } public synchronized void removeComplexService(ComplexService svc) { if(svc==null)return; complexServices.remove(svc); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { //we may have discovered more than 1 service if(complexServices==null|| complexServices.size()==0){ response.getOutputStream().print("No Service found!"); } else{ //there are 1...n services, pick one //using a random pick response.getOutputStream().print(complexServices.get( new Random().nextInt(complexServices.size())).doSomething()); } } .... } Creating the http handler: The Activator for the HTTP Handler must now get a reference to this service and in turn register itself with the HTTP Server. In addition to the public class Activator implements BundleActivator, ServiceListener{ private MyHandler myHandler; private BundleContext bundleContext; public void start(BundleContext context) throws Exception { //we need this later bundleContext = context; //we are interested in service updates context.addServiceListener(this); //load referenced services //http service to register handler ServiceReference svcRef = context.getServiceReference("org.osgi.service.http.HttpService"); HttpService httpService = (HttpService)context.getService(svcRef); //create and register http handler (catch all) myHandler = new MyHandler(); httpService.registerServlet("/", myHandler, null, null); //get a list of ComplexService (there may be more than 1) ServiceReference[] complexSvcRefs = context.getServiceReferences("com.irahul.shared.ComplexService",null); if(complexSvcRefs!=null){ for(ServiceReference ref:complexSvcRefs){ myHandler.addComplexService((ComplexService)context.getService(ref)); } } System.err.println("http.handler started!"); } .... public void serviceChanged(ServiceEvent event) { //some service has been registred/removed Object svc=bundleContext.getService(event.getServiceReference()); if(svc instanceof ComplexService){ if(event.getType()==ServiceEvent.REGISTERED){ System.err.println("New Service added"); myHandler.addComplexService((ComplexService)svc); } else{ System.err.println("Service stopped"); myHandler.removeComplexService((ComplexService)svc); } } } } Next: Running this in Eclipse Equinox Tags: BundleContext, eclipse, equinox, Java, OSGi OSGi Demo app designSeptember 22nd, 2009 by rahulThe application will consist of the following bundles (what are bundles?): shared: This bundle exports the service interface for the proposed You also need external bundles that may be downloaded: (Look at OSGi HTTP Server) I will be using the Maven plugin (Felix plugin based on BND) to create the bundles I am writing. For example the POM file for shared is defined as (look at source for all): <project ....> .... <groupId>com.irahul</groupId> <artifactId>shared</artifactId> <packaging>bundle</packaging> <version>1.0-SNAPSHOT</version> <name>shared</name> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>1.4.0</version> <extensions>true</extensions> <configuration> <instructions> <Export-Package> com.irahul.shared*, !* </Export-Package> <Private-Package> com.irahul.shared* </Private-Package> </instructions> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> <dependencies> .... </dependencies> </project> This results in a nicely created bundle with the MANIFEST.MF file like this: Correctly exported and imported packages are a key to resolving your bundles correctly in the OSGi container. Next: Pure Java implementation Tags: felix, maven, maven-bundle-plugin, OSGi, pom Getting started with OSGiSeptember 17th, 2009 by rahulThis is the first part in a series for a presentation at the Silicon Valley Code Camp at Foothill college. For a concise description read through the official OSGi Architecure page. I’ll present a simple application that shows how to dynamically provide an application upgrade with zero downtime and no JVM restart. It will load a HTTP Server and then register a handler with it. This handler then processes the request using a The following sequence diagram shows the events. ![]() Sequence diagram for OSGi example With this simple set of bundles (less than 200 lines of code in all!) I can show the following: Run multiple versions of your app simultaneously: If your application is designed with this mind, you can continue to run singletons of the http server and your data access layer, however you have multiple versions of your business logic which may be used dynamically. Dynamic routing: Expanding on the point above you can build a smart routing mechanism to invoke the different versions of the services that are available. Install new bundles to upgrade features: You may create new services and register them with the http server to provide new features all without a JVM restart. Upgrade application version: You may install a new version of any service and shutdown and remove a previous version and have existing http services use this dynamically. Again no JVM restart. Note on versioning: In OSGi it is possible to version packages exported/imported by bundles. For the purpose of this exercise I’ll keep things simple and not use it. Download presentation: Getting started with OSGi Next: Application design for this demo Tags: Java, OSGi Injecting beans into Quartz jobMay 28th, 2009 by rahulFinally as promised the revised and more efficient way to inject beans directly into your quartz jobs. Simply use the jobDataAsMap property. <bean name="jobBean" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="com.irahul.example.SpringQuartzJob" /> <property name="name" value="jobName" /> <property name="jobDataAsMap"> <map> <entry key="setterName" value-ref="beanRef" /> ..... </map> </property> </bean> Tags: quartz, Spring Accessing Spring beans from Quartz jobsNovember 3rd, 2007 by rahulI had referred to Mark’s blog in my earlier post and actually now have a improvement over his solution. Define your context as usual (courtesy to Mark for his example) <beans> <!-- Define the Job Bean that will be executed. Our bean is named in the jobClass property. --> <bean name="myJob" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="com.gsoftware.common.util.MyJob"/> </bean> <!-- Associate the Job Bean with a Trigger. Triggers define when a job is executed. --> <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <!-- see the example of method invoking job above --> <property name="jobDetail" ref="myJob"/> <property name="startDelay" value="2000"/> <property name="repeatInterval" value="10000"/> </bean> <!-- A list of Triggers to be scheduled and executed by Quartz --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list><ref bean="simpleTrigger"/></list> </property> <property name="applicationContextSchedulerContextKey" value="applicationContext"/> </bean> </beans> Note that in the factory I have added the property for the application context. public class MyJob extends QuartzJobBean { private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext appContext) { applicationContext = appContext; } @Override protected void executeInternal(JobExecutionContext executionContext) { //your code... } } Now you have the application context available in your job. Nothing else required! Tags: quartz, Spring OSGi – Spring Quartz jobOctober 30th, 2007 by rahulMark’s blog provides a good example of how to provide the Spring application context to a Job. Here I will show how to ’inject’ OSGi services into your Spring OSGi application. This will become much cleaner once Spring Dynamic Modules executor bundle is released but at the moment using Spring 2.0.7 I need to provide some OSGi services to my Quartz job. I have say a bundle ‘MyServiceBundle’ that registers a service with the following interface: package com.irahul.example.myservicebundle; public interface TransactionService{ void updateTransaction(Long id, String status); } The activator looks something like: package com.irahul.example.myservicebundle; public class Activator implements BundleActivator { public void start(BundleContext bundleContext){ TransactionService txnSvc = new ....//an implementation of it Map<String,String> metaProperties = new... //define whatever meta data you want to register for service discovery bundleContext.registerService("com.irahul.example.TransactionService", txnSvc,metaProperties); } } Now over in the bundle ‘MyQuartzJob’ define a JobContext which can be injected with all the beans it requires to perform the Job. package com.irahul.example.myquartzjob; public interface JobContext{ void setTransactionService(TransactionService txnSvc); TransactionService getTransactionService(); } Implement the QuartzJobBean to get the application context like in Mark’s blog. Now in your application context create an empty bean with your JobContext implementation. <!-- Job Context --> <bean id="jobContext" class="com.irahul.example.myquartzjob.JobContextImpl"></bean> After that all that remains is the activator, which looks like: package com.irahul.example.myquartzjob public class Activator implements BundleActivator { public void start(BundleContext bundleContext){ // Initialize the Spring application context ApplicationContext applicationContext = new ClassPathXmlApplicationContext( new String[]{"context.xml"}); //get the service ServiceReference txnRef = bundleContext. getServiceReference("com.irahul.example.TransactionService"); //you can search on additonal meta data filter as well TransactionService txnService = (TransactionService)bundleContext.getService(txnRef); //now get the spring bean as setup JobContext jobContext = (JobContext)applicationContext.getBean("jobContext"); jobContext.setTransactionService(txnService); } Your Job now has the application context all setup and ready to go! Tags: application context, bundle context, OSGi, quartz, Spring Facebook demo app – America VotesOctober 28th, 2007 by rahulSo here is the complete source for my version of a hello world facebook app. It starts off from their footprints example that comes with the facebook client. This is a simple app where you vote for your pick of the 2008 president from the huge list of candidates at the moment! It then shows a tally of the top candidates and allows you to invite your friends. You can see it in action at http://apps.facebook.com/americavotes If you look at the source you will see it is pretty straight forward and I’ll try and post some snippets with details if necessary. A few pieces of code are copied from some public internet sources. Download: America Votes Source Tags: facebook platform example, php WelcomeOctober 25th, 2007 by rahulFinally I’ve installed a blog! I’m no blogger so hopefully a couple posts per year should be good Posted in Uncategorized | No Comments » |
|