Network Deployment (Distributed operating systems), v8.0 > Develop and deploying applications > Develop OSGi applications > Convert existing applications to OSGi applications


Convert a Spring application to an OSGi application

To convert an application that is created using the Spring Framework to an OSGi application and move from the Spring Framework to standards-based technologies, modify the application manually. If a Spring application contains only WAR files, you can convert it automatically to run in OSGi Applications, but it still uses the Spring Framework.


About this task

In a Spring application, the Spring Framework manages features such as transactions, persistence, and dependency injection, and handles the communication between the servlets in the web container and the classes that handle the business logic of the application.

After you convert the application to an OSGi application that uses OSGi Applications support, the Blueprint Container manages the transactions, persistence and dependency injection.

If the application is an EAR file that contains only web application archive (WAR) files, you can convert it automatically. You might convert a Spring application in this way if a WAR file uses other library JAR files that must remain unchanged for the application to work. See Convert an enterprise application to an OSGi application.

Otherwise, you need to identify the Spring components and replace them with the equivalent code to make them plain old Java objects (POJOs), then modify the relevant XML files so that the Blueprint container manages those objects.

To convert a Spring application, you change it as follows:

At the end of each step, the application is still usable, so you can decide whether to make all, or just some, of these changes.

The following procedure describes these steps in more detail.


Procedure

  1. Create a well defined interface to delegate to, for example to replace a dispatcher servlet in the Spring application. The following example replaces the Spring HttpRequestHandler interface in an example application with the MyApplicationHandler interface.

    1. Create an interface to replace the Spring HttpRequestHandler interface.
      package com.ibm.ws.eba.example.springconversion;
      
      import javax.servlet.//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  .HttpServletRequest;
      import javax.servlet.//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  .HttpServletResponse;
      
      interface MyApplicationHandler {
      
       void setMyApplicationHandle(MyApplicationUserInterface b);
      
       void handleRequest(HttpServletRequest request, HttpServletResponse response)
      throws Exception;
      
      }
      

    2. In each class that imports and implements the Spring HttpRequestHandler interface, implement the new interface. For example, change the following code:
      implements HttpRequestHandler
      
      to :
      implements MyApplicationHandler
      

    3. If the method creates an exception that is not in a base Java package, for example a ServletException exception, you can change it to use more general exception handling and avoid additional OSGi package imports. For example, change the following code:
      handleRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException
      
      to:
      handleRequest(HttpServletRequest request, HttpServletResponse response)
      throws Exception
      

    To replace the Spring interface with this new interface, you must also replace the servlet, as described in step 4.

  2. At this point, you could continue to use the Spring classes and use the Blueprint Container to manage those objects.

    To do this, change the blueprint.xml file, as described in step 7.

    The configuration for dependency injection that the Blueprint Container uses is similar to the configuration for the Spring Framework. For example, if the Spring Framework calls the setMyApplicationHandle method to inject the MyApplicationUserInterface variable, this injection continues to work in the Blueprint Container, as long as the blueprint.xml file is configured correctly.

  3. Change the managed bean that handles persistence to use standard Java EE persistence classes. In the following example, the Spring JpaTemplate interface handles persistence. It is equally valid if using JPA directly through an entity manager.

    1. Replace the JpaTemplate interface with Java EE persistence classes. For example, remove the following import statement:
      import org.springframework.orm.jpa.JpaTemplate;
      
      Replace it with the following import statements:
      import javax.persistence.EntityManager;
      import javax.persistence.PersistenceContext;
      import javax.persistence.Query;
      

    2. Use the relevant calls that are available in the API for those interfaces. For example, to replace the JpaTemplate code with EntityManager code, remove the following code:
      @PersistenceUnit(unitName = "springExample")
        private JpaTemplate jpaTemplate;
      
        public void setJpaTemplate(JpaTemplate j)
        {
          jpaTemplate = j;
        }
      
      Replace it with the following code:
      @PersistenceContext(unitName = "myApplication")
        private EntityManager em;
        public void setEntityManager(EntityManager e) {
          em = e;
        }
      

    3. If a persistence unit is inside a web application, separate the persistence unit from the WAR and create a persistence bundle. The persistence bundle must contain the entity classes and the persistence.xml file. The bundle manifest must have a Meta-Persistence header that points to the persistence unit, as shown in the following example:
      Manifest-Version: 1.0
      Bundle-ManifestVersion: 2 Bundle-Name: MyPersistenceBundle
      Bundle-SymbolicName: com.ibm.ws.eba.example.persistence
      Bundle-Version: 1.0.0
      Meta-Persistence: WEB-INF/classes/META-INF/persistence.xml
      Import-Package: javax.persistence
      
    4. Replace each instance of a call from the bean that handles persistence with an equivalent call that uses the EntityManager interface, the Query interface, or both. For example, in the example Spring application, the following code snippet shows two methods that call the jpaTemplate.find method:
      @SuppressWarnings("unchecked")
      public boolean checkEMailAddressUniqueness(String emailAddress)
      {
        boolean result = false;
      
        List
      <UserInfo> users = jpaTemplate.find(uniqueEmailAddressQuery, emailAddress);
      
        if (users.isEmpty()) {
          result = true;
        }
      
        return result;
      }
      
      public boolean checkUsernameUniqueness(String username)
      {
        boolean result = false;
      
        UserInfo user = jpaTemplate.find(UserInfo.class, username);
      
        if (user == null) {
          result = true;
        }
      
        return result;
      }
      
      The following code snippet shows replacement code:
      private static final String uniqueEmailAddressQuery = "select u from UserInfo u
      where u.emailAddress = ?1";
      
      @SuppressWarnings("unchecked")
      public boolean checkEMailAddressUniqueness(String emailAddress)
      {
        boolean result = false;
      
        Query q = em.createQuery(uniqueEmailAddressQuery);
        q.setParameter(1, emailAddress);
      
        List
      <UserInfo> users = q.getResultList();
      
        if (users.isEmpty()) {
          result = true;
        }
      
      return result;
      }
      
      public boolean checkUsernameUniqueness(String username)
      {
        boolean result = false;
      
        UserInfo user = em.find(UserInfo.class, username);
      
        if (user == null) {
          result = true;
        }
      
          return result;
        }
      

  4. Create and register a handler servlet to replace the one from the Spring Framework.

    1. Create a servlet to forward requests to the appropriate handler in the Blueprint Container to process the business logic. This servlet is managed by the web container. The JNDI lookup is constructed as follows:
      osgi:service/class_name/ldap_filter
      

      The following code snippet creates the MyApplicationHandlerServlet servlet that passes an HTTP request to the MyApplicationHandler class in the Blueprint Container:

      package com.ibm.ws.eba.example.springconversion;
      
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      import javax.servlet.//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  .HttpServlet;
      import javax.servlet.//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  .HttpServletRequest;
      import javax.servlet.//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  .HttpServletResponse;
      
      public class MyApplicationHandlerServlet extends HttpServlet {
      
       private static final long serialVersionUID = -3705932907251688199L;
      
       @Override
       public void service(HttpServletRequest request, HttpServletResponse response)
       {
        // Get servlet name   String servletName = this.getServletConfig().getServletName();
      
        // Get business logic class from service registry that is
        // associated with the servlet
      
        try {
             InitialContext ic = new InitialContext();
             MyApplicationHandler myApplicationLogicClass = (MyApplicationHandler)
             ic.lookup("osgi:service/com.ibm.ws.eba.example.springconversion.
             MyApplicationHandler/(servlet.name="+servletName+")");
             myApplicationLogicClass.handleRequest(request, response);
         } catch (NamingException e) {
             e.printStackTrace();
         } catch (Exception e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
        }
      
       }
      
      }
      
    2. Register the new servlet by changing the servlet classes to define the servlet you just created, rather than the Spring servlet.

      To do this, modify the web.xml file in the WEB-INF folder of the WAR file.

      For example, change the following servlet definition in the web.xml file:

      <servlet>
      <servlet-name>RegistrationServlet
      </servlet-name>
      <servlet-class> org.springframework.web.context.support.HttpRequestHandlerServlet
      
      </servlet-class>
      </servlet> 
      to:
      <servlet>
      <servlet-name>RegistrationServlet
      </servlet-name>
      <servlet-class>com.ibm.ws.eba.example.springconversion.MyApplicationHandlerServlet
      
      </servlet-class>
      </servlet> 
    3. Delete the following elements from the web.xml file:
      <context-param>
      <listener> 

  5. Separate the persistence unit from the EAR file and create a persistence bundle. The persistence bundle must contain the entity classes and the persistence.xml file. The bundle manifest must have a Meta-Persistence header that points to the persistence unit, as shown in the following example:
    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2 Bundle-Name: MyPersistenceBundle
    Bundle-SymbolicName: com.ibm.ws.eba.example.persistence
    Bundle-Version: 1.0.0
    Meta-Persistence: WEB-INF/classes/META-INF/persistence.xml
    Import-Package: javax.persistence
    

  6. If you removed the persistence unit from a WAR file, delete the following element from the web.xml file in the WEB-INF folder of the WAR file:
    <persistence-unit-ref> 
  7. Change the XML so that the Blueprint Container manages the objects, rather than the Spring Framework.

    1. Delete the springapp-service.xml file in the WEB-INF folder of the WAR file.

    2. Create the OSGI-INF/blueprint/ directory.

    3. Create a file named blueprint.xml in the OSGI-INF/blueprint/ directory. The following code shows an example blueprint.xml file:
      <blueprint xmlns:tx="//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  ://aries.apache.org/xmlns/transactions/v1.0.0"
                 xmlns:jpa="//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  :////publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  ://aries.apache.org/xmlns/jpa/v1.0.0">     
      
      <bean id="myApplicationImpl"
          class="com.ibm.ws.eba.example.springconversion.impl.MyApplicationImpl">
      <jpa:context property="entityManager" unitname="myApplication" />
      <tx:transaction method="*" value="Required"/>
      </bean>
      
      <bean id="RegistrationServlet"
          class="com.ibm.ws.eba.example.springconversion.Registration">
      <tx:transaction method="*" value="Required"/>
      <property name="myApplicationHandle" ref="myApplicationService" />
      </bean>
      
      <service id="myApplicationService" ref="myApplicationImpl" interface=
           "com.ibm.ws.eba.example.springconversion.MyApplicationUserInterface" />
      
      <service id="registrationService" ref="RegistrationServlet" interface=
           "com.ibm.ws.eba.example.springconversion.MyApplicationHandler" >
      <service-properties>
      <entry key="servlet.name" value="RegistrationServlet"/>
      </service-properties>
      
      </service>
      
      </blueprint> 

  8. Update the persistence.xml file in the war/WEB-INF/classes/META-INF/ directory. For example, you can change the JNDI lookups to use a service from a service registry. The following code is an example:
    <persistence xmlns="//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  ://java.sun.com/xml/ns/persistence"
       xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  ://java.sun.com/xml/ns/persistence
       //publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  ://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
       version="1.0">
    
    <persistence-unit name="myApplication" transaction-type="JTA">
    <description>Persistence unit for the Spring conversion sample application
    </description>
    
    <provider>com.ibm.websphere.persistence.PersistenceProviderImpl
    
    </provider>
    
    <jta-data-source>osgi:service/javax.sql.DataSource/
            (osgi.jndi.service.name=jdbc/userdb)
    
    </jta-data-source>
    <non-jta-data-source>osgi:service/javax.sql.DataSource/
            (osgi.jndi.service.name=jdbc/userdbnonjta)
    
    </non-jta-data-source>
    <class>com.ibm.ws.eba.example.springconversion.Post
    </class>
    <class>com.ibm.ws.eba.example.springconversion.UserInfo
    </class>
    <exclude-unlisted-classes/>
    </persistence-unit>
    </persistence> 

  9. Create the enterprise bundle archive (EBA) structure for the application.

    1. Create a META-INF directory in the root of the project and create an application manifest, APPLICATION.MF. The following code shows an example application manifest file:
      Manifest-Version: 1.0
      Application-ManifestVersion: 1.0
      Application-Name: MyApplication Application-SymbolicName: com.ibm.ws.eba.example.springconversion
      Application-Version: 1.0
      Application-Content: com.ibm.ws.eba.example.springconversion
      
    2. Delete the context.xml file from the war/META-INF/ directory.

    3. In the war/META-INF/ directory, create a bundle manifest file, MANIFEST.MF. The following code shows an example bundle manifest file:
      Manifest-Version: 1.0
      Bundle-ManifestVersion: 2 Bundle-Name: MyApplication Bundle-SymbolicName: com.ibm.ws.eba.example.springconversion
      Bundle-Version: 1.0.0
      Bundle-Vendor: IBM Bundle-ClassPath: WEB-INF/classes,
       WEB-INF/lib/aspectjrt.jar,WEB-INF/lib/aspectweaver.jar,
       WEB-INF/lib/commons-collections-3.2.jar,WEB-INF/lib/commons-lang-2.1.jar,
       WEB-INF/lib/JSON4J.jar,WEB-INF/lib/jstl.jar,WEB-INF/lib/jta.jar,
       WEB-INF/lib/openjpa-1.3.0-SNAPSHOT.jar,WEB-INF/lib/persistence.jar,
       WEB-INF/lib/serp-1.13.1.jar,WEB-INF/lib/standard.jar
      Web-ContextPath: myApplication Import-Package: javax.servlet;version="2.5",
       javax.servlet.//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/  ;version="2.5",
       javax.servlet.jsp;version="2.1",
       javax.servlet.jsp.tagext;version="2.1",
       org.osgi.framework;version="1.5.0",
       javax.persistence
      

Parent topic: Convert existing applications to OSGi applications

Related concepts:

About OSGi Applications
Conversion of an enterprise application to an OSGi application
Web application bundles

Related tasks:

Convert an enterprise application to an OSGi application
Secure OSGi Applications
Use the transaction service

Related reference:

OSGi Applications: Troubleshooting tips
Task topic Feedback
Copyright IBM Corporation 2009, 2011. All Rights Reserved.
This information center is powered by Eclipse technology.

+

Search Tips   |   Advanced Search