Announcement Announcement Module
Collapse
No announcement yet.
HSQL server wrapped into a Spring bean Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • HSQL server wrapped into a Spring bean

    Hi,

    I'm a beginner with Spring so I'm having my first problems with it :shock:

    I'm developing a Web application to manage some content through a web interface. I'm using :
    - HSQLDB as database (In-Process mode, embedded into my webapp)
    - Hibernate as O/Rmapping
    - Spring for business code
    - Apache Cocoon for presentation layer
    - AndroMDA to generate Java, Hibernate and Spring files from my UML model

    What makes my application somwhat original is that I don't want to use any JNDI datasource or external database to persist my data. HSQLDB is embedded in my webapp and it starts with my webapp. Here is the extract of web.xml which is responsible for application context loading :
    Code:
    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/classes/beanRefFactory.xml</param-value>
        </context-param>
        <listener>
            <listener-class>
                org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>
        <filter>
            <filter-name>
                OpenSessionInViewFilter
            </filter-name>
            <filter-class>
                org.springframework.orm.hibernate.support.OpenSessionInViewFilter
            </filter-class>
            <init-param>
                <param-name>singleSession</param-name>
                <param-value>false</param-value>
            </init-param>
        </filter>
    beanRefFactory.xml is a file which is generated by AndroMDA with the following content :
    Code:
    <beans>
    
    		<bean id="hsqlServer" 
                    class="ca.polymtl.larim.schaman.persistence.HsqlServer"
                    init-method="start" destroy-method="stop">
                </bean>
    
        <bean id="beanRefFactory"
             class="org.springframework.context.support.ClassPathXmlApplicationContext">
            <constructor-arg>
               <list>
                    <value>applicationContext.xml</value>
                    <value>applicationContext-dataSource.xml</value>
               </list>
            </constructor-arg>
        </bean>
    
    </beans>
    This way the HSQL server is wrapped in a Spring bean and started before application context loading...
    Then when I want to access my service beans inside my application I use another class generated by AndroMDA, called ServiceLocator :
    Code:
    package ca.polymtl.larim.schaman;
    
    /**
     * Locates and provides all available application services.
     */
    public class ServiceLocator
    &#123;
        /**
         * The default application context location.
         */
        private final String DEFAULT_BEAN_REFERENCE_LOCATION = "beanRefFactory.xml";
    
        /**
         * The bean factory reference location.
         */
        private String beanFactoryReferenceLocation;
    
        private ServiceLocator&#40;&#41;
        &#123;
            // shouldn't be instantiated
        &#125;
    
        /**
         * The shared instance of this ServiceLocator.
         */
        private final static ServiceLocator instance = new ServiceLocator&#40;&#41;;
    
        /**
         * Gets the shared instance of this Class
         *
         * @return the shared service locator instance.
         */
        public static final ServiceLocator instance&#40;&#41;
        &#123;
            return instance;
        &#125;
    
        /**
         * Initializes the Spring application context from
         * the given <code>beanFactoryReferenceLocation</code>.  If <code>null</code>
         * is specified for the <code>beanFactoryReferenceLocation</code>
         * then the default application context will be used.
         *
         * @param contextLocation the location of the context
         */
        public synchronized void init&#40;String beanFactoryReferenceLocation&#41;
        &#123;
            this.beanFactoryReferenceLocation = beanFactoryReferenceLocation;
            this.beanFactoryReference = null;
        &#125;
    
        /**
         * The bean factory reference instance.
         */
        private org.springframework.beans.factory.access.BeanFactoryReference beanFactoryReference;
    
        /**
         * Gets the Spring ApplicationContext.
         */
        protected synchronized org.springframework.context.ApplicationContext getContext&#40;&#41;
        &#123;
            if &#40;this.beanFactoryReference == null&#41;
            &#123;
                if &#40;this.beanFactoryReferenceLocation == null&#41;
                &#123;
                    this.beanFactoryReferenceLocation = DEFAULT_BEAN_REFERENCE_LOCATION;
                &#125;
                org.springframework.beans.factory.access.BeanFactoryLocator beanFactoryLocator =
                    org.springframework.context.access.ContextSingletonBeanFactoryLocator.getInstance&#40;
                        this.beanFactoryReferenceLocation&#41;;
                this.beanFactoryReference = beanFactoryLocator.useBeanFactory&#40;"beanRefFactory"&#41;;
            &#125;
            return &#40;org.springframework.context.ApplicationContext&#41;this.beanFactoryReference.getFactory&#40;&#41;;
        &#125;
        
        /**
         * Shuts down the ServiceLocator and releases any used resources.
         */
        public synchronized void shutdown&#40;&#41; 
        &#123; 
            if &#40;this.beanFactoryReference != null&#41; 
            &#123; 
                this.beanFactoryReference.release&#40;&#41;; 
                this.beanFactoryReference = null;
            &#125; 
        &#125; 
    
        /**
         * Gets an instance of &#123;@link ca.polymtl.larim.schaman.SecurityManagement&#125;
         */
        public final ca.polymtl.larim.schaman.SecurityManagement getSecurityManagement&#40;&#41;
        &#123;
            return &#40;ca.polymtl.larim.schaman.SecurityManagement&#41;
                getContext&#40;&#41;.getBean&#40;"securityManagement"&#41;;
        &#125;
    
        /**
         * Gets an instance of &#123;@link ca.polymtl.larim.schaman.UsersManagement&#125;
         */
        public final ca.polymtl.larim.schaman.UsersManagement getUsersManagement&#40;&#41;
        &#123;
            return &#40;ca.polymtl.larim.schaman.UsersManagement&#41;
                getContext&#40;&#41;.getBean&#40;"usersManagement"&#41;;
        &#125;
    
        /**
         * Gets an instance of &#123;@link ca.polymtl.larim.schaman.RolesManagement&#125;
         */
        public final ca.polymtl.larim.schaman.RolesManagement getRolesManagement&#40;&#41;
        &#123;
            return &#40;ca.polymtl.larim.schaman.RolesManagement&#41;
                getContext&#40;&#41;.getBean&#40;"rolesManagement"&#41;;
        &#125;
    
        /**
         * Gets an instance of &#123;@link ca.polymtl.larim.schaman.ModulesManagement&#125;
         */
        public final ca.polymtl.larim.schaman.ModulesManagement getModulesManagement&#40;&#41;
        &#123;
            return &#40;ca.polymtl.larim.schaman.ModulesManagement&#41;
                getContext&#40;&#41;.getBean&#40;"modulesManagement"&#41;;
        &#125;
    
    &#125;
    And then everything goes wrong because when I call :
    Code:
    users = ServiceLocator.instance&#40;&#41;.getUsersManagement&#40;&#41;;
    The following exception is thrown and I don't understand it :
    org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'hsqlServer' defined in URL [file:/C:/dev/pfe/schaman/target/webapp/WEB-INF/classes/beanRefFactory.xml]: Initialization of bean failed; nested exception is java.lang.ClassCastException: null
    I'm aware that my question is a bit long and complex because I integrate many tools and dependencies around spring. If you need more information, feel free to ask.

    Thank you very much in advance for your help.[/code]

  • #2
    What was the stacktrace for that NPE above?

    I was able to embed a hsqldb bean in a Spring RCP (i.e. Swing) application I worked on. But I don't have the code at hand. I'll let you know if I can dig it up.

    Comment


    • #3
      Looks like the difference between yours and mine is I don't have a bean to start/stop the Hsqlserver. All I did was to specify the basename for the data files directly in the jdbc url when configuring the data source bean, something like:
      Code:
        <bean id="data-source" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
          <property name="driverClassName">
            <value>org.hsqldb.jdbcDriver</value>
          </property>
          <property name="url">
            &#91;b&#93;<value>jdbc&#58;hsqldb&#58;file&#58;test/hsqldb/data</value>&#91;/b&#93;
          </property>
          <property name="username">
            <value>sa</value>
          </property>
          <property name="password">
            <value></value>
          </property>
        </bean>
      If you look at the hsqldb documentation, that's exactly the way they suggested.

      Comment


      • #4
        Yes but when you do that you access a HSQLDB server instance that is already started somewhere before you access it. That's why I need my HsqlServer class/bean to start the instance before accessing it. And once the server instance is started up, I can access it any datasource, BasicDatasource or others.
        But anyway I think I partially solved this issue for now : I don't use the ServiceLocator class. I access my beans directly through beanRefFactory using the fact that beanRefFactory is itself an application context :
        Code:
        applicationContext.getBean&#40;"beanRefFactory"&#41;.getBean&#40;"myBean"&#41;;
        And it seems to work like this so far. I guess the problem came from the fact that the first call to ServiceLocator trie to create the instance of the singleton and to initialize beanRefFactory application context, which tries to load hsqlServer and calls its init method (that starts the server instance) while it has already been called when the application context was loaded from web.xml processing when web application was loaded. And I guess that there is a problem when I try to have two instances of the same server running and listening on the same port, which causes some kind of NullPointerException somewhere.

        I'm trying to find a solution with the guys at AndroMDA, as ServiceLocator is a class of their own, but if the solution I found works, it's fine. I haven't come to test persistence I/O yet. I'll see then.

        But from your link to HSQLDB doc, I've just realized that it seems to be possible to access the database directly with JDBC without really starting a server instance before. I will study this solution to see if it works...

        Thanks for your help...

        Comment


        • #5
          Ok I just understood how it seems to work and why it is called In-process mode : it's because there is really no need to start a server instance in another thread. So now I just have to find the right relative URL and make a few test to see if it works... I'll get back to you with my test results...

          From your experience with this configuration, what should be the relative url path knowing that according to hsql documentation, relative path is resolved from path where JVM is started. When using tomcat for example what is this base path ?

          Comment


          • #6
            There is an implementation of an HSQL Server Bean that can be included in a Spring application context in the sandbox over at the Spring Modules project https://springmodules.dev.java.net/.

            This is an example of how to declare it in the context xml file:

            Code:
                 <bean id="dataBase" class="org.springmodules.db.hsqldb.ServerBean" singleton="true" lazy-init="false">
                     <property name="dataSource"><ref local="dataSource"/></property>
                     <property name="serverProperties">
                         <props>
                             <prop key="server.port">9101</prop>
                             <prop key="server.database.0">webapps/myapp/db/test</prop>
                             <prop key="server.dbname.0">test</prop>
                         </props>
                     </property>
                 </bean>
            It does open the databse as a server on the specified port.

            Here is a link to the code:

            https://springmodules.dev.java.net/s....1&view=markup

            Comment


            • #7
              Originally posted by sebastien
              Ok I just understood how it seems to work and why it is called In-process mode : it's because there is really no need to start a server instance in another thread. So now I just have to find the right relative URL and make a few test to see if it works... I'll get back to you with my test results...
              Exactly. In this In-process mode the server is actually started when the first connection is made, which in Spring is usally when the datasource bean is instantiated.

              Originally posted by sebastien
              From your experience with this configuration, what should be the relative url path knowing that according to hsql documentation, relative path is resolved from path where JVM is started. When using tomcat for example what is this base path ?
              You might want to externalize this into a property file, and actually hardcode the absolute path in there, because if you deploy your web app in a war (typically), you have to put the data files somewhere else anyway.

              Comment


              • #8
                Originally posted by manifoldronin
                You might want to externalize this into a property file, and actually hardcode the absolute path in there, because if you deploy your web app in a war (typically), you have to put the data files somewhere else anyway.
                Thank you very much for your help. In fact I prefer to deploy my application in expanded format and integrate the database inside the folder.
                But I'm intrigued because when my application is started and initialized, I have .log, .properties, .script and .lck file written in my db directory but no data file ! Yet, my data is stored somewhere because when my application is reloaded everything is still there.
                Any idea about this mystery ?

                Thx in advance.

                Comment


                • #9
                  Originally posted by sebastien
                  But I'm intrigued because when my application is started and initialized, I have .log, .properties, .script and .lck file written in my db directory but no data file ! Yet, my data is stored somewhere because when my application is reloaded everything is still there.
                  Any idea about this mystery ?
                  IIRC, by default all the data is saved in the *.script file, which is basically a bunch of insert statements that get executed everytime a database is reloaded. It'll become more obvious once you insert some more data into your database.

                  I suppose that's why hsqldb is sometimes criticized to be not so scalable.

                  Comment


                  • #10
                    Hi,
                    It is the first time I post a message in this forum, I am doing exactly the same thing as what are you doing.
                    I am using HSQL data base, and properties are setted in a property file, however I do not now what relative path to use
                    The generated war doesn't contain .script file, the script file is generated in TOMCAT_HOME instead.
                    I tried to put my script file in DB folder in my application folder, and add this folder to my war when it is generating (by maven), but still not works.
                    Does some one have an idea about how implementing this?
                    Thank you

                    Comment

                    Working...
                    X