You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2019/03/22 09:12:06 UTC

[tomcat] branch master updated: Add optional listeners for Server/Listener

This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new 407d805  Add optional listeners for Server/Listener
407d805 is described below

commit 407d805f1772ae1dd03b6ffbac03be83f55c406b
Author: remm <re...@apache.org>
AuthorDate: Fri Mar 22 10:11:57 2019 +0100

    Add optional listeners for Server/Listener
    
    It is a very slight variant of a standard listener. The difference is
    that loading is not fatal when it fails. This would allow adding example
    configuration to the standard server.xml if deemed useful (example:
    CDI).
    Storeconfig will not attempt to persist the new listener at this time.
    The dummy listener object includes the necessary information, just in
    case, to hold on the properties and original className.
---
 java/org/apache/catalina/startup/Catalina.java     |   5 +-
 .../catalina/startup/ListenerCreateRule.java       | 110 +++++++++++++++++++++
 .../catalina/startup/LocalStrings.properties       |   2 +
 .../catalina/storeconfig/server-registry.xml       |   1 +
 .../tomcat/util/digester/ObjectCreateRule.java     |  31 +++---
 webapps/docs/changelog.xml                         |   7 ++
 6 files changed, 141 insertions(+), 15 deletions(-)

diff --git a/java/org/apache/catalina/startup/Catalina.java b/java/org/apache/catalina/startup/Catalina.java
index f6b1446..f5a0974 100644
--- a/java/org/apache/catalina/startup/Catalina.java
+++ b/java/org/apache/catalina/startup/Catalina.java
@@ -315,9 +315,8 @@ public class Catalina {
                             "setGlobalNamingResources",
                             "org.apache.catalina.deploy.NamingResourcesImpl");
 
-        digester.addObjectCreate("Server/Listener",
-                                 null, // MUST be specified in the element
-                                 "className");
+        digester.addRule("Server/Listener",
+                new ListenerCreateRule(null, "className"));
         digester.addSetProperties("Server/Listener");
         digester.addSetNext("Server/Listener",
                             "addLifecycleListener",
diff --git a/java/org/apache/catalina/startup/ListenerCreateRule.java b/java/org/apache/catalina/startup/ListenerCreateRule.java
new file mode 100644
index 0000000..4a63952
--- /dev/null
+++ b/java/org/apache/catalina/startup/ListenerCreateRule.java
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+
+package org.apache.catalina.startup;
+
+
+import java.util.HashMap;
+import java.util.Set;
+
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.digester.ObjectCreateRule;
+import org.apache.tomcat.util.res.StringManager;
+import org.xml.sax.Attributes;
+
+
+/**
+ * Rule implementation that creates a server listener.
+ */
+public class ListenerCreateRule extends ObjectCreateRule {
+
+    private static final Log log = LogFactory.getLog(ListenerCreateRule.class);
+    protected static final StringManager sm = StringManager.getManager(ListenerCreateRule.class);
+
+    public ListenerCreateRule(String className, String attributeName) {
+        super(className, attributeName);
+    }
+
+    @Override
+    public void begin(String namespace, String name, Attributes attributes)
+            throws Exception {
+        if ("true".equals(attributes.getValue("optional"))) {
+            try {
+                super.begin(namespace, name, attributes);
+            } catch (Exception e) {
+                String className = getRealClassName(attributes);
+                if (log.isDebugEnabled()) {
+                    log.info(sm.getString("listener.createFailed", className), e);
+                } else {
+                    log.info(sm.getString("listener.createFailed", className));
+                }
+                digester.push(new OptionalListener(className));
+            }
+        } else {
+            super.begin(namespace, name, attributes);
+        }
+    }
+
+    public class OptionalListener implements LifecycleListener {
+        protected final String className;
+        protected final HashMap<String, String> properties = new HashMap<>();
+        public OptionalListener(String className) {
+            this.className = className;
+        }
+        /**
+         * @return the className
+         */
+        public String getClassName() {
+            return className;
+        }
+        @Override
+        public void lifecycleEvent(LifecycleEvent event) {
+            // Do nothing
+        }
+        /**
+         * Return a set of the property keys.
+         * @return the set
+         */
+        public Set<String> getProperties() {
+            return properties.keySet();
+        }
+        /**
+         * Return a property from the protocol handler.
+         *
+         * @param name the property name
+         * @return the property value
+         */
+        public Object getProperty(String name) {
+            return properties.get(name);
+        }
+        /**
+         * Set the given property.
+         *
+         * @param name the property name
+         * @param value the property value
+         * @return <code>true</code>
+         */
+        public boolean setProperty(String name, String value) {
+            properties.put(name, value);
+            return true;
+        }
+    }
+}
diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties
index 2bbe045..b3c74ff 100644
--- a/java/org/apache/catalina/startup/LocalStrings.properties
+++ b/java/org/apache/catalina/startup/LocalStrings.properties
@@ -147,6 +147,8 @@ hostConfig.stop=HostConfig: Processing STOP
 hostConfig.undeploy=Undeploying context [{0}]
 hostConfig.undeployVersion=Undeploying old version of context [{0}] which has no active session
 
+listener.createFailed=Optional listener [{0}] is not enabled
+
 passwdUserDatabase.readFail=Failed to obtain a complete set of users from /etc/passwd
 
 tomcat.addWebapp.conflictChild=Unable to deploy WAR at [{0}] to context path [{1}] because of existing context [{2}]
diff --git a/java/org/apache/catalina/storeconfig/server-registry.xml b/java/org/apache/catalina/storeconfig/server-registry.xml
index 97d0a45..124ad9d 100644
--- a/java/org/apache/catalina/storeconfig/server-registry.xml
+++ b/java/org/apache/catalina/storeconfig/server-registry.xml
@@ -292,6 +292,7 @@
        <TransientChild>org.apache.catalina.startup.ContextConfig</TransientChild>
        <TransientChild>org.apache.catalina.startup.EngineConfig</TransientChild>
        <TransientChild>org.apache.catalina.startup.HostConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.ListenerCreateRule$OptionalListener</TransientChild>
        <TransientChild>org.apache.catalina.core.StandardHost$MemoryLeakTrackingListener</TransientChild>
        <TransientChild>org.apache.catalina.mapper.MapperListener</TransientChild>
        <TransientChild>org.apache.catalina.core.StandardEngine$AccessLogListener</TransientChild>
diff --git a/java/org/apache/tomcat/util/digester/ObjectCreateRule.java b/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
index b728ba6..21d0f11 100644
--- a/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
+++ b/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
@@ -94,18 +94,7 @@ public class ObjectCreateRule extends Rule {
     public void begin(String namespace, String name, Attributes attributes)
             throws Exception {
 
-        // Identify the name of the class to instantiate
-        String realClassName = className;
-        if (attributeName != null) {
-            String value = attributes.getValue(attributeName);
-            if (value != null) {
-                realClassName = value;
-            }
-        }
-        if (digester.log.isDebugEnabled()) {
-            digester.log.debug("[ObjectCreateRule]{" + digester.match +
-                    "}New " + realClassName);
-        }
+        String realClassName = getRealClassName(attributes);
 
         if (realClassName == null) {
             throw new NullPointerException(sm.getString("rule.noClassName", namespace, name));
@@ -119,6 +108,24 @@ public class ObjectCreateRule extends Rule {
 
 
     /**
+     * Return the actual class name of the class to be instantiated.
+     * @param attributes The attribute list for this element
+     * @return the class name
+     */
+    protected String getRealClassName(Attributes attributes) {
+        // Identify the name of the class to instantiate
+        String realClassName = className;
+        if (attributeName != null) {
+            String value = attributes.getValue(attributeName);
+            if (value != null) {
+                realClassName = value;
+            }
+        }
+        return realClassName;
+    }
+
+
+    /**
      * Process the end of this element.
      *
      * @param namespace the namespace URI of the matching element, or an
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index b49a62c..0f39d60 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -79,6 +79,13 @@
         that <code>HttpServletRequest.getContextPath()</code> returns an encoded
         path in the dispatched request. (markt)
       </fix>
+      <update>
+        Add optional listeners for Server/Listener, as a slight variant of
+        a standard listener. The difference is that loading is not fatal when
+        it fails. This would allow adding example configuration to the standard
+        server.xml if deemed useful. Storeconfig will not attempt to persist
+        the new listener. (remm)
+      </update>
     </changelog>
   </subsection>
   <subsection name="Coyote">


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


Re: [tomcat] branch master updated: Add optional listeners for Server/Listener

Posted by Rémy Maucherat <re...@apache.org>.
On Fri, Mar 22, 2019 at 10:12 AM <re...@apache.org> wrote:

> This is an automated email from the ASF dual-hosted git repository.
>
> remm pushed a commit to branch master
> in repository https://gitbox.apache.org/repos/asf/tomcat.git
>
>
> The following commit(s) were added to refs/heads/master by this push:
>      new 407d805  Add optional listeners for Server/Listener
> 407d805 is described below
>
> commit 407d805f1772ae1dd03b6ffbac03be83f55c406b
> Author: remm <re...@apache.org>
> AuthorDate: Fri Mar 22 10:11:57 2019 +0100
>
>     Add optional listeners for Server/Listener
>
>     It is a very slight variant of a standard listener. The difference is
>     that loading is not fatal when it fails. This would allow adding
> example
>     configuration to the standard server.xml if deemed useful (example:
>     CDI).
>     Storeconfig will not attempt to persist the new listener at this time.
>     The dummy listener object includes the necessary information, just in
>     case, to hold on the properties and original className.
>

For maximum flexibility, I was planning to add service loader support, but
this then causes difficulties for overriding or avoiding to use a listener.
Maybe it is best to not do it.

Rémy