You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2006/01/03 21:24:42 UTC

svn commit: r365735 - in /tomcat/container/branches/tc4.1.x: catalina/src/share/org/apache/catalina/mbeans/ catalina/src/share/org/apache/catalina/realm/ webapps/admin/WEB-INF/ webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ webapps/admin/WEB-IN...

Author: markt
Date: Tue Jan  3 12:24:27 2006
New Revision: 365735

URL: http://svn.apache.org/viewcvs?rev=365735&view=rev
Log:
Fix bug 16185 by porting support for localDataSource attribute from TC5

Added:
    tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java   (with props)
    tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java   (with props)
    tomcat/container/branches/tc4.1.x/webapps/admin/realm/dataSourceRealm.jsp   (with props)
Modified:
    tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml
    tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java
    tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_en.properties
    tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java
    tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java
    tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/struts-config.xml
    tomcat/container/branches/tc4.1.x/webapps/admin/resources/dataSources.jspf
    tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/config/realm.xml
    tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/realm-howto.xml

Modified: tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml (original)
+++ tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml Tue Jan  3 12:24:27 2006
@@ -353,6 +353,11 @@
                 group="Realm"
                  type="org.apache.catalina.realm.DataSourceRealm">
 
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
     <attribute   name="dataSourceName"
           description="The JNDI named JDBC DataSource for your database"
                  type="java.lang.String"/>
@@ -365,6 +370,10 @@
           description="Digest algorithm used in storing passwords in a
                         non-plaintext format"
                  type="java.lang.String"/>
+
+    <attribute   name="localDataSource"
+          description="Configures if the DataSource is local to the webapp"
+                 type="boolean"/>
 
     <attribute   name="roleNameCol"
           description="The column in the user role table that names a role"

Modified: tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java (original)
+++ tomcat/container/branches/tc4.1.x/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java Tue Jan  3 12:24:27 2006
@@ -32,6 +32,7 @@
 import org.apache.catalina.ServerFactory;
 import org.apache.catalina.core.StandardServer;
 import org.apache.catalina.util.StringManager;
+import org.apache.naming.ContextBindings;
 
 /**
 *
@@ -79,6 +80,12 @@
 
 
     /**
+     * Does this realm use a context local datasource.
+     */
+    protected boolean localDataSource = false;
+    
+    
+    /**
      * Descriptive information about this Realm implementation.
      */
     protected static final String name = "DataSourceRealm";
@@ -142,6 +149,23 @@
     }
 
     /**
+     * Return if the datasource will be looked up in the webapp JNDI Context.
+     */
+    public boolean getLocalDataSource() {
+        return localDataSource;
+    }
+    
+    /**
+     * Set to true to cause the datasource to be looked up in the webapp JNDI
+     * Context.
+     *
+     * @param localDataSource the new flag value
+     */
+    public void setLocalDataSource(boolean localDataSource) {
+        this.localDataSource = localDataSource;
+    }
+
+    /**
      * Return the column in the user role table that names a role.
      *
      */
@@ -360,8 +384,15 @@
     private Connection open() {
 
         try {
-            StandardServer server = (StandardServer) ServerFactory.getServer();
-            Context context = server.getGlobalNamingContext();
+            Context context = null;
+            if (localDataSource) {
+                context = ContextBindings.getClassLoader();
+                context = (Context) context.lookup("comp/env");
+            } else {
+                StandardServer server = 
+                    (StandardServer) ServerFactory.getServer();
+                context = server.getGlobalNamingContext();
+            }
             DataSource dataSource = (DataSource)context.lookup(dataSourceName);
             return dataSource.getConnection();
         } catch (Exception e) {

Modified: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_en.properties
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_en.properties?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_en.properties (original)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_en.properties Tue Jan  3 12:24:27 2006
@@ -244,6 +244,9 @@
 realm.userPassword=User Password
 realm.userPattern=User Pattern
 realm.userSearch=User Search
+realm.dataSourceName=DataSource Name
+realm.localDataSource=Local DataSource
+realm.userCredCol=User Credential Column 
 valve.access.properties=Access Logger Properties
 valve.request.properties=Request Filter Properties
 valve.single.properties=Single SignOn Valve Properties
@@ -288,6 +291,9 @@
 error.connPassword.required=<li>Connection password is required.</li>
 error.connURL.required=<li>Connection URL is required.</li>
 error.connName.required=<li>Connection name is required.</li>
+error.dataSourceName.required=<li>DataSource name is required.</li>
+error.userCredCol.required=<li>User credential is required.</li>
+error.userRoleTable.required=<li>User role table is required.</li>
 
 # ---------- Resources Module ----------
 resources.treeBuilder.subtreeNode=Resources

Modified: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java (original)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java Tue Jan  3 12:24:27 2006
@@ -81,11 +81,12 @@
 
         // Fill in the form values for display and editing
 
-        String realmTypes[] = new String[4];
+        String realmTypes[] = new String[5];
         realmTypes[0] = "UserDatabaseRealm";
         realmTypes[1] = "JNDIRealm";
         realmTypes[2] = "MemoryRealm";
         realmTypes[3] = "JDBCRealm";
+        realmTypes[4] = "DataSourceRealm";
 
         String parent = request.getParameter("parent");
         String type = request.getParameter("type");
@@ -111,9 +112,10 @@
             createJNDIRealm(session, parent);
         } else if ("MemoryRealm".equalsIgnoreCase(type)) {
             createMemoryRealm(session, parent);
-        } else {
-            //JDBC
+        } else if ("JDBCRealm".equalsIgnoreCase(type)){
             createJDBCRealm(session, parent);
+        } else if ("DataSourceRealm".equalsIgnoreCase(type)) {
+            createDataSourceRealm(session, parent);
         }
         // Forward to the realm display page
         return (mapping.findForward(type));
@@ -208,6 +210,28 @@
         realmFm.setRealmTypeVals(types);
     }
 
+    private void createDataSourceRealm(HttpSession session, String parent) {
+        DataSourceRealmForm realmFm = new DataSourceRealmForm();
+        session.setAttribute("dataSourceRealmForm", realmFm);
+        realmFm.setAdminAction("Create");
+        realmFm.setObjectName("");
+        realmFm.setParentObjectName(parent);
+        String realmType = "DataSourceRealm";
+        realmFm.setNodeLabel("Realm (" + realmType + ")");
+        realmFm.setRealmType(realmType);
+        realmFm.setDebugLvl("0");
+        realmFm.setDataSourceName("");
+        realmFm.setDigest("");
+        realmFm.setLocalDataSource("false");
+        realmFm.setRoleNameCol("");
+        realmFm.setUserCredCol("");
+        realmFm.setUserNameCol("");
+        realmFm.setUserRoleTable("");
+        realmFm.setUserTable("");
+        realmFm.setDebugLvlVals(Lists.getDebugLevels());
+        realmFm.setRealmTypeVals(types);
+        realmFm.setBooleanVals(Lists.getBooleanValues());
+    }
 
 
 }

Added: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java?rev=365735&view=auto
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java (added)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java Tue Jan  3 12:24:27 2006
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+
+package org.apache.webapp.admin.realm;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the datasource realm page.
+ * 
+ * @author Amy Roh
+ * @version $Revision: 1.1 $ $Date: 2004/04/17 02:53:17 $
+ */
+
+public final class DataSourceRealmForm extends RealmForm {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The text for the JNDI named JDBC DataSource for your database.
+     */
+    private String dataSourceName = null;
+
+    /**
+     * The text for the digest.
+     */
+    private String digest = null;
+
+    /**
+     * The text for if the DataSource is local to the webapp.
+     */
+    private String localDataSource = "false";
+
+    /**
+     * The text for the roleNameCol.
+     */
+    private String roleNameCol = null;
+
+    /**
+     * The text for the userCredCol.
+     */
+    private String userCredCol = null;
+
+    /**
+     * The text for the userNameCol.
+     */
+    private String userNameCol = null;
+
+    /**
+     * The text for the userRoleTable.
+     */
+    private String userRoleTable = null;
+
+    /**
+     * The text for the user table.
+     */
+    private String userTable = null;
+
+    /**
+     * Represent boolean (true, false) values for unpackWARs etc.
+     */
+    private List booleanVals = null;
+   
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the dataSourceName.
+     */
+    public String getDataSourceName() {
+
+        return this.dataSourceName;
+
+    }
+
+    /**
+     * Set the dataSourceName.
+     */
+    public void setDataSourceName(String dataSourceName) {
+
+        this.dataSourceName = dataSourceName;
+
+    }
+
+    /**
+     * Return the digest.
+     */
+    public String getDigest() {
+
+        return this.digest;
+
+    }
+
+    /**
+     * Set the digest.
+     */
+    public void setDigest(String digest) {
+
+        this.digest = digest;
+
+    }
+
+    /**
+     * Return the localDataSource.
+     */
+    public String getLocalDataSource() {
+
+        return this.localDataSource;
+
+    }
+
+    /**
+     * Set the localDataSource.
+     */
+    public void setLocalDataSource(String localDataSource) {
+
+        this.localDataSource = localDataSource;
+
+    }
+
+    /**
+     * Return the roleNameCol.
+     */
+    public String getRoleNameCol() {
+
+        return this.roleNameCol;
+
+    }
+
+    /**
+     * Set the roleNameCol.
+     */
+    public void setRoleNameCol(String roleNameCol) {
+
+        this.roleNameCol = roleNameCol;
+
+    }
+
+    /**
+     * Return the userCredCol.
+     */
+    public String getUserCredCol() {
+
+        return this.userCredCol;
+
+    }
+
+    /**
+     * Set the userCredCol.
+     */
+    public void setUserCredCol(String userCredCol) {
+
+        this.userCredCol = userCredCol;
+
+    }
+
+    /**
+     * Return the userNameCol.
+     */
+    public String getUserNameCol() {
+
+        return this.userNameCol;
+
+    }
+
+    /**
+     * Set the userNameCol.
+     */
+    public void setUserNameCol(String userNameCol) {
+
+        this.userNameCol = userNameCol;
+
+    }
+
+    /**
+     * Return the user role table.
+     */
+    public String getUserRoleTable() {
+
+        return this.userRoleTable;
+
+    }
+
+    /**
+     * Set the user role table.
+     */
+    public void setUserRoleTable(String userRoleTable) {
+
+        this.userRoleTable = userRoleTable;
+
+    }
+
+    /**
+     * Return the user table.
+     */
+    public String getUserTable() {
+
+        return this.userTable;
+
+    }
+
+    /**
+     * Set the user Table.
+     */
+    public void setUserTable(String userTable) {
+
+        this.userTable = userTable;
+
+    }
+
+    /**
+     * Return the booleanVals.
+     */
+    public List getBooleanVals() {
+
+        return this.booleanVals;
+
+    }
+
+    /**
+     * Set the booleanVals.
+     */
+    public void setBooleanVals(List booleanVals) {
+
+        this.booleanVals = booleanVals;
+
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     * 
+     * @param mapping
+     *            The mapping used to select this instance
+     * @param request
+     *            The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.dataSourceName = null;
+        this.digest = null;
+        this.localDataSource = "false";
+        this.roleNameCol = null;
+        this.userCredCol = null;
+        this.userNameCol = null;
+        this.userTable = null;
+        this.userRoleTable = null;
+
+    }
+
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("DataSourceRealmForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append(",debugLvl=");
+        sb.append(getDebugLvl());
+        sb.append(",dataSourceName=");
+        sb.append(dataSourceName);
+        sb.append(",digest=");
+        sb.append(digest);
+        sb.append("',localDataSource='");
+        sb.append(localDataSource);
+        sb.append("',roleNameCol=");
+        sb.append(roleNameCol);
+        sb.append("',userCredCol=");
+        sb.append(userCredCol);
+        sb.append("',userNameCol=");
+        sb.append(userNameCol);
+        sb.append("',userRoleTable=");
+        sb.append(userRoleTable);
+        sb.append("',userTable='");
+        sb.append(userTable);
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("',realmType=");
+        sb.append(getRealmType());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request, and
+     * return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found. If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     * 
+     * @param mapping
+     *            The mapping used to select this instance
+     * @param request
+     *            The servlet request we are processing
+     */
+
+    public ActionErrors validate(ActionMapping mapping,
+            HttpServletRequest request) {
+
+        ActionErrors errors = new ActionErrors();
+
+        if ((dataSourceName == null) || (dataSourceName.length() < 1)) {
+            errors.add("dataSourceName", new ActionError(
+                    "error.dataSourceName.required"));
+        }
+
+        if ((roleNameCol == null) || (roleNameCol.length() < 1)) {
+            errors.add("roleNameCol", new ActionError(
+                    "error.roleNameCol.required"));
+        }
+
+        if ((userCredCol == null) || (userCredCol.length() < 1)) {
+            errors.add("userCredCol", new ActionError(
+                    "error.userCredCol.required"));
+        }
+
+        if ((userNameCol == null) || (userNameCol.length() < 1)) {
+            errors.add("userNameCol", new ActionError(
+                    "error.userNameCol.required"));
+        }
+
+        if ((userRoleTable == null) || (userRoleTable.length() < 1)) {
+            errors.add("userRoleTable", new ActionError(
+                    "error.userRoleTable.required"));
+        }
+
+        if ((userTable == null) || (userTable.length() < 1)) {
+            errors
+                    .add("userTable", new ActionError(
+                            "error.userTable.required"));
+        }
+
+        return errors;
+    }
+}
\ No newline at end of file

Propchange: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java (original)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java Tue Jan  3 12:24:27 2006
@@ -143,8 +143,10 @@
                setUpMemoryRealm(rname, response);
         } else if ("JDBCRealm".equalsIgnoreCase(realmType)) {
                setUpJDBCRealm(rname, response);
-        } else {
+        } else if ("JNDIRealm".equalsIgnoreCase(realmType)) {
                setUpJNDIRealm(rname, response);
+        } else if ("DataSourceRealm".equalsIgnoreCase(realmType)) {
+               setUpDataSourceRealm(rname, response);
         }
 
         return (mapping.findForward(realmType));
@@ -371,6 +373,70 @@
                 ((String) mBServer.getAttribute(rname, attribute));
             attribute = "connectionURL";
             realmFm.setConnectionURL
+                ((String) mBServer.getAttribute(rname, attribute));
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }
+    }
+
+    private void setUpDataSourceRealm(ObjectName rname,
+                                        HttpServletResponse response)
+    throws IOException {
+        // Fill in the form values for display and editing
+        DataSourceRealmForm realmFm = new DataSourceRealmForm();
+        session.setAttribute("dataSourceRealmForm", realmFm);
+        realmFm.setAdminAction("Edit");
+        realmFm.setObjectName(rname.toString());
+        String realmType = "DataSourceRealm";
+        StringBuffer sb = new StringBuffer();
+        sb.append(resources.getMessage(locale,
+                "server.service.treeBuilder.realm"));
+        sb.append(" (");
+        sb.append(realmType);
+        sb.append(")");
+        realmFm.setNodeLabel(sb.toString());
+        realmFm.setRealmType(realmType);
+        realmFm.setDebugLvlVals(Lists.getDebugLevels());
+        realmFm.setAllowDeletion(allowDeletion(rname));
+        realmFm.setBooleanVals(Lists.getBooleanValues());
+        
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "dataSourceName";
+            realmFm.setDataSourceName
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "debug";
+            realmFm.setDebugLvl
+                (((Integer) mBServer.getAttribute(rname, attribute)).toString());
+            attribute = "digest";
+            realmFm.setDigest
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "localDataSource";
+            realmFm.setLocalDataSource
+                (((Boolean) mBServer.getAttribute(rname, attribute)).toString());
+            attribute = "roleNameCol";
+            realmFm.setRoleNameCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userCredCol";
+            realmFm.setUserCredCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userNameCol";
+            realmFm.setUserNameCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userRoleTable";
+            realmFm.setUserRoleTable
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userTable";
+            realmFm.setUserTable
                 ((String) mBServer.getAttribute(rname, attribute));
 
         } catch (Throwable t) {

Added: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java?rev=365735&view=auto
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java (added)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java Tue Jan  3 12:24:27 2006
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+
+package org.apache.webapp.admin.realm;
+
+import java.net.URLEncoder;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.logger.DeleteLoggerAction;
+
+/**
+ * The <code>Action</code> that completes <em>Add Realm</em> and
+ * <em>Edit Realm</em> transactions for DataSource realm.
+ * 
+ * @author Amy Roh
+ * @version $Revision: 1.1 $ $Date: 2004/04/17 02:53:17 $
+ */
+
+public final class SaveDataSourceRealmAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createDataSourceRealm</code> operation.
+     */
+    private String createDataSourceRealmTypes[] = { "java.lang.String", // parent
+            "java.lang.String", // dataSourceName
+            "java.lang.String", // roleNameCol
+            "java.lang.String", // userCredCol
+            "java.lang.String", // userNameCol
+            "java.lang.String", // userRoleTable
+            "java.lang.String", // userTable
+    };
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+
+    /**
+     * The MessageResources we will be retrieving messages from.
+     */
+    private MessageResources resources = null;
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     * 
+     * @param mapping
+     *            The ActionMapping used to select this instance
+     * @param actionForm
+     *            The optional ActionForm bean for this request (if any)
+     * @param request
+     *            The HTTP request we are processing
+     * @param response
+     *            The HTTP response we are creating
+     * 
+     * @exception IOException
+     *                if an input/output error occurs
+     * @exception ServletException
+     *                if a servlet exception occurs
+     */
+    public ActionForward perform(ActionMapping mapping, ActionForm form,
+            HttpServletRequest request, HttpServletResponse response)
+            throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = (Locale) session.getAttribute(Action.LOCALE_KEY);
+        if (resources == null) {
+            resources = getServlet().getResources();
+        }
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException("Cannot acquire MBeanServer reference",
+                    t);
+        }
+
+        // Identify the requested action
+        DataSourceRealmForm rform = (DataSourceRealmForm) form;
+        String adminAction = rform.getAdminAction();
+        String rObjectName = rform.getObjectName();
+
+        // Perform a "Create DataSource Realm" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            String values[] = null;
+
+            try {
+
+                String parent = rform.getParentObjectName();
+                String objectName = DeleteLoggerAction.getObjectName(parent,
+                        TomcatTreeBuilder.REALM_TYPE);
+
+                ObjectName pname = new ObjectName(parent);
+                StringBuffer sb = new StringBuffer(pname.getDomain());
+
+                // For service, create the corresponding Engine mBean
+                // Parent in this case needs to be the container mBean for the
+                // service
+                try {
+                    if ("Service"
+                            .equalsIgnoreCase(pname.getKeyProperty("type"))) {
+                        sb.append(":type=Engine");
+                        parent = sb.toString();
+                    }
+                } catch (Exception e) {
+                    String message = resources.getMessage(locale,
+                            "error.engineName.bad", sb.toString());
+                    getServlet().log(message);
+                    response.sendError(HttpServletResponse.SC_BAD_REQUEST,
+                            message);
+                    return (null);
+                }
+
+                // Ensure that the requested user database name is unique
+                ObjectName oname = new ObjectName(objectName);
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("realmName", new ActionError(
+                            "error.realmName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+
+                // Look up our MBeanFactory MBean
+                ObjectName fname =
+                    new ObjectName(TomcatTreeBuilder.FACTORY_TYPE);
+
+                // Create a new DataSourceRealm object
+                values = new String[7];
+                values[0] = parent;
+                values[1] = rform.getDataSourceName();
+                values[2] = rform.getRoleNameCol();
+                values[3] = rform.getUserCredCol();
+                values[4] = rform.getUserNameCol();
+                values[5] = rform.getUserRoleTable();
+                values[6] = rform.getUserTable();
+                operation = "createDataSourceRealm";
+                rObjectName = (String) mBServer.invoke(fname, operation,
+                        values, createDataSourceRealmTypes);
+
+                if (rObjectName == null) {
+                    request.setAttribute("warning", "error.datasourcerealm");
+                    return (mapping.findForward("Save Unsuccessful"));
+                }
+
+                // Add the new Realm to our tree control node
+                TreeControl control = (TreeControl) session
+                        .getAttribute("treeControlTest");
+                if (control != null) {
+                    TreeControlNode parentNode = control.findNode(rform
+                            .getParentObjectName());
+                    if (parentNode != null) {
+                        String nodeLabel = rform.getNodeLabel();
+                        String encodedName = URLEncoder.encode(rObjectName);
+                        TreeControlNode childNode =
+                            new TreeControlNode(rObjectName,
+                                                "Realm.gif",
+                                                nodeLabel,
+                                                "EditRealm.do?select="
+                                                + encodedName,
+                                                "content",
+                                                true);
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log(
+                                "Cannot find parent node '" + parent + "'");
+                    }
+                } else {
+                    getServlet().log("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log(
+                        resources.getMessage(locale, "users.error.invoke",
+                                operation), e);
+                response.sendError(
+                        HttpServletResponse.SC_INTERNAL_SERVER_ERROR, resources
+                                .getMessage(locale, "users.error.invoke",
+                                        operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            ObjectName roname = new ObjectName(rObjectName);
+
+            attribute = "debug";
+            int debug = 0;
+            try {
+                debug = Integer.parseInt(rform.getDebugLvl());
+            } catch (Throwable t) {
+                debug = 0;
+            }
+            mBServer.setAttribute(roname, new Attribute("debug", new Integer(
+                    debug)));
+
+            attribute = "dataSourceName";
+            mBServer.setAttribute(roname, new Attribute(attribute, rform
+                    .getDataSourceName()));
+            attribute = "digest";
+            mBServer.setAttribute(roname, new Attribute("digest", rform
+                    .getDigest()));
+
+            attribute = "roleNameCol";
+            mBServer.setAttribute(roname, new Attribute("roleNameCol", rform
+                    .getRoleNameCol()));
+            attribute = "userCredCol";
+            mBServer.setAttribute(roname, new Attribute("userCredCol", rform
+                    .getUserCredCol()));
+            attribute = "userNameCol";
+            mBServer.setAttribute(roname, new Attribute("userNameCol", rform
+                    .getUserNameCol()));
+            attribute = "userRoleTable";
+            mBServer.setAttribute(roname, new Attribute("userRoleTable", rform
+                    .getUserRoleTable()));
+            attribute = "userTable";
+            mBServer.setAttribute(roname, new Attribute("userTable", rform
+                    .getUserTable()));
+        } catch (Exception e) {
+
+            getServlet().log(
+                    resources.getMessage(locale, "users.error.attribute.set",
+                            attribute), e);
+            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                    resources.getMessage(locale, "users.error.attribute.set",
+                            attribute));
+            return (null);
+        }
+
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+
+    }
+
+}
\ No newline at end of file

Propchange: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/struts-config.xml
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/struts-config.xml?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/struts-config.xml (original)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/WEB-INF/struts-config.xml Tue Jan  3 12:24:27 2006
@@ -56,6 +56,9 @@
 
     <!-- ============= Realm Module ============= -->
 
+    <form-bean      name="dataSourceRealmForm"
+                    type="org.apache.webapp.admin.realm.DataSourceRealmForm"/>
+
     <form-bean      name="jdbcRealmForm"
                     type="org.apache.webapp.admin.realm.JDBCRealmForm"/>
 
@@ -286,6 +289,10 @@
 
     <!-- ============ Realm Module ============== -->
 
+    <forward        name="DataSourceRealm"
+                    path="/realm/dataSourceRealm.jsp"
+                redirect="false"/>
+                
     <forward        name="JDBCRealm"
                     path="/realm/jdbcRealm.jsp"
                 redirect="false"/>
@@ -652,6 +659,13 @@
                type="org.apache.webapp.admin.realm.SaveUserDatabaseRealmAction"
                name="userDatabaseRealmForm"
               input="/realm/userDatabaseRealm.jsp"
+               scope="session"/>
+
+   <!-- Perform Save DataSource Realm transaction -->
+    <action    path="/SaveDataSourceRealm"
+               type="org.apache.webapp.admin.realm.SaveDataSourceRealmAction"
+               name="dataSourceRealmForm"
+              input="/realm/dataSourceRealm.jsp"
                scope="session"/>
 
    <!-- Perform Save JDBC Realm transaction -->

Added: tomcat/container/branches/tc4.1.x/webapps/admin/realm/dataSourceRealm.jsp
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/realm/dataSourceRealm.jsp?rev=365735&view=auto
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/realm/dataSourceRealm.jsp (added)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/realm/dataSourceRealm.jsp Tue Jan  3 12:24:27 2006
@@ -0,0 +1,166 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
+<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveDataSourceRealm">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="dataSourceRealmForm" property="objectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="allowDeletion"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="dataSourceRealmForm" property="adminAction" value="Create">
+            <bean:message key="actions.realms.create"/>
+          </logic:equal>
+          <logic:equal name="dataSourceRealmForm" property="adminAction" value="Edit">
+            <bean:write name="dataSourceRealmForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Realm Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="dataSourceRealmForm" property="adminAction" value="Create">
+            <logic:notEqual name="dataSourceRealmForm" property="allowDeletion" value="false">
+             <controls:action url='<%= "/DeleteRealm.do?select=" +
+                                        URLEncoder.encode(thisObjectName) %>'>
+                <bean:message key="actions.realms.delete"/>
+              </controls:action>
+               </logic:notEqual>
+             </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="dataSourceRealmForm" property="adminAction" value="Create">
+                    <html:select property="realmType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="realmTypeVals" name="dataSourceRealmForm" property="realmTypeVals"/>
+                     <html:options collection="realmTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="dataSourceRealmForm" property="adminAction" value="Edit">
+                  <bean:write name="dataSourceRealmForm" property="realmType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="driver">
+            <controls:label><bean:message key="realm.dataSourceName"/>:</controls:label>
+            <controls:data>
+              <html:text property="dataSourceName" size="30" styleId="dataSourceName"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="debuglevel">
+            <controls:label><bean:message key="server.debuglevel"/>:</controls:label>
+            <controls:data>
+               <html:select property="debugLvl" styleId="debuglevel">
+                     <bean:define id="debugLvlVals" name="dataSourceRealmForm" property="debugLvlVals"/>
+                     <html:options collection="debugLvlVals" property="value"
+                        labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="digest">
+            <controls:label><bean:message key="realm.digest"/>:</controls:label>
+            <controls:data>
+                <html:text property="digest" size="30" styleId="digest"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="localDataSource">
+            <controls:label><bean:message key="realm.localDataSource"/>:</controls:label>
+            <controls:data>
+               <html:select property="localDataSource" styleId="localDataSource">
+                     <bean:define id="booleanVals" name="dataSourceRealmForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="roleNameCol">
+            <controls:label><bean:message key="realm.roleNameCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="roleNameCol" size="30" styleId="roleNameCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userCredCol">
+            <controls:label><bean:message key="realm.userCredCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="userCredCol" size="30" styleId="userCredCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userNameCol">
+            <controls:label><bean:message key="realm.userNameCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="userNameCol" size="30" styleId="userNameCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userRoleTable">
+            <controls:label><bean:message key="realm.userRoleTable"/>:</controls:label>
+            <controls:data>
+                <html:text property="userRoleTable" size="30" styleId="userRoleTable"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userTable">
+            <controls:label><bean:message key="realm.userTable"/>:</controls:label>
+            <controls:data>
+                <html:text property="userTable" size="30" styleId="userTable"/>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>
\ No newline at end of file

Propchange: tomcat/container/branches/tc4.1.x/webapps/admin/realm/dataSourceRealm.jsp
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/container/branches/tc4.1.x/webapps/admin/resources/dataSources.jspf
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/admin/resources/dataSources.jspf?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/admin/resources/dataSources.jspf (original)
+++ tomcat/container/branches/tc4.1.x/webapps/admin/resources/dataSources.jspf Tue Jan  3 12:24:27 2006
@@ -28,20 +28,20 @@
             <input type="checkbox" name="dataSources"
                   value="<%= dataSource %>" styleId="dataSources">
           </td>
+          <td><div align="left" class="table-normal-text">
+            <html:link page='<%= "/resources/setUpDataSource.do?objectName=" + 
+                                 URLEncoder.encode(dataSource) + "&resourcetype=" +
+                                 URLEncoder.encode(resourcetypeInfo) + "&path="+
+                                 URLEncoder.encode(pathInfo) + "&host="+
+                                 URLEncoder.encode(hostInfo) + "&service="+
+                                 URLEncoder.encode(serviceInfo) %>'>
+              <controls:attribute name="dataSource" attribute="name"/>
+            </html:link>
+          </div></td>
+          <td><div align="left" class="table-normal-text">&nbsp;
+            <controls:attribute name="dataSource" attribute="driverClassName"/>
+          </div></td>
         </logic:present>
-        <td><div align="left" class="table-normal-text">
-          <html:link page='<%= "/resources/setUpDataSource.do?objectName=" + 
-                               URLEncoder.encode(dataSource) + "&resourcetype=" +
-                               URLEncoder.encode(resourcetypeInfo) + "&path="+
-                               URLEncoder.encode(pathInfo) + "&host="+
-                               URLEncoder.encode(hostInfo) + "&service="+
-                               URLEncoder.encode(serviceInfo) %>'>
-            <controls:attribute name="dataSource" attribute="name"/>
-          </html:link>
-        </div></td>
-        <td><div align="left" class="table-normal-text">&nbsp;
-          <controls:attribute name="dataSource" attribute="driverClassName"/>
-        </div></td>
       </tr>
     </logic:iterate>
 

Modified: tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/config/realm.xml
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/config/realm.xml?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/config/realm.xml (original)
+++ tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/config/realm.xml Tue Jan  3 12:24:27 2006
@@ -189,6 +189,13 @@
         user passwords are assumed to be stored in clear-text.</p>
       </attribute>
 
+      <attribute name="localDataSource" required="false">
+        <p>When the realm is nested inside a Context element, this allows the
+        realm to use a DataSource defined for the Context rather than a global
+        DataSource.  If not specified, the default is <code>false</code>: use a
+        global DataSource.</p>
+      </attribute>
+
       <attribute name="roleNameCol" required="true">
         <p>Name of the column, in the "user roles" table, which contains
         a role name assigned to the corresponding user.</p>

Modified: tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/realm-howto.xml
URL: http://svn.apache.org/viewcvs/tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/realm-howto.xml?rev=365735&r1=365734&r2=365735&view=diff
==============================================================================
--- tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/realm-howto.xml (original)
+++ tomcat/container/branches/tc4.1.x/webapps/tomcat-docs/realm-howto.xml Tue Jan  3 12:24:27 2006
@@ -428,6 +428,13 @@
     information.  If not specified, passwords are stored in clear text.</p>
   </attribute>
 
+  <attribute name="localDataSource" required="false">
+    <p>When the realm is nested inside a Context element, this allows the 
+    realm to use a DataSource defined for the Context rather than a global
+    DataSource.  If not specified, the default is <code>false</code>: use a 
+    global DataSource.</p>
+  </attribute>
+
   <attribute name="roleNameCol" required="true">
     <p>The name of the column, in the <em>user roles</em> table, that
     contains the name of a role assigned to this user.</p>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org