1 2 Previous Next 15 Replies Latest reply on Jan 27, 2003 7:30 PM by Gwellyn Daandels

    Running PetStore 1.3 on JBoss 3.0

    Elmar Henne Newbie

      To learn more about EJB and JBoss I decided to try to run Petstore on JBoss with Oracle as database. As it turned out this is not an easy undertaking as Petstore 1.3 uses some features which are not yet available in JBoss 3.0 (e.g. unknown foreign keys, deployment descriptors for submodules on ear-level). But solving all those problems resulted in a lot of experience and that was just what I wanted to get out this experiment.

      In this topic I will try to share my results in small steps:

      I am using Wnidows NT 4.0, PetStore 1_3_01, JBoss 3.0.2 and Ant 1.5.1.

      1) Building PetStore

      PetStore consists of 4 applications:

      petstore.ear
      petstoreadmin.ear
      opc.ear
      supplier.ear


      To build all of them run <petstore-home>\src\build.bat but for starting it is much better to concentrate on the store core which is in petstore.ear. This can be build with <petstore-home>\src\apps\petstore\src\build.bat. The result will be created in <petstore-home>\src\apps\petstorebuild\petstore.ear and it can now be deployed to JBoss by copying it into <jboss-home>\server\default\deploy.

      2) Relationship names

      This will generate the jboss error: ejb-relation-name must be unique in ejb-jar.xml file

      Because petstore.ear (open it with WinZip) contains a lot of submodules (components) which all have ejb-jar.xml files it is not clear from the error message which one must be changed. But by looking at the JBoss logfile <jboss-home>\server\default\log\server.log you can see that the last opened module is petstore.ear-contents/customer-ejb.jar.
      The corresponding source file is <petstore-home>\src\components\customer\src\ejb-jar.xml and there we find several empty relationship names "<ejb-relation-name></ejb-relation-name>". We must give them unique names, e.g. "<ejb-relation-name>RelCustomerEJBAccountEJB</ejb-relation-name>".

      Rebuilding petstore and deploying it will now end up in a first successful deployment. You can now already access the petstore start page on http://localhost:8080/petstore/

      But there are several new errors on the log and you cannot yet enter the store. I will talk about this in my next post.

        • 1. 3) Defining the datasource
          Elmar Henne Newbie

          3) Defining the datasource

          Petstore uses the files sun-j2ee-ri.xml for defining the vendor (sun) specific deployment information. For JBoss we have to use jboss.xml and jboss-web.xml instead. Luckily we do not have to convert all those information because much of it can be left to jboss default mechanism. Let us start with the datasource:

          The datasource jdbc/CatalogDB is used in the catalog component and the web client. For CatalogEJB we have to add the file <petstore-home>\src\components\catalog\src\jboss.xml:

          <?xml version='1.0'?>

          <enterprise-beans>

          <ejb-name>CatalogEJB</ejb-name>
          <resource-ref>
          <res-ref-name>jdbc/CatalogDB</res-ref-name>
          <res-type>javax.sql.DataSource</res-type>
          <jndi-name>java:/OracleDS</jndi-name>
          </resource-ref>

          </enterprise-beans>


          To include it in the build process we have to change src\components\catalog\src\build.xml:
          Add a line for jboss.xml in the target "ejbjar":


          ...


          ....


          For the web client we need the file src\apps\petstore\src\docroot\WEB-INF\jboss-web.xml:

          <?xml version='1.0'?>
          <jboss-web>
          <resource-ref>
          <res-ref-name>jdbc/CatalogDB</res-ref-name>
          <res-type>javax.sql.DataSource</res-type>
          <jndi-name>java:/OracleDS</jndi-name>
          </resource-ref>
          </jboss-web>

          For this file we do not need to change build.xml because it uses already all files from the WEB-INF directory.

          When you look at sun-j2ee-ri.xml you will notice that the datasources are defined at the ear level, together with a <module-name> tag. This is not possible in jboss, the jboss.xml and jboss-web.xml files must be at the same level as the corresponding ejb-jar.xml and web.xml files. This will create some difficulties when we will later deploy the other applications.

          Now we have mapped the datasource references from ejb-jar.xml and web.xml to the global jndi name java:/OracleDS. The next post will connect Oracle with this name.

          • 2. 4) Setting up Oracle
            Elmar Henne Newbie

            4) Setting up Oracle

            Copy the file <jboss-home>\docs\examples\jca\oracle-service.xml to the deployment directory and change the entry "ConnectionURL" according to your Oracle server location.

            Uncomment the line
            OracleDbRealm

            and copy <application-policy name = "OracleDbRealm">... to <jboss-home>\server\default\conf\login-config.xml. There you have to specify the user and password you want to use for Oracle access.

            In file <jboss-home>\server\default\conf\standardjbosscmp-jdbc.xml change the first lines to:

            java:/OracleDS
            <datasource-mapping>Oracle8</datasource-mapping>
            true

            This makes java:/OracleDS the default datasource for CMP and the debug flag will output the executed SQL statements to server.log.

            Include ".;%ORACLE_HOME%\jdbc\lib\nls_charset12.zip;%ORACLE_HOME%\jdbc\lib\classes12.zip" in your CLASSPATH environment variable to give jboss access to the Oracle JDBC driver. If you change this in your system environment you have to reopen your DOS shell for the jboss server to make it available (use the command "set classpath" to control the settings).

            With these changes running Petstore should now make the first database accesses. In server.log you can see the SQL statements to create entries in the table USEREJB.

            In the next post I will take care of the primary key problem.

            • 3. 5. Adding primary keys
              Elmar Henne Newbie

              5. Adding primary keys

              "unknown primary keys" is a new feature of CMP 2.0 which is not implemented in Jboss 3.0, it is available in 3.2beta (see topic "Unknown primary key class" http://www.jboss.org/modules/bb/index.html?module=bb&op=viewtopic&t=forums/ I decided to stay with 3.0.2 and for learning it might be a good idea to make some changes to petstore?

              To add explicit primary keys we have to define them and add code for producing unique values. I will show here the changes for AddressEJB (files \src\components\address\src\...\*.java)

              In class AddressEJB we have to add:

              // counter for primary key
              static private int idCounter = 0;

              // primary key field
              public abstract Integer getId();
              public abstract void setId(Integer id);


              In both ejbCreate methods we have to set a value for the new id field:

              setId (new Integer (++idCounter));
              // test output to console
              System.out.println ("AddressEJB.ejbCreate " + idCounter);


              In findByPrimaryKey in interface AddressLocalHome we have to change the type of parameter "key" to Integer.

              public AddressLocal findByPrimaryKey(Integer key) throws FinderException;

              These changes must be also applied to ContactInfoEJB, CreditCardEJB, ProfileEJB and AccountEJB (the last two files are in component customer).


              The deployment descriptor for all those classes are in file \src\components\customer\src\ejb-jar.xml.

              There we have to change the primary key class:

              <prim-key-class>java.lang.Integer</prim-key-class>


              And to add the new field:

              <cmp-field>
              Address primary key
              <field-name>id</field-name>
              </cmp-field>
              <primkey-field>id</primkey-field>


              This must be done for AddressEJB, ContactInfoEJB, CreditCardEJB, ProfileEJB and AccountEJB.

              You should also change the parameter type for the findByPrimaryKey methods in the assembly-descriptor, but this seems not to be really necessary.

              The above method of producing primary key values is in general not a very good idea, but it does work for petstore as the keys are only generated once in the populate method. Normally you would need a persistent counter, e.g. Oracle's sequence numbers. I have done this by developing a new session bean and will show it perhaps later.

              Now you should be able to populate and enter the store. But with Oracle you will get some SQL errors (see the log file) and I will talk about them next week.

              • 4. Re: Running PetStore 1.3 on JBoss 3.0
                Elmar Henne Newbie

                5. Adding primary keys

                "unknown primary keys" is a new feature of CMP 2.0 which is not implemented in Jboss 3.0, it is available in 3.2beta (see topic "Unknown primary key class" http://www.jboss.org/modules/bb/index.html?module=bb&op=viewtopic&t=forums/ I decided to stay with 3.0.2 and for learning it might be a good idea to make some changes to petstore?

                To add explicit primary keys we have to define them and add code for producing unique values. I will show here the changes for AddressEJB (files \src\components\address\src\...\*.java)

                In class AddressEJB we have to add:

                // counter for primary key
                static private int idCounter = 0;

                // primary key field
                public abstract Integer getId();
                public abstract void setId(Integer id);


                In both ejbCreate methods we have to set a value for the new id field:

                setId (new Integer (++idCounter));
                // test output to console
                System.out.println ("AddressEJB.ejbCreate " + idCounter);


                In findByPrimaryKey in interface AddressLocalHome we have to change the type of parameter "key" to Integer.

                public AddressLocal findByPrimaryKey(Integer key) throws FinderException;

                These changes must be also applied to ContactInfoEJB, CreditCardEJB, ProfileEJB and AccountEJB (the last two files are in component customer).


                The deployment descriptor for all those classes are in file \src\components\customer\src\ejb-jar.xml.

                There we have to change the primary key class:

                <prim-key-class>java.lang.Integer</prim-key-class>


                And to add the new field:

                <cmp-field>
                Address primary key
                <field-name>id</field-name>
                </cmp-field>
                <primkey-field>id</primkey-field>


                This must be done for AddressEJB, ContactInfoEJB, CreditCardEJB, ProfileEJB and AccountEJB.

                You should also change the parameter type for the findByPrimaryKey methods in the assembly-descriptor, but this seems not to be really necessary.

                The above method of producing primary key values is in general not a very good idea, but it does work for petstore as the keys are only generated once in the populate method. Normally you would need a persistent counter, e.g. Oracle's sequence numbers. I have done this by developing a new session bean and will show it perhaps later.

                Now you should be able to populate and enter the store. But with Oracle you will get some SQL errors (see the log file) and I will talk about them next week.

                • 5. Re: 4) Setting up Oracle
                  Lionel Pieniazek Newbie

                  All made all the changes that you said. But when I deploy the file petstore.ear to the JBoss server I get some errors:

                  2002-12-09 13:45:01,394 WARN [org.jboss.system.ServiceController] Problem starting service jboss.j2ee:jndiName=local/ContactInfoEJB,service=EJB
                  org.jboss.deployment.DeploymentException: Atleast one role of a foreign-key mapped relationship must have key fields: ejb-relation-name=RelAccountEJBCredicCardEJB
                  ---
                  2002-12-09 13:45:01,474 WARN [org.jboss.system.ServiceController] Problem starting service jboss.j2ee:jndiName=local/AddressEJB,service=EJB
                  org.jboss.deployment.DeploymentException: Atleast one role of a foreign-key mapped relationship must have key fields: ejb-relation-name=RelContactInfoEJBAddressEJB
                  ---
                  2002-12-09 13:45:02,255 WARN [org.jboss.system.ServiceController] Problem starting service jboss.j2ee:jndiName=local/CounterEJB,service=EJB
                  org.jboss.deployment.DeploymentException: Error while fixing table name; - nested throwable: (org.jboss.util.NestedSQLException: Could not create connection; - nested throwable: (java.sql.SQLException: ORA-01017: invalid username/password; logon denied
                  ); - nested throwable: (org.jboss.resource.ResourceException: Could not create connection; - nested throwable: (java.sql.SQLException: ORA-01017: invalid username/password; logon denied
                  )))

                  What is wrong?

                  I have to setup a spcial user in the database? What about the relationships?

                  Thanks

                  • 6. Re: 4) Setting up Oracle
                    Elmar Henne Newbie

                    You have to define the primary keys for AddressEJB, ContactInfoEJB, CreditCardEJB, ProfileEJB and AccountEJB in file \src\components\customer\src\ejb-jar.xml as described in 5. Adding primary keys.

                    The Oarcle user is defined in &lt;jboss-home&gt;\server\default\conf\login-config.xml:

                    &lt;application-policy name = "OracleDbRealm"&gt;
                    &lt;authentication&gt;
                    &lt;login-module code = "org.jboss.resource.security.ConfiguredIdentityLoginModule" flag = "required"&gt;
                    &lt;module-option name = "principal"&gt;PetStore&lt;/module-option&gt;
                    &lt;module-option name = "userName"&gt;PetStore&lt;/module-option&gt;
                    &lt;module-option name = "password"&gt;PetStore&lt;/module-option&gt;
                    &lt;module-option name = "managedConnectionFactoryName"&gt;jboss.jca:service=LocalTxCM,name=OracleDS&lt;/module-option&gt;
                    &lt;/login-module&gt;
                    &lt;/authentication&gt;
                    &lt;/application-policy&gt;

                    Here I have used "PetStore" as Oracle user name, you have either to create it in Oracle or to replace the above with an existing oracle user.

                    • 7. Re: Running PetStore 1.3 on JBoss 3.0
                      Elmar Henne Newbie

                      6. Decimal point

                      I am running Oracle server with German as language setting, which means that oracle expects "," as decimal point in numbers, but petstore uses "." in its sample data. I solved this by inserting an ALTER SESSION command in method populate in src\apps\petstore\...\tools\populate\PopulateServlet.java:

                      ...
                      catalogPopulator.createTables(connection);
                      try {
                      // set "." as decimal point for Oracle
                      PreparedStatement stmt = connection.prepareStatement ("alter session set nls_numeric_characters = '.,'");
                      stmt.executeQuery();

                      ...


                      7. Join clauses

                      When entering Petstore you will get Oracle errors from com.sun.j2ee.blueprints.catalog.dao.CatalogDAOImpl.getCategories. This is because it uses a Cloudscape specific form of JOIN syntax in its SELECT statements, e.g.:


                      ps = c.prepareStatement("select name, descn "
                      + "from (category a join "
                      + "category_details b on "
                      + "a.catid=b.catid) "
                      + "where locale = ? "
                      + "and a.catid = ?",


                      we have to change this into its normal SQL syntax:

                      ps = c.prepareStatement("select name, descn "
                      + "from category a, "
                      + "category_details b where "
                      + "a.catid=b.catid "
                      + "and locale = ? "
                      + "and a.catid = ?",


                      There are 7 select statements in the file src\components\catalog\...\catalog\dao\CatalogDAOImpl.java which must be changed accordingly, search for "join" to find all of them. I think it would be much nicer if such database specific strings would not be hard coded but come from the deployment environment.


                      8. JDBC problems with CHAR fields

                      Now there should be no more Oracle errors, but you will still not see catalog listings in the Petstore application. This comes from an Oracle specific problem, which I would actually call a bug in the jdbc driver:

                      The above select statements use "?" parameters for CHAR(10) fields. For Oracle the passed values must be filled with blanks to their upper limit. To do this I defined a small helper method:


                      // Fill string with blanks to specified length
                      private static String strFill (String s, int len) {
                      int i;
                      int l = s.length();
                      if (l > len) {
                      return s.substring (1, len);
                      }
                      else {
                      StringBuffer sb = new StringBuffer (s);
                      for (i = l; i < len; i++) {
                      sb.append (' ');
                      }
                      return sb.toString() ;
                      }
                      }


                      This must be used in the setString(...) calls, e.g.:

                      ps.setString(1, strFill (l.toString(), 10) );
                      ps.setString(2, strFill (categoryID, 10) );


                      Now the store front of Petstore should be working, you should be able to place orders, create an account, etc.

                      The next step is to run the administrator client application. For this we have to deal with the message queues and to resolve some naming conflicts. I will discuss this under a new topic "PetStore 1.3 Admin Client"

                      • 8. Re: Running PetStore 1.3 on JBoss 3.0
                        Elmar Henne Newbie

                        Before going on with the Admin interface I switched to the latest version 1.3.1_01 of Pet Store. This required some changes to the above steps:


                        3. Defining the datasource

                        In src\apps\petstore\src\docroot\WEB-INF\jboss_web.xml we need an additional entry:

                        <resource-ref>
                        <res-ref-name>url/CatalogDAOSQLURL</res-ref-name>
                        <res-type>java.net.URL</res-type>
                        <res-url>http://localhost:8080/petstore/CatalogDAOSQL.xml</res-url>
                        </resource-ref>


                        Be careful to use the tag <res-url> as this is not documented in jboss-web.dtd!


                        5. Adding primary keys

                        AddressEJB and ContactInfoEJB have now 3 create methods which must be changed.


                        7. Join clauses

                        This is no longer necessary, the SQL is now defined in CatalogDAOSQL.xml and there are already variants for Oracle. To enable them you have only to change the following entry in file src\apps\petstore\src\docroot\WEB-INF\web.xml:

                        <env-entry>
                        <env-entry-name>param/CatalogDAODatabase</env-entry-name>
                        <env-entry-value>oracle</env-entry-value>
                        <env-entry-type>java.lang.String</env-entry-type>
                        </env-entry>



                        8. JDBC problems with CHAR fields

                        This has now to be solved by replacing the SQL parameters before calling the JDBC driver in GenericCatalogDAO.buildSQLStatement(...):

                        // Replace parameters directly (Oracle problems with CHAR() type)
                        if (parameterValues != null) {
                        int k = 0;
                        for (int i = 0; i < buffer.length() && k < parameterValues.length; i++) {
                        if (buffer.charAt(i) == '?') {
                        buffer.replace(i, i + 1, "'" + parameterValues[k] + "'");
                        i += parameterValues[k++].length() + 1;
                        }
                        }
                        }
                        if (TRACE) {
                        System.out.print("SQL: " + buffer);
                        }

                        PreparedStatement statement = connection.prepareStatement(buffer.toString(),
                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_READ_ONLY);
                        /*
                        if (parameterValues != null) {
                        for (int i = 0; i < parameterValues.length; i++) {
                        statement.setString(i + 1, parameterValues[ i]);
                        }
                        }
                        */



                        9. Using Pet Store core only

                        To use only petstore.ear we have to make a small change in src\apps\petstore\src\docroot\populating.jsp. We replace the reference to "/supplier/populating" by "/petstore/main.screen" to skip the population of the supplier application. This must be changed back when we will later use supplier.ear:

                        <%--
                        <META HTTP-EQUIV=REFRESH CONTENT="0; URL=Populate?success_page=//supplier/populating.jsp%3fforcefully%3d<%=request.getParameter("forcefully") %>&forcefully=<%=request.getParameter("forcefully") %>"
                        --%>
                        <META HTTP-EQUIV=REFRESH CONTENT="0; URL=Populate?success_page=//petstore/main.screen&forcefully=<%=request.getParameter("forcefully") %>"



                        With all those changes you should now have running the store front of Pet Store 1.3.1_01.

                        • 9. Re: Running PetStore 1.3 on JBoss 3.0
                          Elmar Henne Newbie

                          10. More Info for CatalogEJB

                          There have been still some things missing, which you would notice when trying to actually buy something in Pet Store.

                          The file from step 3) is erroneous (CatalogEJB is a session bean!) and incomplete (entry for CatalogDAOSQLURL is missing). It should now look as follows:


                          <enterprise-beans>
                          src\components\catalog\src\jboss.xml
                          <ejb-name>CatalogEJB</ejb-name>
                          <resource-ref>
                          <res-ref-name>jdbc/CatalogDB</res-ref-name>
                          <res-type>javax.sql.DataSource</res-type>
                          <jndi-name>java:/OracleDS</jndi-name>
                          </resource-ref>
                          <resource-ref>
                          <res-ref-name>url/CatalogDAOSQLURL</res-ref-name>
                          <res-type>java.net.URL</res-type>
                          <res-url>http://localhost:8080/petstore/CatalogDAOSQL.xml</res-url>
                          </resource-ref>

                          </enterprise-beans>


                          The entry CatalogDAODatabase in src\components\catalog\src\ejb-jar.xml must be changed to "oracle":

                          <env-entry-value>oracle</env-entry-value>
                          <!--env-entry-value>cloudscape</env-entry-value-->



                          11. Message Queues

                          For AsyncSenderEJB we need a new file src\components\asyncsender\src\jboss.xml:


                          <enterprise-beans>

                          <ejb-name>AsyncSenderEJB</ejb-name>
                          <local-jndi-name>ejb/local/admin/asyncsender/AsyncSender</local-jndi-name>
                          <!--Queues for petstore.ear -->
                          <resource-ref>
                          <res-ref-name>jms/QueueConnectionFactory</res-ref-name>
                          <!--jndi-name>jms/petstore/QueueConnectionFactory</jndi-name-->
                          <jndi-name>ConnectionFactory</jndi-name>
                          </resource-ref>
                          <resource-env-ref>
                          <resource-env-ref-name>jms/AsyncSenderQueue</resource-env-ref-name>
                          <!--jndi-name>jms/opc/OrderQueue</jndi-name-->
                          <jndi-name>queue/A</jndi-name>
                          </resource-env-ref>

                          </enterprise-beans>


                          As you can see I have used one of the standard jboss queues (queue/A), but you could also define your own queue in jbossmq-destinations-service.xml. This queue will be read with opc.ear. To include jboss.xml in the ant build you have to add a copy statement in build.xml, you should now know how to do this.

                          • 10. Re: Running PetStore 1.3 on JBoss 3.0
                            Mark Ellis Newbie

                            Hi EHenne

                            As it twas the Christmas holidays I thought I would investigate JBoss and found myself here!

                            I've got the petstore to populate using JBOSS 3.0.4 and Postgres as a database - thanks to your instructions.

                            I liked to be able to get the rest of the demo working starting with the supplier - any clues!

                            Regards
                            Mark

                            • 11. Re: Running PetStore 1.3 on JBoss 3.0
                              Elmar Henne Newbie

                              Hi Mark,

                              I have now started a new topic "PetStore 1.3.1 Admin Client" http://www.jboss.org/modules/bb/index.html?module=bb&op=viewtopic&t=forums/ where I will explain what to do to let the rest of PetStore run.

                              Sorry for the late response but I have spent most part of my holidays without Jboss and my first reply got lost in the tmporary new forum structure which has been in place between 9th and 14th of January.

                              Elmar

                              • 12. Re: Running PetStore 1.3 on JBoss 3.0
                                Mark Ellis Newbie

                                Hi Elmar

                                I'll give the rest of the instructions a go.

                                Belated Happy New Year,

                                Regards
                                Mark

                                • 13. Re: Running PetStore 1.3 on JBoss 3.0
                                  David Zhao Newbie

                                  I made the changes as you said. But when I deploy the petstore.ear, I got following errors:
                                  ..
                                  jndiName=local/CustomerEJB,service=EJB
                                  org.jboss.deployment.DeploymentException: primkey-field must be the same type as prim-key-class at org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData.(J
                                  DBCCMPFieldMetaData.java:130)
                                  at org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData.(JDB
                                  CEntityMetaData.java:277)
                                  ........

                                  Could you help me with this?

                                  Thanks!

                                  • 14. Re: Running PetStore 1.3 on JBoss 3.0
                                    Elmar Henne Newbie

                                    This error occurs when the primary key class specified in the deploymentdescriptor
                                    [pre] <prim-key-class>java.lang.String</prim-key-class>
                                    [/pre]does not match the type used for the primary key field in the java source of the entity bean.

                                    Your error message refers to CustomerEJB, there we do not have to change anything, it has already an explicit primary key userId of type String.

                                    Please check your \src\components\customer\src\ejb-jar.xml and CustomerEJB.java

                                    1 2 Previous Next