Saturday, April 7, 2012

Class Reloading-4 using Struts2 OSGi plugin without springs dependency

Class Reloading-4 using Struts2 OSGi plugin without springs dependency

I am writing this blog because I did not find a tutorial of using struts2 OSGi plugin without spring dependency. The official plugin document is a bit blurred. In fact this plugin has very minimal documentation. Which shows either people found it uninteresting or are unknown to this plugin. So in order to bring some interest to this plugin and one can easily get a feel of how this works, I am writing this along with small projects in google code, which should be easy to run as soon as you checkout. These are eclipse projects and maven managed dependencies.



The main project already contains 3 bundles. 
MyOsgi.jar
struts2-osgi-admin-bundle-2.3.1.jar
struts2-osgi-demo-bundle-2.3.1.jar (The official demo bundle comes with spring dependency injection for ActionClass creation, which I changed to a normal action without DI, it works great) 
This is my web.xml. Note the TemplatePath variable I found this out the hard way.


<web-app id="struts_blank" version="2.4" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://java.sun.com/xml/ns/j2ee" 
xsi:schemalocation=
"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Struts Blank Convention</display-name>

    <listener>
        <listener-class>view.InitListener</listener-class>
    </listener>

 <context-param>
     <param-name>TemplatePath</param-name>
     <param-value>class://</param-value>
 </context-param>
 <context-param>
     <param-name>struts.osgi.clearBundleCache</param-name>
     <param-value>false</param-value>
 </context-param>
 
 <listener>
        <listener-class>
           org.apache.struts2.osgi.StrutsOsgiListener
        </listener-class>
    </listener>
 
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
      

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Here is my struts.properties
struts.ObjectFactory tells that class reloading and instantiation is done by OSGi Note my second line is committed

struts.objectFactory=osgi
#struts.objectFactory.delegate=sprintOsgi

All the dependencies are managed by maven. So here is the pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>view</groupId>
    <artifactId>osgi</artifactId>
    <version>${project.version}</version>
    <packaging>war</packaging>
    <name>Struts 2 Blank Convention Webapp</name>

    <properties>
        <project.version>2.3.1</project.version>
        <struts2.version>${project.version}</struts2.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-core</artifactId>
            <version>${struts2.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-convention-plugin</artifactId>
            <version>${struts2.version}</version>
        </dependency>

         

        <dependency>
          <groupId>org.apache.struts</groupId>
          <artifactId>struts2-config-browser-plugin</artifactId>
          <version>${struts2.version}</version>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.5</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
      <groupId>velocity</groupId>
      <artifactId>velocity</artifactId>
      <version>1.5</version>
  </dependency>
  
  <dependency>
      <groupId>velocity-tools</groupId>
      <artifactId>velocity-tools</artifactId>
      <version>1.3</version>
  </dependency>
  

  <dependency>
   <groupId>commons-digester</groupId>
   <artifactId>commons-digester</artifactId>
   <version>2.1</version>
  </dependency>
  <dependency>
   <groupId>org.apache.struts</groupId>
   <artifactId>struts2-osgi-plugin</artifactId>
   <version>${struts2.version}</version>
  </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.21</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <scanTargets>
                        <scanTarget>src/main/webapp/WEB-INF</scanTarget>
                        <scanTarget>src/main/webapp/WEB-INF/web.xml</scanTarget>
                        <scanTarget>src/main/resources/struts.xml</scanTarget>
                    </scanTargets>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


If you know struts2 this should get you started. The project directory hierarchy looks like this
osgi
│   .classpath
│   .project
│   pom.xml
│
├───.settings
│
├───src
│   ├───main
│   │   ├───java
│   │   │   └───view
│   │   │       │   InitListener.java
│   │   │       │
│   │   │       └───actions
│   │   │               HelloAction.java
│   │   │
│   │   ├───resources
│   │   │   │   log4j.properties
│   │   │   │   struts.properties
│   │   │   │
│   │   │   └───view
│   │   │           package.properties
│   │   │           package_es.properties
│   │   │
│   │   └───webapp
│   │       │   index.jsp
│   │       │
│   │       └───WEB-INF
│   │           │   appengine-web.xml
│   │           │   web.xml
│   │           │
│   │           ├───classes
│   │           │   └───bundles
│   │           │       └───2
│   │           │               MyOsgi.jar
│   │           │               struts2-osgi-admin-bundle-2.3.1.jar
│   │           │               struts2-osgi-demo-bundle-2.3.1.jar
│   │           │
│   │           └───content
│   │                   hello.jsp
│   │
│   └───test
│       └───java
│           └───view
│               └───actions
└───target

This is really a struts-blank created using mvn archetype:generate for struts2 conventions example. The Action class HelloAction.class is actually empty and not really of any use. The interesting part is the folder where you can put all your bundles WEB-INF/classes/bundles/2 Just copy the bundle there and fire up the browser http://localhost:6060/osgi/osgi/admin/


You will see the below screen:



There is the shell for apache felix: http://localhost:6060/osgi/osgi/admin/shell.action Click on that, open the shell and type ps It will show all the active bundles
$ ps
START LEVEL 3

   ID   State         Level  Name

[   0] [Active     ] [    0] System Bundle (1.4.1)

[   1] [Active     ] [    1] Apache Felix Shell Service (1.0.2)

[   2] [Active     ] [    1] Apache Felix Framework (1.4.1)

[   3] [Active     ] [    2] MyOsgi (1.0.0.qualifier)

[   4] [Active     ] [    2] Struts 2 OSGi Admin Bundle (2.3.1)

[  24] [Active     ] [    2] Struts 2 OSGi Demo Bundle (2.3.1)


$ stop 3



$ uninstall 3





The number of running processed now becomes MyOsgi.
$ ps


START LEVEL 3

   ID   State         Level  Name

[   0] [Active     ] [    0] System Bundle (1.4.1)

[   1] [Active     ] [    1] Apache Felix Shell Service (1.0.2)

[   2] [Active     ] [    1] Apache Felix Framework (1.4.1)

[   4] [Active     ] [    2] Struts 2 OSGi Admin Bundle (2.3.1)

[  24] [Active     ] [    2] Struts 2 OSGi Demo Bundle (2.3.1)



The MyOSGI bundle will be now installed again:
---$ install file:///C:/Users/Samarjit/Desktop/test/MyOSGI/MyOsgi.jar
Bundle ID: 26



$ ps
START LEVEL 3

   ID   State         Level  Name

[   0] [Active     ] [    0] System Bundle (1.4.1)

[   1] [Active     ] [    1] Apache Felix Shell Service (1.0.2)

[   2] [Active     ] [    1] Apache Felix Framework (1.4.1)

[   4] [Active     ] [    2] Struts 2 OSGi Admin Bundle (2.3.1)

[  24] [Active     ] [    2] Struts 2 OSGi Demo Bundle (2.3.1)

[  26] [
Installed
  ] [    1] MyOsgi (1.0.0.qualifier)



$ start 26




$ ps
START LEVEL 3

   ID   State         Level  Name

[   0] [Active     ] [    0] System Bundle (1.4.1)

[   1] [Active     ] [    1] Apache Felix Shell Service (1.0.2)

[   2] [Active     ] [    1] Apache Felix Framework (1.4.1)

[   4] [Active     ] [    2] Struts 2 OSGi Admin Bundle (2.3.1)

[  24] [Active     ] [    2] Struts 2 OSGi Demo Bundle (2.3.1)

[  26] [
Active     
] [    1] MyOsgi (1.0.0.qualifier)
Also look at eclipse console: Among other things you will also see the initiation logs of the MyOsgi bundle which is in our case a simple "Hello World!!". Go ahead and change that and uninstall/install again.

Creating Bundle MyOsgi.jar

We will now see how the bundles are created. Frankly enough I am really a new to OSGi, but I will try to create a very basic bundle, and this can be dropped in bundles folder and installed and activated. The MyOsgi project is ofcourse a basic ecclipse plugin project, created by
eclipse->New project->Plugin Project As you know eclipse is build on top of equinox OSGi, but since we are going to use Apache Felix which is bundles with the Struts2 OSGi plugin, just select the targeted runtime as standard.
Enter a project name, and select Target Platform (this project is targeted to run with:): Standard

MyOsgi
│   .project
│   .classpath
│   build.properties
│
├───src
│   └───myosgi
│           Activator.java
│
├───.settings
│       org.eclipse.jdt.core.prefs
│       org.eclipse.pde.core.prefs
│
├───META-INF
│       MANIFEST.MF
│
└───bin
    └───myosgi
            Activator.class
The main entry point of any bundle is this class. This needs to be mentioned in META-INF/MANIFEST.MF file. All I have done is added in the System.out.println() there which gets printed when the bundle is activated or deactivated.
package myosgi;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

 /*
  * (non-Javadoc)
  * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
  */
 public void start(BundleContext context) throws Exception {
  System.out.println("Hello World!!");
 }
 
 /*
  * (non-Javadoc)
  * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
  */
 public void stop(BundleContext context) throws Exception {
  System.out.println("Goodbye World!!");
 }

}
This is how the MANIFEST.MF file should look like, which eclipse will create automatically. To export import packages you will need to edit this file.
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MyOsgi
Bundle-SymbolicName: MyOsgi
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: myosgi.Activator
Import-Package: org.osgi.framework;version="1.3.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6


To create the MyOsgi.jar, export from eclipse as a normal jar, but make sure NOT to overwrite META-INF/MANIFEST.MF. Once that jar is exported you can extract it and check the MANIFEST.MF file remains as it is. That's all so far. Also note all the bundle packages that are present in You should be able to understand how to use struts2 osgi plugin, install uninstall bundles. In the project uploaded in google code, you can checkout create a few mode bundles and have fun.

2 comments:

  1. Hello! Google code repository is empty. Where can I find the source? Thanks

    ReplyDelete
  2. Source code is present in readonly mode in google code.
    https://code.google.com/archive/p/class-reloading-test/source/default/source

    ReplyDelete