Announcement Announcement Module
Collapse
No announcement yet.
Comments to this way of implementing Spring into ejbs Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Comments to this way of implementing Spring into ejbs

    I wanted to have access to my POJO's and local interfaces to ejb's from other ejb's using one single Spring application context within the Jboss container..

    I have created a Spring MBean,- running a standalone MBean service....


    Code:
    package no.aftenposten.framework.spring;
    
    import org.jboss.naming.NonSerializableFactory;
    import org.jboss.system.ServiceMBeanSupport;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    
    import javax.naming.*;
    import java.io.*;
    import java.util.Properties;
    
    /**
     * JMX - MBean which initiates the Spring framework by reading the spring.xml, exposing
     * the Spring ApplicationContext from withing the ejb-container via jndi lookup.
     * see spring-service.xml
     *
     * <p/>
     * User&#58; regearne
     * Date&#58; 03.des.2004
     * Time&#58; 15&#58;02&#58;51
     *
     * @author regearne
     * @version $Revision&#58; 1.2 $Date&#58; 2005/01/01 19&#58;31&#58;52 $
     */
    public class SpringService extends ServiceMBeanSupport implements SpringServiceMBean &#123;
        private Properties properties;
        private String jndiName;
        private String propertiesFile;
        private boolean useProperties;
        private boolean usePropertiesFile;
        ApplicationContext context = null;
        private static final String SPRING_CONFIG_KEY = "spring.config";
    
        /*
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         *
         * Constructors.
         *
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         */
        public SpringService&#40;&#41; &#123;
            usePropertiesFile = false;
            propertiesFile = "";
            useProperties = false;
            properties = new Properties&#40;&#41;;
            jndiName = "Spring";
        &#125;
    
        /*
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         *
         * Interface.
         *
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         */
        public void setJndiName&#40;String jndiName&#41; throws Exception &#123;
            String oldName = this.jndiName;
            this.jndiName = jndiName;
    
            if &#40;super.getState&#40;&#41; == STARTED&#41;&#123;
                try &#123;
                    unbind&#40;oldName&#41;;
                &#125; catch &#40;NamingException ne&#41; &#123;
                    log.error&#40;captureStackTrace&#40;ne&#41;&#41;;
    
                    throw new Exception&#40;"Failed to unbind Spring - ", ne&#41;;
                &#125;
    
                try &#123;
                    rebind&#40;&#41;;
                &#125; catch &#40;NamingException ne&#41; &#123;
                    log.error&#40;captureStackTrace&#40;ne&#41;&#41;;
    
                    throw new Exception&#40;"Failed to rebind Spring - ", ne&#41;;
                &#125;
            &#125;
        &#125;
    
        /** Getter for jndiName
         *
         * @return
         */
        public String getJndiName&#40;&#41; &#123;
            return jndiName;
        &#125;
    
        /** Getter for name
         *
         * @return
         */
        public String getName&#40;&#41; &#123;
            return "SpringService&#40;" + jndiName + "&#41;";
        &#125;
    
        /** Setter for properties, - used when assign properties via the
         *  spring-service.xml
         *
         * @param properties
         */
        public void setProperties&#40;String properties&#41; &#123;
            if &#40;usePropertiesFile&#41;&#123;
                log.error&#40;"Must specify only one of 'Properties' or 'PropertiesFile'"&#41;;
                return;
            &#125;
    
            useProperties = true;
    
            try &#123;
                ByteArrayInputStream bais = new ByteArrayInputStream&#40;properties.getBytes&#40;&#41;&#41;;
                this.properties = new Properties&#40;&#41;;
                this.properties.load&#40;bais&#41;;
            &#125; catch &#40;IOException ioe&#41; &#123;
                // should not happen
            &#125;
        &#125;
    
        /** Get properties
         *
         * @return
         */
        public String getProperties&#40;&#41; &#123;
            try &#123;
                ByteArrayOutputStream baos = new ByteArrayOutputStream&#40;&#41;;
                properties.store&#40;baos, ""&#41;;
    
                return new String&#40;baos.toByteArray&#40;&#41;&#41;;
            &#125; catch &#40;IOException ioe&#41; &#123;
                // should not happen
                return "";
            &#125;
        &#125;
    
        /** Setter for propertiesFile
         *
         * @param propertiesFile
         */
        public void setPropertiesFile&#40;String propertiesFile&#41; &#123;
            if &#40;useProperties&#41;&#123;
                log.error&#40;"Must specify only one of 'Properties' or 'PropertiesFile'"&#41;;
                return;
            &#125;
            usePropertiesFile = true;
            this.propertiesFile = propertiesFile;
        &#125;
    
        public String getPropertiesFile&#40;&#41; &#123;
            return propertiesFile;
        &#125;
    
        public void createService&#40;&#41; throws Exception &#123;
        &#125;
    
        public void destroyService&#40;&#41; throws Exception &#123;
            log.info&#40;"Destroy SpringService&#40;" + jndiName + "&#41;..."&#41;;
        &#125;
    
        /** Starting the jmx-service
         *
         * @throws Exception
         */
        public void startService&#40;&#41; throws Exception &#123;
            log.info&#40;"Start SpringService&#40;" + jndiName + "&#41;..."&#41;;
            String configFile;
            if &#40;&#40;configFile = properties.getProperty&#40;SPRING_CONFIG_KEY&#41;&#41; != null&#41;&#123;
                if &#40;new File&#40;configFile&#41;.exists&#40;&#41;&#41;&#123;
                    log.info&#40;"Initializing Spring framework with " + configFile&#41;;
                    context = new FileSystemXmlApplicationContext&#40;configFile&#41;;
                    log.info&#40;"Spring framework initialized"&#41;;
                &#125; else &#123;
                    throw new FileNotFoundException&#40;"File&#58; "+configFile+"doesn't exist"&#41;;
                &#125;
            &#125;
    
            try &#123;
                rebind&#40;&#41;;
            &#125; catch &#40;NamingException ne&#41; &#123;
                log.error&#40;captureStackTrace&#40;ne&#41;&#41;;
    
                throw new Exception&#40;"Failed to rebind Spring - ",
                        ne&#41;;
            &#125;
            log.info&#40;"SpringService&#40;" + jndiName + "&#41; started."&#41;;
        &#125;
    
        public void stopService&#40;&#41; throws Exception &#123;
            log.info&#40;"Stop SpringService&#40;" + jndiName + "&#41;..."&#41;;
    
            log.info&#40;"Spring&#40;" + jndiName + "&#41; stopped."&#41;;
        &#125;
    
        private String captureStackTrace&#40;Throwable throwable&#41; &#123;
            StringWriter sw = new StringWriter&#40;&#41;;
            throwable.printStackTrace&#40;new PrintWriter&#40;sw, true&#41;&#41;;
    
            return sw.toString&#40;&#41;;
        &#125;
    
        private static Context createContext&#40;Context rootCtx, Name name&#41;
                throws NamingException &#123;
            Context subctx = rootCtx;
    
            for &#40;int n = 0; n < name.size&#40;&#41;; n++&#41;&#123;
                String atom = name.get&#40;n&#41;;
                try &#123;
                    Object obj = subctx.lookup&#40;atom&#41;;
                    subctx = &#40;Context&#41; obj;
                &#125; catch &#40;NamingException e&#41; &#123;
                    // No binding exists, create a subcontext
                    subctx = subctx.createSubcontext&#40;atom&#41;;
                &#125;
            &#125;
            return subctx;
        &#125;
    
        private void rebind&#40;&#41; throws Exception &#123;
            InitialContext rootCtx = new InitialContext&#40;&#41;;
    
            // Get the parent context into which we are to bind
            Name fullName = rootCtx.getNameParser&#40;""&#41;.parse&#40;jndiName&#41;;
    
            Name parentName = fullName;
    
            if &#40;fullName.size&#40;&#41; > 1&#41;&#123;
                parentName = fullName.getPrefix&#40;fullName.size&#40;&#41; - 1&#41;;
            &#125; else &#123;
                parentName = new CompositeName&#40;&#41;;
            &#125;
    
            Context parentCtx = createContext&#40;rootCtx, parentName&#41;;
            Name atomName = fullName.getSuffix&#40;fullName.size&#40;&#41; - 1&#41;;
            String atom = atomName.get&#40;0&#41;;
    
    //        Scheduler scheduler = schedulerFactory.getScheduler&#40;&#41;;
    
            NonSerializableFactory.rebind&#40;parentCtx, atom, context&#41;;
        &#125;
    
        private void unbind&#40;String jndiName&#41; throws NamingException &#123;
            Context rootCtx = new InitialContext&#40;&#41;;
    
            Name fullName = rootCtx.getNameParser&#40;""&#41;.parse&#40;jndiName&#41;;
            Name atomName = fullName.getSuffix&#40;fullName.size&#40;&#41; - 1&#41;;
            String atom = atomName.get&#40;0&#41;;
    
            rootCtx.unbind&#40;jndiName&#41;;
            NonSerializableFactory.unbind&#40;atom&#41;;
        &#125;
    
    &#125;
    // deployed the class within a jar into the jboss lib folder...

    and a spring-service.xml into the deploy folder, firing up the the service into the Jboss....

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <server>
      <classpath codebase="." archives="a-framework.jar"/>
      <mbean code="no.aftenposten.framework.spring.SpringService"
          name="user&#58;service=SpringService,name=SpringService">
        <attribute name="JndiName">Spring</attribute>
        <attribute name="Properties">
          spring.config=/jboss-3.2.2/server/default/deploy/spring.xml  
        </attribute>
      </mbean>
    </server>
    This enables me through this static method from any ejb to access the Spring application context within the container...

    Code:
        public static Object getBean&#40;String name&#41; throws NamingException, ComponentNotAvailableException &#123;
            //Initializing the spring configuration
            InitialContext jndiContext = new InitialContext&#40;&#41;;
            ApplicationContext context;
            if&#40;&#40;context =  &#40;ApplicationContext&#41; jndiContext.lookup&#40;"Spring"&#41;&#41; != null&#41;&#123;
                return context.getBean&#40;name&#41;;
            &#125; else &#123;
                throw new ComponentNotAvailableException&#40;"Could get Spring-bean-"+name+"," +
                        " due to missing BeanFactory &#40;jndi-Spring&#41;"&#41;;
            &#125;
        &#125;
    From my ejb, - the only code I need to access a Spring configured bean is:
    Code:
            HibernateDAO sf = &#40;HibernateDAO&#41; SpringBeanFactory.getBean&#40;"DAOImplementation"&#41;;
            sf.create&#40;bean&#41;;
    What about this way of implementing the Spring into ejb container. Have I overlooked something. I haven't found any standard Spring classes helping my to achieve the same solution, - which I would have preferred. Or should I solve it another way??


    Geir

  • #2
    See if this post helps any.
    http://forum.springframework.org/showthread.php?t=11492
    By using SingletonContext... all your beans should have access to the same Spring container.
    Last edited by robyn; May 19th, 2006, 06:17 AM.

    Comment


    • #3
      The solution i was looking for!... for another problem

      Hey,

      Thx for the code I was just about to implement the same thing to get a better beanFactory deployment on the JBoss server. The only difference is that my problem is another.

      I already use the provided AbstractEjb methods from spring but i find a problem in the interaction with the EJB.

      BeanFactoryLocator holds a counter that is incremented everytime someone requests a SingletonFactory. Whenever someone is interested in releasing its hold he can call the singleton method release() which in time, when the counter gets to 0 destroys the bean context forcing someone accesing the factory again to recreate the Bean Factory.

      The above exposed (which i find perfect for some situations) is a real drawback when working with EJB in JBoss due to the fact that JBoss destroys and recreates the EJB (counter-- 0 destroy context, next access = create bean factory) everytime the EJB throws an unexpected runtime exception.

      In this scenary i need another anchor to enforce the lifecicle i want for the spring context (full application container life, not ejb, that is the reason it is singleton) and the MBean deployment descriptor is just the perfect place for it .

      Comment

      Working...
      X