Author: bago
Date: Wed Oct 14 17:13:48 2009
New Revision: 825198

URL: http://svn.apache.org/viewvc?rev=825198&view=rev
Log:
a sample refactoring using composition instead of inheritance (JAMES-930)

Added:
    
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServerComposed.java
   (with props)
    
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerComposedTest.java
   (with props)

Added: 
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServerComposed.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServerComposed.java?rev=825198&view=auto
==============================================================================
--- 
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServerComposed.java
 (added)
+++ 
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServerComposed.java
 Wed Oct 14 17:13:48 2009
@@ -0,0 +1,400 @@
+/****************************************************************
+ * 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.james.smtpserver;
+
+import javax.annotation.Resource;
+
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.DefaultServiceManager;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.commons.logging.impl.AvalonLogger;
+import org.apache.james.Constants;
+import org.apache.james.api.dnsservice.DNSService;
+import org.apache.james.api.dnsservice.util.NetMatcher;
+import org.apache.james.api.kernel.LoaderService;
+import org.apache.james.services.MailServer;
+import org.apache.james.socket.AvalonProtocolServer;
+import org.apache.james.socket.api.ProtocolHandler;
+import org.apache.james.socket.api.ProtocolHandlerFactory;
+import org.apache.james.socket.api.ProtocolServer;
+import org.apache.james.socket.configuration.JamesConfiguration;
+import org.apache.mailet.MailetContext;
+
+/**
+ * This is an test refactoring for SMTPServer where the avalon socket server
+ * is a dependency and this class do not depend on it.
+ * 
+ * <p>Accepts SMTP connections on a server socket and dispatches them to 
SMTPHandlers.</p>
+ *
+ * <p>Also responsible for loading and parsing SMTP specific configuration.</p>
+ *
+ * @version 1.1.0, 06/02/2001
+ */
+/*
+ * IMPORTANT: SMTPServer extends AbstractJamesService.  If you implement ANY
+ * lifecycle methods, you MUST call super.<method> as well.
+ */
+public class SMTPServerComposed extends AbstractLogEnabled implements 
ProtocolHandlerFactory, Serviceable, Configurable, Initializable {
+
+
+    /**
+     * The handler chain - SMTPhandlers can lookup handlerchain to obtain
+     * Command handlers , Message handlers and connection handlers
+     * Constructed during initialisation to allow dependency injection.
+     */
+    private SMTPHandlerChain handlerChain;
+
+    /**
+     * The mailet context - we access it here to set the hello name for the 
Mailet API
+     */
+    private MailetContext mailetcontext;
+
+    /**
+     * The internal mail server service.
+     */
+    private MailServer mailServer;
+
+    /** Loads instances */
+    private LoaderService loader;
+
+    /** Cached configuration data for handler */
+    private Configuration handlerConfiguration;
+
+    /**
+     * The DNSService
+     */
+    private DNSService dnsService = null;
+
+    /**
+     * Whether authentication is required to use
+     * this SMTP server.
+     */
+    private final static int AUTH_DISABLED = 0;
+    private final static int AUTH_REQUIRED = 1;
+    private final static int AUTH_ANNOUNCE = 2;
+    private int authRequired = AUTH_DISABLED;
+
+    /**
+     * Whether the server needs helo to be send first
+     */
+    private boolean heloEhloEnforcement = false;
+
+    /**
+     * SMTPGreeting to use 
+     */
+    private String smtpGreeting = null;
+
+    /**
+     * This is a Network Matcher that should be configured to contain
+     * authorized networks that bypass SMTP AUTH requirements.
+     */
+    private NetMatcher authorizedNetworks = null;
+
+    /**
+     * The maximum message size allowed by this SMTP server.  The default
+     * value, 0, means no limit.
+     */
+    private long maxMessageSize = 0;
+
+    /**
+     * The number of bytes to read before resetting
+     * the connection timeout timer.  Defaults to
+     * 20 KB.
+     */
+    private int lengthReset = 20 * 1024;
+
+    /**
+     * The configuration data to be passed to the handler
+     */
+    private SMTPConfiguration theConfigData
+    = new SMTPHandlerConfigurationDataImpl();
+
+    private boolean addressBracketsEnforcement = true;
+
+    private ProtocolServer protocolServer;
+    
+    private AvalonProtocolServer avalonProtocolServer;
+    
+    /**
+     * Gets the current instance loader.
+     * @return the loader
+     */
+    public final LoaderService getLoader() {
+        return loader;
+    }
+
+    /**
+     * Sets the loader to be used for instances.
+     * @param loader the loader to set, not null
+     */
+    @Resource(name="org.apache.james.LoaderService")
+    public final void setLoader(LoaderService loader) {
+        this.loader = loader;
+    }
+
+    /**
+     * @see 
org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
+     */
+    public void service( final ServiceManager manager ) throws 
ServiceException {
+        mailetcontext = (MailetContext) 
manager.lookup("org.apache.mailet.MailetContext");
+        mailServer = (MailServer) manager.lookup(MailServer.ROLE);
+        dnsService = (DNSService) manager.lookup(DNSService.ROLE);
+
+        // initialize the avalonProtocolServer passing "this" as the 
ProtocolHandlerFactory service
+        DefaultServiceManager sm = new DefaultServiceManager(manager);
+        sm.put(ProtocolHandlerFactory.ROLE, (ProtocolHandlerFactory) this);
+        avalonProtocolServer = new AvalonProtocolServer();
+        avalonProtocolServer.enableLogging(getLogger());
+        avalonProtocolServer.service(sm);
+    }
+
+    /**
+     * @see 
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+     */
+    public void configure(final Configuration configuration) throws 
ConfigurationException {
+        avalonProtocolServer.configure(configuration);
+        
+        if (avalonProtocolServer.isEnabled()) {
+
+            handlerConfiguration = configuration.getChild("handler");
+            String authRequiredString = 
handlerConfiguration.getChild("authRequired").getValue("false").trim().toLowerCase();
+            if (authRequiredString.equals("true")) authRequired = 
AUTH_REQUIRED;
+            else if (authRequiredString.equals("announce")) authRequired = 
AUTH_ANNOUNCE;
+            else authRequired = AUTH_DISABLED;
+            if (authRequired != AUTH_DISABLED) {
+                getLogger().info("This SMTP server requires authentication.");
+            } else {
+                getLogger().info("This SMTP server does not require 
authentication.");
+            }
+
+            String authorizedAddresses = 
handlerConfiguration.getChild("authorizedAddresses").getValue(null);
+            if (authRequired == AUTH_DISABLED && authorizedAddresses == null) {
+                /* if SMTP AUTH is not requred then we will use
+                 * authorizedAddresses to determine whether or not to
+                 * relay e-mail.  Therefore if SMTP AUTH is not
+                 * required, we will not relay e-mail unless the
+                 * sending IP address is authorized.
+                 *
+                 * Since this is a change in behavior for James v2,
+                 * create a default authorizedAddresses network of
+                 * 0.0.0.0/0, which matches all possible addresses, thus
+                 * preserving the current behavior.
+                 *
+                 * James v3 should require the <authorizedAddresses>
+                 * element.
+                 */
+                authorizedAddresses = "0.0.0.0/0.0.0.0";
+            }
+
+            if (authorizedAddresses != null) {
+                java.util.StringTokenizer st = new 
java.util.StringTokenizer(authorizedAddresses, ", ", false);
+                java.util.Collection<String> networks = new 
java.util.ArrayList<String>();
+                while (st.hasMoreTokens()) {
+                    String addr = st.nextToken();
+                    networks.add(addr);
+                }
+                authorizedNetworks = new NetMatcher(networks, dnsService);
+            }
+
+            if (authorizedNetworks != null) {
+                getLogger().info("Authorized addresses: " + 
authorizedNetworks.toString());
+            }
+
+            // get the message size limit from the conf file and multiply
+            // by 1024, to put it in bytes
+            maxMessageSize = handlerConfiguration.getChild( "maxmessagesize" 
).getValueAsLong( maxMessageSize ) * 1024;
+            if (maxMessageSize > 0) {
+                getLogger().info("The maximum allowed message size is " + 
maxMessageSize + " bytes.");
+            } else {
+                getLogger().info("No maximum message size is enforced for this 
server.");
+            }
+            // How many bytes to read before updating the timer that data is 
being transfered
+            lengthReset = 
configuration.getChild("lengthReset").getValueAsInteger(lengthReset);
+            if (lengthReset <= 0) {
+                throw new ConfigurationException("The configured value for the 
idle timeout reset, " + lengthReset + ", is not valid.");
+            }
+            if (getLogger().isInfoEnabled()) {
+                getLogger().info("The idle timeout will be reset every " + 
lengthReset + " bytes.");
+            }
+
+            heloEhloEnforcement = 
handlerConfiguration.getChild("heloEhloEnforcement").getValueAsBoolean(true);
+
+            if (authRequiredString.equals("true")) authRequired = 
AUTH_REQUIRED;
+
+            // get the smtpGreeting
+            smtpGreeting = 
handlerConfiguration.getChild("smtpGreeting").getValue(null);
+
+            addressBracketsEnforcement = 
handlerConfiguration.getChild("addressBracketsEnforcement").getValueAsBoolean(true);
+        }
+    }
+
+    public void initialize() throws Exception {
+        // this initialize the protocol server that wil call back our 
init(ProtocolServer) method
+        avalonProtocolServer.initialize();
+
+    }
+
+    private void prepareHandlerChain() throws Exception {
+        handlerChain = loader.load(SMTPHandlerChain.class);
+        
+        //set the logger
+        handlerChain.setLog(new AvalonLogger(getLogger()));
+        
+        //read from the XML configuration and create and configure each of the 
handlers
+        handlerChain.configure(new 
JamesConfiguration(handlerConfiguration.getChild("handlerchain")));
+    }
+
+    /**
+     * @see org.apache.james.core.AbstractProtocolServer#getDefaultPort()
+     */
+    public int getDefaultPort() {
+        return 25;
+    }
+
+    /**
+     * @see org.apache.james.core.AbstractProtocolServer#getServiceType()
+     */
+    public String getServiceType() {
+        return "SMTP Service";
+    }
+
+    /**
+     * A class to provide SMTP handler configuration to the handlers
+     */
+    private class SMTPHandlerConfigurationDataImpl implements 
SMTPConfiguration {
+
+        /**
+         * @see org.apache.james.smtpserver.SMTPConfiguration#getHelloName()
+         */
+        public String getHelloName() {
+            if (SMTPServerComposed.this.avalonProtocolServer.getHelloName() == 
null) {
+                return SMTPServerComposed.this.mailServer.getHelloName();
+            } else {
+                return 
SMTPServerComposed.this.avalonProtocolServer.getHelloName();
+            }
+        }
+
+        /**
+         * @see org.apache.james.smtpserver.SMTPConfiguration#getResetLength()
+         */
+        public int getResetLength() {
+            return SMTPServerComposed.this.lengthReset;
+        }
+
+        /**
+         * @see 
org.apache.james.smtpserver.SMTPConfiguration#getMaxMessageSize()
+         */
+        public long getMaxMessageSize() {
+            return SMTPServerComposed.this.maxMessageSize;
+        }
+
+        /**
+         * @see 
org.apache.james.smtpserver.SMTPConfiguration#isAuthSupported(String)
+         */
+        public boolean isRelayingAllowed(String remoteIP) {
+            boolean relayingAllowed = false;
+            if (authorizedNetworks != null) {
+                relayingAllowed = 
SMTPServerComposed.this.authorizedNetworks.matchInetNetwork(remoteIP);
+            }
+            return relayingAllowed;
+        }
+
+        /**
+         * @see 
org.apache.james.smtpserver.SMTPConfiguration#useHeloEhloEnforcement()
+         */
+        public boolean useHeloEhloEnforcement() {
+            return SMTPServerComposed.this.heloEhloEnforcement;
+        }
+
+
+        /**
+         * @see org.apache.james.smtpserver.SMTPConfiguration#getSMTPGreeting()
+         */
+        public String getSMTPGreeting() {
+            return SMTPServerComposed.this.smtpGreeting;
+        }
+
+        /**
+         * @see 
org.apache.james.smtpserver.SMTPConfiguration#useAddressBracketsEnforcement()
+         */
+        public boolean useAddressBracketsEnforcement() {
+            return SMTPServerComposed.this.addressBracketsEnforcement;
+        }
+
+        public boolean isAuthRequired(String remoteIP) {
+            if (SMTPServerComposed.this.authRequired == AUTH_ANNOUNCE) return 
true;
+            boolean authRequired = SMTPServerComposed.this.authRequired != 
AUTH_DISABLED;
+            if (authorizedNetworks != null) {
+                authRequired = authRequired && 
!SMTPServerComposed.this.authorizedNetworks.matchInetNetwork(remoteIP);
+            }
+            return authRequired;
+        }
+
+               public boolean isStartTLSSupported() {
+                       return 
SMTPServerComposed.this.avalonProtocolServer.useStartTLS();
+               }
+        
+        //TODO: IF we create here an interface to get DNSServer
+        //      we should access it from the SMTPHandlers
+
+    }
+
+    /**
+     * @see 
org.apache.james.socket.AbstractProtocolServer#newProtocolHandlerInstance()
+     */
+    public ProtocolHandler newProtocolHandlerInstance() {
+        final SMTPHandler theHandler = new SMTPHandler(handlerChain, 
theConfigData);
+        return theHandler;
+    }
+
+    
+    public void init() throws Exception {
+        // complete the initialization
+
+    }
+
+    public void prepare(ProtocolServer server) throws Exception {
+        // in this case the protocolServer has been instantiated by us,
+        // so this will equal to avalonProtocolServer.
+        this.protocolServer = server;
+
+        String hello = (String) 
mailetcontext.getAttribute(Constants.HELLO_NAME);
+
+        if (protocolServer.isEnabled()) {
+            // TODO Remove this in next not backwards compatible release!
+            if (hello == null) 
mailetcontext.setAttribute(Constants.HELLO_NAME, protocolServer.getHelloName());
+        } else {
+            // TODO Remove this in next not backwards compatible release!
+            if (hello == null) 
mailetcontext.setAttribute(Constants.HELLO_NAME, "localhost");
+        }
+
+        
+        prepareHandlerChain();
+    }
+    
+}

Propchange: 
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServerComposed.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServerComposed.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerComposedTest.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerComposedTest.java?rev=825198&view=auto
==============================================================================
--- 
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerComposedTest.java
 (added)
+++ 
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerComposedTest.java
 Wed Oct 14 17:13:48 2009
@@ -0,0 +1,44 @@
+/****************************************************************
+ * 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.james.smtpserver;
+
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.james.test.mock.avalon.MockLogger;
+
+public class SMTPServerComposedTest extends SMTPServerTest {
+
+    private SMTPServerComposed m_smtpServer;
+
+    protected void setUp() throws Exception {
+        m_smtpServer = new SMTPServerComposed();
+        ContainerUtil.enableLogging(m_smtpServer,new MockLogger());
+        m_serviceManager = setUpServiceManager();
+        ContainerUtil.service(m_smtpServer, m_serviceManager);
+        m_smtpServer.setLoader(m_serviceManager);
+        m_testConfiguration = new SMTPTestConfiguration(m_smtpListenerPort);
+    }
+
+    protected void finishSetUp(SMTPTestConfiguration testConfiguration) throws 
Exception {
+        testConfiguration.init();
+        ContainerUtil.configure(m_smtpServer, testConfiguration);
+        
m_mailServer.setMaxMessageSizeBytes(m_testConfiguration.getMaxMessageSize()*1024);
+        ContainerUtil.initialize(m_smtpServer);
+    }
+}

Propchange: 
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerComposedTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerComposedTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to