You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

This article describes about how to develop a Struts1 web application for Geronimo. Besides Struts1 technology, you also can find some sample code about JPA and Security annotation.

Because of the JIRA, the sample is not available as a geronimo plugin at the written time.

This article won't serve as a tutorial of developing a Struts1 application. For more information about Struts1 development, refer to Struts1 web site.

This article is organized into the following sections.

Application overview

Assuming you have accumulated lot of archival data CDs from your computer, each of them includes rich of information you ever collected. The collection of the archived CDs is your valuable knowledge asset, so you want to manage them carefully and organizedly for future easy references. The DataCDInfo is an application to assist you to manage the information of your archival data CDs.

With this application, you can register a user, and then login to add records for your archived CDs. You can record detail information that is not suitable to label on CD surface, such as detailed list of data CD content, archival date, and CD size.

This application set some admin roles to be able to view overall recorded CDs and help retrieve user's password if there is a forgotten.

In a short summary, DataCDInfo is a simple CRUD(Create, Retrieve, Update and Delete) application, which adopts Struts1, JPA, JTA, and security annotation techniques.

Application contents

DataCDInfo uses the typical Java EE application structure: an EJB module, an Web module, and an EAR module.

The EJB module

The EJB module includes the major business logic of this application. It consists of JPA entity beans, a stateless session bean, a stateful session bean and some exception clasess.

  • Two JPA entity beans: DataCDBean and OwnerBean, represents Data CD records and Owner records respectively. The relation bewteen OwnerBean and DataCDBean is 1...*, one owner could have multiple Data CDs.
  • The DataCDInfoJTAImpl is a stateless session bean which implements the business logic of DataCDInfo application, including login, registration/unregistration of owner, and add/update/remove data CD records. DataCDInfoLocal and DataCDInfoRemote is the local and remote business interface respectively.
  • The DataCDInfoAdmin is a stateful session, in which there is an EXTENDED persistence context. By default, a container-managed persistence context is of type TRANSACTION. The EXTENDED persistence context can only be initiated within a scope of a stateful session bean.
  • The DataCDInfoAdmin defines two roles "superadmin" and "admin" with security annotation @RolesAllowed. In the code, role "superadmin" can access all of three methods, while role "admin" can only access "listOwners" method. Another way to define the access is via EJB deployment descriptor "ejb-jar.mxl". The definition in ejb-jar.xml overrides the one in code. As the definition of "ejb-jar.xml" below, the role "admin" also has access to method "listAllDataCDs" besides the method "listOwners" defined in the code.
    ejb-jar.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!--
        Licensed to the Apache Software Foundation (ASF) under one or more
        contributor license agreements.  See the NOTICE file distributed with
        this work for additional information regarding copyright ownership.
        The ASF licenses this file to You under the Apache License, Version 2.0
        (the "License"); you may not use this file except in compliance with
        the License.  You may obtain a copy of the License at
    
           http://www.apache.org/licenses/LICENSE-2.0
    
        Unless required by applicable law or agreed to in writing, software
        distributed under the License is distributed on an "AS IS" BASIS,
        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        See the License for the specific language governing permissions and
        limitations under the License.
    -->
    <ejb-jar version="3.0"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"> 
        <display-name>DataCDInfo Enterprise Bean Definitions</display-name>
        
        <enterprise-beans>
    	<session>
    		<ejb-name>ejb/DataCDInfoJTAImpl</ejb-name>
    		<business-local>org.apache.geronimo.samples.datacdinfo.core.DataCDInfoLocal</business-local>
    		<business-remote>org.apache.geronimo.samples.datacdinfo.core.DataCDInfoRemote</business-remote>
    		<ejb-class>org.apache.geronimo.samples.datacdinfo.core.DataCDInfoJTAImpl</ejb-class>
                    <!-- Stateful|Stateless -->
    		<session-type>Stateless</session-type>
                    <!-- Who manages transanction? Bean|Container -->
    		<transaction-type>Container</transaction-type>
    	</session>
    	<session>
    		<ejb-name>ejb/DataCDInfoAdmin</ejb-name>
    		<business-local>org.apache.geronimo.samples.datacdinfo.core.DataCDInfoAdminLocal</business-local>
    		<ejb-class>org.apache.geronimo.samples.datacdinfo.core.DataCDInfoAdmin</ejb-class>
                    <!-- Stateful|Stateless -->
    	        <session-type>Stateful</session-type>
                    <!-- Who manages transanction? Bean|Container -->
    		<transaction-type>Container</transaction-type>
    	</session>		
        </enterprise-beans>	
    
        <assembly-descriptor>
    	<method-permission>
    	    <role-name>superadmin</role-name>
    	    <method>
    		<ejb-name>ejb/DataCDInfoAdmin</ejb-name>
    		<method-name>*</method-name>
    	    </method>
    	</method-permission>
    		<!-- In code, role "admin" only has right to access listOwners method
    		but via this xml definition, the role could also access listAllDataCDs method -->
    	<method-permission>
    	    <role-name>admin</role-name>
    		<method>
    	 	    <ejb-name>ejb/DataCDInfoAdmin</ejb-name>
    		    <method-name>listAllDataCDs</method-name>					
    		</method>
    	</method-permission>
        </assembly-descriptor>     
    </ejb-jar>
    
  • A persistence unit is defined via META-INF/persistence.xml as shown below.
    persistence.xml
    <?xml version="1.0" encoding="UTF-8"?>
    
    <!--
    
        Licensed to the Apache Software Foundation (ASF) under one or more
    
        contributor license agreements.  See the NOTICE file distributed with
    
        this work for additional information regarding copyright ownership.
    
        The ASF licenses this file to You under the Apache License, Version 2.0
    
        (the "License"); you may not use this file except in compliance with
    
        the License.  You may obtain a copy of the License at
    
    
    
           http://www.apache.org/licenses/LICENSE-2.0
    
    
    
        Unless required by applicable law or agreed to in writing, software
    
        distributed under the License is distributed on an "AS IS" BASIS,
    
        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    
        See the License for the specific language governing permissions and
    
        limitations under the License.
    
    -->
    
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    
      <persistence-unit name="DataCDInfoUnit" transaction-type="JTA">
    
        <description>DataCDInfo Persistence Unit Definition</description>
    
        <jta-data-source>jdbc/DataCDInfoDS</jta-data-source>
    
        <non-jta-data-source>jdbc/NoTxDataCDInfoDS</non-jta-data-source>	
    
        <class>org.apache.geronimo.samples.datacdinfo.beans.OwnerBean</class>
    
        <class>org.apache.geronimo.samples.datacdinfo.beans.DataCDBean</class>
    
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
    
        <properties>      
    
          <property name="openjpa.Sequence" value="table(Table=OPENJPASEQ, Increment=1)"/>       
    
          <!--<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>-->
    
          <!--<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/>-->
    
          <property name="openjpa.Log" value="File=/tmp/org.apache.openjpa.log, DefaultLevel=WARN, Tool=INFO, Runtime=TRACE, SQL=TRACE"/>
    
        </properties>
    
      </persistence-unit>
    
    </persistence>
    
    

If the persistence context requires some non-transactional operations, such as table sequence generation, you need to define a non-jta-data-source as well. Otherwise, you will encounter an exception like "org.apache.openjpa.persistence.RollbackException: The transaction has been rolled back."

The EJB module maven project is layout as follows:

|-- pom.xml
`-- src
    `-- main
        |-- java
        |   `-- org
        |       `-- apache
        |           `-- geronimo
        |               `-- samples
        |                   `-- datacdinfo
        |                       |-- beans
        |                       |   |-- DataCDBean.java
        |                       |   `-- OwnerBean.java
        |                       |-- core
        |                       |   |-- DataCDInfoAdmin.java
        |                       |   |-- DataCDInfoAdminLocal.java
        |                       |   |-- DataCDInfoJTAImpl.java
        |                       |   |-- DataCDInfoLocal.java
        |                       |   `-- DataCDInfoRemote.java
        |                       `-- exceptions
        |                           |-- DuplicatedDataCDException.java
        |                           |-- IncorrectPasswordException.java
        |                           |-- InvalidOwnerException.java
        |                           `-- InvalidPasswordException.java
        `-- resources
            `-- META-INF
                |-- ejb-jar.xml
                |-- openejb-jar.xml
                `-- persistence.xml

The Web Module

|-- pom.xml
`-- src
    `-- main
        |-- java
        |   `-- org
        |       `-- apache
        |           `-- geronimo
        |               `-- samples
        |                   `-- datacdinfo
        |                       `-- web
        |                           |-- DataCDInfoAdminServlet.java
        |                           |-- ListOwnerServlet.java
        |                           `-- struts1
        |                               |-- DataCDActions.java
        |                               |-- DataCDForm.java
        |                               |-- DataCDInfoContextListener.java
        |                               |-- OwnerActions.java
        |                               `-- OwnerForm.java
        |-- resources
        |   |-- DataCDInfoResources.properties
        |   |-- DataCDInfoResources_en_US.properties
        |   |-- DataCDInfoResources_zh.properties.template
        |   `-- DataCDInfoResources_zh_CN.properties
        `-- webapp
            |-- META-INF
            |   |-- LICENSE
            |   |-- MANIFEST.MF
            |   `-- NOTICE
            |-- WEB-INF
            |   |-- geronimo-web.xml
            |   |-- struts-config.xml
            |   |-- validation.xml
            |   `-- web.xml
            |-- admin
            |   |-- adminhome.html
            |   |-- showCDs.jsp
            |   |-- showOwners.jsp
            |   `-- showPasswd.jsp
            |-- auth
            |   |-- logon.html
            |   `-- logonError.html
            |-- header.html
            |-- index.html
            `-- view
                `-- jsp
                    |-- AddCD.jsp
                    |-- ListCDs.jsp
                    |-- Logon.jsp
                    |-- Logout.jsp
                    |-- Register.jsp
                    |-- RemoveCD.jsp
                    `-- UpdateCD.jsp

The EAR module

|-- pom.xml
`-- src
    `-- main
        `-- resources
            |-- DataCDInfo_tables_derby.sql
            |-- DataCDInfo_tables_mysql.sql
            `-- META-INF
                |-- application.xml
                |-- geronimo-application-mysql.xml
                `-- geronimo-application.xml

Steps to

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements. See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership. The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License. You may obtain a copy of the License at
    
    http://www.apache.org/licenses/LICENSE-2.0
    
    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied. See the License for the
    specific language governing permissions and limitations
    under the License.
-->
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
	 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>employee</web-resource-name>
            <url-pattern>/employee/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>employee</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>manager</web-resource-name>
            <url-pattern>/manager/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>manager</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>TimeReportRealm</realm-name>
        <form-login-config>
            <form-login-page>/login/login.jsp</form-login-page>
            <form-error-page>/login/login_error.jsp</form-error-page>
        </form-login-config>
    </login-config>

    <security-role>
        <role-name>employee</role-name>
    </security-role>
    <security-role>
        <role-name>manager</role-name>
    </security-role>

    <servlet>
        <display-name>AddTimeRecordServlet</display-name>
        <servlet-name>AddTimeRecordServlet</servlet-name>
        <servlet-class>org.apache.geronimo.samples.timereport.web.AddTimeRecordServlet</servlet-class>
    </servlet>
    <servlet>
        <display-name>AddEmployeeServlet</display-name>
        <servlet-name>AddEmployeeServlet</servlet-name>
        <servlet-class>org.apache.geronimo.samples.timereport.web.AddEmployeeServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>AddTimeRecordServlet</servlet-name>
        <url-pattern>/employee/add_timerecord</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>AddEmployeeServlet</servlet-name>
        <url-pattern>/manager/add_employee</url-pattern>
    </servlet-mapping>

</web-app>

The Geronimo deployment plan ( plan.xml found after building the project at timereport/timereport-jetty/target/resources/META-INF/plan.xml) includes the Geronimo specific security configuration including the security realm configuration and the principal-role mapping relating the principals from the security realm to the application roles defined above in web.xml This project uses two roles, manager and employee. There is a business rule that every manager is an employee. This is enforced through the principal-role mapping: both the EmployeeGroup and ManagerGroup imply the app specific employee role.

plan.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at
    
     http://www.apache.org/licenses/LICENSE-2.0
    
    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.-->
<!--$Rev: 497879 $ $Date: 2007-01-19 12:11:01 -0500 (Fri, 19 Jan 2007) $-->
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1">
  <dep:environment xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2">
    <dep:moduleId>
      <dep:groupId>org.apache.geronimo.samples</dep:groupId>
      <dep:artifactId>timereport-jetty</dep:artifactId>
      <dep:version>2.1-SNAPSHOT</dep:version>
      <dep:type>car</dep:type>
    </dep:moduleId>
    <dep:dependencies>
      <dep:dependency>
        <dep:groupId>org.apache.geronimo.samples</dep:groupId>
        <dep:artifactId>sample-datasource</dep:artifactId>
        <dep:version>2.1-SNAPSHOT</dep:version>
        <dep:type>car</dep:type>
      </dep:dependency>
      <dep:dependency>
        <dep:groupId>org.apache.geronimo.configs</dep:groupId>
        <dep:artifactId>jasper</dep:artifactId>
        <dep:version>2.1</dep:version>
        <dep:type>car</dep:type>
      </dep:dependency>
      <dep:dependency>
        <dep:groupId>org.apache.geronimo.configs</dep:groupId>
        <dep:artifactId>jetty6</dep:artifactId>
        <dep:version>2.1</dep:version>
        <dep:type>car</dep:type>
      </dep:dependency>
    </dep:dependencies>
    <dep:hidden-classes/>
    <dep:non-overridable-classes/>
  </dep:environment>
  <context-root>/timereport</context-root>
  <security-realm-name>TimeReportRealm</security-realm-name>
  <security>
    <default-principal realm-name="TimeReportRealm">
      <principal name="anonymous" class="org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"/>
    </default-principal>
    <role-mappings>
      <role role-name="employee">
        <realm realm-name="TimeReportRealm">
          <principal name="EmployeeGroup" class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"/>
        </realm>
        <realm realm-name="TimeReportRealm">
          <principal name="ManagerGroup" class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"/>
        </realm>
      </role>
      <role role-name="manager">
        <realm realm-name="TimeReportRealm">
          <principal name="ManagerGroup" class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"/>
        </realm>
      </role>
    </role-mappings>
  </security>
  <gbean name="DBInitialization" class="org.apache.geronimo.connector.DatabaseInitializationGBean">
    <!--<attribute name="testSQL">select * from users</attribute>-->
    <attribute name="path">TimeReportDB.sql</attribute>
    <reference name="DataSource">
      <name>SampleTxDatasource</name>
    </reference>
  </gbean>
  <gbean name="TimeReportRealm" class="org.apache.geronimo.security.realm.GenericSecurityRealm">
    <attribute name="realmName">TimeReportRealm</attribute>
    <reference name="ServerInfo">
      <name>ServerInfo</name>
    </reference>
    <xml-reference name="LoginModuleConfiguration">
      <log:login-config xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-1.1">
        <log:login-module control-flag="REQUIRED" wrap-principals="false">
          <log:login-domain-name>TimeReportRealm</log:login-domain-name>
          <log:login-module-class>org.apache.geronimo.security.realm.providers.SQLLoginModule</log:login-module-class>
          <log:option name="dataSourceName">SampleNoTxDatasource</log:option>
          <log:option name="userSelect">select userid, password from users where userid=?</log:option>
          <log:option name="groupSelect">select userid, groupname from usergroups where userid=?</log:option>
        </log:login-module>
      </log:login-config>
    </xml-reference>
  </gbean>
</web-app>

To restrict access to the Add Employee functionality from Time Report page, programmatic authentication has beeen used as in indicated below.

employee/index.jsp
...
<BR>
<%if(request.isUserInRole("manager")){%>
<A href="../manager/">Add Employees</A>
<BR>
...

Testing of the Sample Application

To test the sample application open a browser and type http://localhost:8080/timereport. It will forward to the Welcome page of the application.

User can access Time Report page providing username as emp1 and password with pass1. To login to the application as a Manager provide mgm1 and pass3 credentials.

Summary

This article has shown you how to deploy web application in to the Geronimo Application server with J2EE declarative security features. You followed step-by-step instructions to build, deploy and test the sample application.

Some highlights of the article are:

  • Apache Geronimo provides two different web containers namely Jetty and Tomcat.
  • Create a database to hold security data with built-in Derby.
  • Define security roles in Geronimo Web applications.
  • Deploy deployment plans and web archives using the Geronimo Console.
  • No labels