directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From trus...@apache.org
Subject svn commit: r158586 - in directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server: auth/ jndi/ jndi/invocation/interceptor/
Date Tue, 22 Mar 2005 09:39:10 GMT
Author: trustin
Date: Tue Mar 22 01:39:07 2005
New Revision: 158586

URL: http://svn.apache.org/viewcvs?view=rev&rev=158586
Log:
* Added InterceptorContext which gives access to various internal properties of service.
* Modified Interceptor.init() to have InterceptorContext passed to interceptors.
* Updated all interceptor implementations to have default constructors and configure themselves in init().
* InterceptorChain is now Interceptor, and thus InterceptorChains can nest.
* Added EnvKeys.INTERCEPTOR property to let users override the default interceptor chain.

Added:
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorContext.java   (with props)
Modified:
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/AuthenticatorContext.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/SimpleAuthenticator.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/Authenticator.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/CoreContextFactory.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/EnvKeys.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/JndiProvider.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Authorizer.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Interceptor.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorChain.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/OperationalAttributeInterceptor.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/SchemaManager.java
    directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Validator.java

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/AuthenticatorContext.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/AuthenticatorContext.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/AuthenticatorContext.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/AuthenticatorContext.java Tue Mar 22 01:39:07 2005
@@ -17,7 +17,7 @@
 package org.apache.ldap.server.auth;
 
 
-import org.apache.ldap.server.RootNexus;
+import org.apache.ldap.server.PartitionNexus;
 
 
 /**
@@ -30,7 +30,7 @@
 {
 
     /** the root nexus to all database partitions */
-    private RootNexus rootNexus;
+    private PartitionNexus partitionNexus;
     /** whether or not to allow anonymous users */
     private boolean allowAnonymous = false;
 
@@ -41,13 +41,13 @@
     {
     }
 
-    public RootNexus getRootNexus()
+    public PartitionNexus getPartitionNexus()
     {
-        return rootNexus;
+        return partitionNexus;
     }
-    public void setRootNexus( RootNexus rootNexus )
+    public void setPartitionNexus( PartitionNexus rootNexus )
     {
-        this.rootNexus = rootNexus;
+        this.partitionNexus = rootNexus;
     }
 
     public boolean getAllowAnonymous()

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/SimpleAuthenticator.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/SimpleAuthenticator.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/SimpleAuthenticator.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/auth/SimpleAuthenticator.java Tue Mar 22 01:39:07 2005
@@ -17,17 +17,17 @@
 package org.apache.ldap.server.auth;
 
 
-import org.apache.ldap.server.RootNexus;
-import org.apache.ldap.server.jndi.ServerContext;
-import org.apache.ldap.common.exception.LdapNameNotFoundException;
-import org.apache.ldap.common.exception.LdapAuthenticationException;
-import org.apache.ldap.common.util.ArrayUtils;
-import org.apache.ldap.common.name.LdapName;
-
 import javax.naming.Context;
 import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
 import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+
+import org.apache.ldap.common.exception.LdapAuthenticationException;
+import org.apache.ldap.common.exception.LdapNameNotFoundException;
+import org.apache.ldap.common.name.LdapName;
+import org.apache.ldap.common.util.ArrayUtils;
+import org.apache.ldap.server.PartitionNexus;
+import org.apache.ldap.server.jndi.ServerContext;
 
 
 /**
@@ -100,7 +100,7 @@
 
         LdapName principalDn = new LdapName( principal );
 
-        RootNexus rootNexus = getAuthenticatorContext().getRootNexus();
+        PartitionNexus rootNexus = getAuthenticatorContext().getPartitionNexus();
 
         Attributes userEntry = rootNexus.lookup( principalDn );
 

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/Authenticator.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/Authenticator.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/Authenticator.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/Authenticator.java Tue Mar 22 01:39:07 2005
@@ -17,12 +17,13 @@
 package org.apache.ldap.server.jndi;
 
 
+import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
-import java.util.Properties;
 
 import javax.naming.Context;
 import javax.naming.NamingException;
@@ -31,9 +32,15 @@
 import org.apache.ldap.common.exception.LdapAuthenticationNotSupportedException;
 import org.apache.ldap.common.message.ResultCodeEnum;
 import org.apache.ldap.common.util.StringTools;
+import org.apache.ldap.server.auth.AbstractAuthenticator;
+import org.apache.ldap.server.auth.AnonymousAuthenticator;
+import org.apache.ldap.server.auth.AuthenticatorConfig;
+import org.apache.ldap.server.auth.AuthenticatorContext;
 import org.apache.ldap.server.auth.LdapPrincipal;
+import org.apache.ldap.server.auth.SimpleAuthenticator;
 import org.apache.ldap.server.jndi.invocation.Invocation;
 import org.apache.ldap.server.jndi.invocation.interceptor.Interceptor;
+import org.apache.ldap.server.jndi.invocation.interceptor.InterceptorContext;
 import org.apache.ldap.server.jndi.invocation.interceptor.NextInterceptor;
 
 /**
@@ -63,6 +70,76 @@
     {
     }
 
+    public void init( InterceptorContext ctx ) throws NamingException
+    {
+        /*
+         * Create and add the Authentication service interceptor to before
+         * interceptor chain.
+         */
+        boolean allowAnonymous = !ctx.getEnvironment().containsKey( EnvKeys.DISABLE_ANONYMOUS );
+
+        // create authenticator context
+        AuthenticatorContext authenticatorContext = new AuthenticatorContext();
+        authenticatorContext.setPartitionNexus( ctx.getRootNexus() );
+        authenticatorContext.setAllowAnonymous( allowAnonymous );
+
+        try // initialize default authenticators
+        {
+            // create anonymous authenticator
+            AuthenticatorConfig authenticatorConfig = new AuthenticatorConfig();
+            authenticatorConfig.setAuthenticatorName( "none" );
+            authenticatorConfig.setAuthenticatorContext( authenticatorContext );
+
+            org.apache.ldap.server.auth.Authenticator authenticator = new AnonymousAuthenticator();
+            authenticator.init( authenticatorConfig );
+            this.register( authenticator );
+
+            // create simple authenticator
+            authenticatorConfig = new AuthenticatorConfig();
+            authenticatorConfig.setAuthenticatorName( "simple" );
+            authenticatorConfig.setAuthenticatorContext( authenticatorContext );
+
+            authenticator = new SimpleAuthenticator();
+            authenticator.init( authenticatorConfig );
+            this.register( authenticator );
+        }
+        catch ( Exception e )
+        {
+            throw new NamingException( e.getMessage() );
+        }
+
+        AuthenticatorConfig[] configs = null;
+        configs = AuthenticatorConfigBuilder
+                .getAuthenticatorConfigs( new Hashtable( ctx.getEnvironment() ) );
+
+        for ( int ii = 0; ii < configs.length; ii++ )
+        {
+            try
+            {
+                configs[ii].setAuthenticatorContext( authenticatorContext );
+
+                String authenticatorClass = configs[ii].getAuthenticatorClass();
+                Class clazz = Class.forName( authenticatorClass );
+                Constructor constructor = clazz.getConstructor( new Class[] { } );
+
+                AbstractAuthenticator authenticator = ( AbstractAuthenticator ) constructor.newInstance( new Object[] { } );
+                authenticator.init( configs[ii] );
+
+                this.register( authenticator );
+            }
+            catch ( Exception e )
+            {
+                e.printStackTrace();
+            }
+        }
+
+    }
+    
+    public void destroy()
+    {
+        authenticators.clear();
+    }
+
     /**
      * Registers an Authenticator with this AuthenticatorService.  Called by each
      * Authenticator implementation after it has started to register for
@@ -112,14 +189,6 @@
         return (Collection)authenticators.get( type );
     }
     
-    public void init( Properties config )
-    {
-    }
-    
-    public void destroy()
-    {
-    }
-
     public void process( NextInterceptor nextProcessor, Invocation call ) throws NamingException
     {
         // check if we are already authenticated and if so we return making

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/CoreContextFactory.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/CoreContextFactory.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/CoreContextFactory.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/CoreContextFactory.java Tue Mar 22 01:39:07 2005
@@ -44,23 +44,16 @@
 import org.apache.ldap.server.ContextPartitionConfig;
 import org.apache.ldap.server.RootNexus;
 import org.apache.ldap.server.SystemPartition;
-import org.apache.ldap.server.auth.AbstractAuthenticator;
-import org.apache.ldap.server.auth.AnonymousAuthenticator;
-import org.apache.ldap.server.auth.AuthenticatorConfig;
-import org.apache.ldap.server.auth.AuthenticatorContext;
-import org.apache.ldap.server.auth.SimpleAuthenticator;
 import org.apache.ldap.server.db.Database;
 import org.apache.ldap.server.db.DefaultSearchEngine;
 import org.apache.ldap.server.db.ExpressionEnumerator;
 import org.apache.ldap.server.db.ExpressionEvaluator;
 import org.apache.ldap.server.db.SearchEngine;
 import org.apache.ldap.server.db.jdbm.JdbmDatabase;
-import org.apache.ldap.server.jndi.invocation.interceptor.Authorizer;
-import org.apache.ldap.server.jndi.invocation.interceptor.OperationalAttributeInterceptor;
-import org.apache.ldap.server.jndi.invocation.interceptor.SchemaManager;
-import org.apache.ldap.server.jndi.invocation.interceptor.Validator;
+import org.apache.ldap.server.jndi.invocation.interceptor.Interceptor;
+import org.apache.ldap.server.jndi.invocation.interceptor.InterceptorChain;
+import org.apache.ldap.server.jndi.invocation.interceptor.InterceptorContext;
 import org.apache.ldap.server.schema.AttributeTypeRegistry;
-import org.apache.ldap.server.schema.ConcreteNameComponentNormalizer;
 import org.apache.ldap.server.schema.GlobalRegistries;
 import org.apache.ldap.server.schema.MatchingRuleRegistry;
 import org.apache.ldap.server.schema.OidRegistry;
@@ -497,131 +490,21 @@
         // --------------------------------------------------------------------
         // Adding interceptors
         // --------------------------------------------------------------------
-        addDefaultInterceptors();
+        Interceptor interceptor = (Interceptor) initialEnv.get( EnvKeys.INTERCEPTOR );
+        if( interceptor == null ) {
+            // If custom interceptor is not specified, use defaule one.
+            interceptor = InterceptorChain.newDefaultChain();
+        }
+        // FIXME interceptor config is passed incorrectly
+        interceptor.init( new InterceptorContext(
+                initialEnv, system, globalRegistries, nexus, initialEnv ) );
+        provider.setInterceptor( interceptor );
 
         // fire up the app partitions now!
         if ( initialEnv.get( EnvKeys.PARTITIONS ) != null )
         {
             startUpAppPartitions( wkdir );
         }
-    }
-    
-    private void addDefaultInterceptors() throws NamingException
-    {
-        addAuthenticator();
-        addAuthorizer();
-        addValidator();
-        addSchemaManager();
-        addDefaultAttributeTagger();
-    }
-    
-    private void addAuthenticator() throws NamingException
-    {
-        /*
-         * Create and add the Authentication service interceptor to before
-         * interceptor chain.
-         */
-        boolean allowAnonymous = !initialEnv.containsKey( EnvKeys.DISABLE_ANONYMOUS );
-        Authenticator authenticationService = new Authenticator();
-
-        // create authenticator context
-        AuthenticatorContext authenticatorContext = new AuthenticatorContext();
-        authenticatorContext.setRootNexus( nexus );
-        authenticatorContext.setAllowAnonymous( allowAnonymous );
-
-        try // initialize default authenticators
-        {
-            // create anonymous authenticator
-            AuthenticatorConfig authenticatorConfig = new AuthenticatorConfig();
-            authenticatorConfig.setAuthenticatorName( "none" );
-            authenticatorConfig.setAuthenticatorContext( authenticatorContext );
-
-            org.apache.ldap.server.auth.Authenticator authenticator = new AnonymousAuthenticator();
-            authenticator.init( authenticatorConfig );
-            authenticationService.register( authenticator );
-
-            // create simple authenticator
-            authenticatorConfig = new AuthenticatorConfig();
-            authenticatorConfig.setAuthenticatorName( "simple" );
-            authenticatorConfig.setAuthenticatorContext( authenticatorContext );
-
-            authenticator = new SimpleAuthenticator();
-            authenticator.init( authenticatorConfig );
-            authenticationService.register( authenticator );
-        }
-        catch ( Exception e )
-        {
-            throw new NamingException( e.getMessage() );
-        }
-
-        AuthenticatorConfig[] configs = null;
-        configs = AuthenticatorConfigBuilder
-                .getAuthenticatorConfigs( initialEnv );
-
-        for ( int ii = 0; ii < configs.length; ii++ )
-        {
-            try
-            {
-                configs[ii].setAuthenticatorContext( authenticatorContext );
-
-                String authenticatorClass = configs[ii].getAuthenticatorClass();
-                Class clazz = Class.forName( authenticatorClass );
-                Constructor constructor = clazz.getConstructor( new Class[] { } );
-
-                AbstractAuthenticator authenticator = ( AbstractAuthenticator ) constructor.newInstance( new Object[] { } );
-                authenticator.init( configs[ii] );
-
-                authenticationService.register( authenticator );
-            }
-            catch ( Exception e )
-            {
-                e.printStackTrace();
-            }
-        }
-        
-        provider.getInterceptorChain().addLast( "authenticator", authenticationService );
-    }
-
-    private void addAuthorizer() throws NamingException
-    {
-        /*
-         * Create and add the Authorization service interceptor to before
-         * interceptor chain.
-         */
-
-        AttributeTypeRegistry atr = globalRegistries.getAttributeTypeRegistry();
-        ConcreteNameComponentNormalizer normalizer = new ConcreteNameComponentNormalizer( atr );
-        Authorizer authorizer = new Authorizer( normalizer );
-        provider.getInterceptorChain().addLast( "authorizer", authorizer );
-    }
-    
-    private void addValidator()
-    {
-        /*
-         * Create and add the Eve Exception service interceptor to both the
-         * before and onError interceptor chains.
-         */
-        Validator validator = new Validator( nexus );
-        provider.getInterceptorChain().addLast( "validator", validator );
-    }
-    
-    private void addSchemaManager() throws NamingException
-    {
-        /*
-         * Create and add the Eve schema service interceptor to before chain.
-         */
-        SchemaManager schemaManager = new SchemaManager( nexus, globalRegistries );
-        provider.getInterceptorChain().addLast( "schemaManager", schemaManager );
-    }
-    
-    private void addDefaultAttributeTagger()
-    {
-        /*
-         * Create and add the Eve operational attribute managment service
-         * interceptor to both the before and after interceptor chains.
-         */
-        OperationalAttributeInterceptor tagger = new OperationalAttributeInterceptor( nexus, globalRegistries );
-        provider.getInterceptorChain().addLast( "defaultAttributeTagger", tagger );
     }
 
     /**

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/EnvKeys.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/EnvKeys.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/EnvKeys.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/EnvKeys.java Tue Mar 22 01:39:07 2005
@@ -52,6 +52,15 @@
     /** the envprop key base to the properties of an authenticator */
     public static final String AUTHENTICATOR_PROPERTIES = "server.authenticator.properties.";
 
+    /**
+     * bootstrap property: {@link Interceptor} or {@link InterceptorChain}
+     * that will intercept directory operations when they are invoked.  You
+     * don't need to specify this property if you want to use the default
+     * interceptor chain.  If you specify this property, you might have to
+     * add some default interceptors in <tt>org.apache.ldap.server.jndi.invocation.interceptor</tt>
+     * package in your custom interceptor chain. 
+     */
+    public static final String INTERCEPTOR = "server.interceptor";
 
     // ------------------------------------------------------------------------
     // Properties for protocol/network settings

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/JndiProvider.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/JndiProvider.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/JndiProvider.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/JndiProvider.java Tue Mar 22 01:39:07 2005
@@ -35,11 +35,11 @@
 import org.apache.ldap.server.PartitionNexus;
 import org.apache.ldap.server.RootNexus;
 import org.apache.ldap.server.jndi.invocation.Add;
-import org.apache.ldap.server.jndi.invocation.Invocation;
 import org.apache.ldap.server.jndi.invocation.Delete;
 import org.apache.ldap.server.jndi.invocation.GetMatchedDN;
 import org.apache.ldap.server.jndi.invocation.GetSuffix;
 import org.apache.ldap.server.jndi.invocation.HasEntry;
+import org.apache.ldap.server.jndi.invocation.Invocation;
 import org.apache.ldap.server.jndi.invocation.IsSuffix;
 import org.apache.ldap.server.jndi.invocation.List;
 import org.apache.ldap.server.jndi.invocation.ListSuffixes;
@@ -51,6 +51,7 @@
 import org.apache.ldap.server.jndi.invocation.Move;
 import org.apache.ldap.server.jndi.invocation.MoveAndModifyRN;
 import org.apache.ldap.server.jndi.invocation.Search;
+import org.apache.ldap.server.jndi.invocation.interceptor.Interceptor;
 import org.apache.ldap.server.jndi.invocation.interceptor.InterceptorChain;
 
 
@@ -65,8 +66,8 @@
     /** Singleton instance of this class */
     private static JndiProvider s_singleton;
     
-    /** The interceptor chain for this provider */
-    private InterceptorChain interceptors;
+    /** The interceptor (or interceptor chain) for this provider */
+    private Interceptor interceptor;
     /** RootNexus as it was given to us by the ServiceManager */
     private RootNexus nexus;
     /** PartitionNexus proxy wrapping nexus to inject services */
@@ -98,7 +99,7 @@
 
         s_singleton = this;
         this.nexus = nexus;
-        this.interceptors = new InterceptorChain( nexus );
+        this.interceptor = new InterceptorChain();
         this.proxy = new PartitionNexusImpl();
     }
 
@@ -161,20 +162,30 @@
         this.nexus.close();
         this.nexus = null;
         this.proxy = null;
-        this.interceptors.clear();
+        this.interceptor.destroy();
+        this.interceptor = null;
         this.isShutdown = true;
         s_singleton = null;
     }
     
-    public InterceptorChain getInterceptorChain()
+    public Interceptor getInterceptor()
     {
-        return interceptors;
+        return interceptor;
+    }
+
+    public void setInterceptor( Interceptor interceptor )
+    {
+        if( interceptor == null )
+        {
+            throw new NullPointerException( "interceptor" );
+        }
+        this.interceptor = interceptor;
     }
 
 
     public Object invoke( Invocation call ) throws NamingException
     {
-        interceptors.process( call );
+        interceptor.process( null, call );
         return call.getResponse();
     }
 

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Authorizer.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Authorizer.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Authorizer.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Authorizer.java Tue Mar 22 01:39:07 2005
@@ -16,9 +16,6 @@
  */
 package org.apache.ldap.server.jndi.invocation.interceptor;
 
-
-import java.util.Properties;
-
 import javax.naming.Name;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
@@ -30,14 +27,14 @@
 
 import org.apache.ldap.common.exception.LdapNoPermissionException;
 import org.apache.ldap.common.name.DnParser;
-import org.apache.ldap.common.name.NameComponentNormalizer;
+import org.apache.ldap.server.BackingStore;
 import org.apache.ldap.server.SystemPartition;
 import org.apache.ldap.server.db.ResultFilteringEnumeration;
 import org.apache.ldap.server.db.SearchResultFilter;
 import org.apache.ldap.server.jndi.ServerContext;
-import org.apache.ldap.server.jndi.invocation.Invocation;
 import org.apache.ldap.server.jndi.invocation.Delete;
 import org.apache.ldap.server.jndi.invocation.HasEntry;
+import org.apache.ldap.server.jndi.invocation.Invocation;
 import org.apache.ldap.server.jndi.invocation.List;
 import org.apache.ldap.server.jndi.invocation.Lookup;
 import org.apache.ldap.server.jndi.invocation.LookupWithAttrIds;
@@ -47,6 +44,8 @@
 import org.apache.ldap.server.jndi.invocation.Move;
 import org.apache.ldap.server.jndi.invocation.MoveAndModifyRN;
 import org.apache.ldap.server.jndi.invocation.Search;
+import org.apache.ldap.server.schema.AttributeTypeRegistry;
+import org.apache.ldap.server.schema.ConcreteNameComponentNormalizer;
 
 
 /**
@@ -71,23 +70,20 @@
     private static final Name GROUP_BASE_DN = SystemPartition.getGroupsBaseDn();
 
     /** the name parser used by this service */
-    private final DnParser dnParser;
+    private DnParser dnParser; 
 
 
     /**
      * Creates an authorization service interceptor.
-     *
-     * @param normalizer a schema enabled name component normalizer
-     * @param filterService a {@link FilterService} to register filters with
      */
-    public Authorizer( NameComponentNormalizer normalizer )
-            throws NamingException
+    public Authorizer()
     {
-        this.dnParser = new DnParser( normalizer );
     }
     
-    public void init( Properties config )
+    public void init( InterceptorContext ctx ) throws NamingException
     {
+        AttributeTypeRegistry atr = ctx.getGlobalRegistries().getAttributeTypeRegistry();
+        dnParser = new DnParser( new ConcreteNameComponentNormalizer( atr ) );
     }
     
     public void destroy()

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Interceptor.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Interceptor.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Interceptor.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Interceptor.java Tue Mar 22 01:39:07 2005
@@ -16,10 +16,9 @@
  */
 package org.apache.ldap.server.jndi.invocation.interceptor;
 
-import java.util.Properties;
-
 import javax.naming.NamingException;
 
+import org.apache.ldap.server.BackingStore;
 import org.apache.ldap.server.jndi.invocation.Invocation;
 
 /**
@@ -96,10 +95,10 @@
      * @param config the configuration properties for this interceptor
      * @throws NamingException if failed to initialize this interceptor
      */
-    void init( Properties config ) throws NamingException;
+    void init( InterceptorContext context ) throws NamingException;
 
     /**
-     * Deinitialized this interceptor.  This is invoked by directory service
+     * Deinitializes this interceptor.  This is invoked by directory service
      * provider when this intercepter is unloaded from interceptor chain.
      */
     void destroy();

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorChain.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorChain.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorChain.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorChain.java Tue Mar 22 01:39:07 2005
@@ -18,17 +18,20 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-import java.util.Properties;
 
 import javax.naming.NamingException;
 
-import org.apache.ldap.server.BackingStore;
+import org.apache.ldap.server.jndi.Authenticator;
 import org.apache.ldap.server.jndi.invocation.Invocation;
 
 /**
- * Manages the chain of {@link Interceptor}s.
+ * Manages the chain of {@link Interceptor}s.  <tt>InterceptorChain</tt> is
+ * also an {@link Interceptor}, and thus you can create hiararchical interceptor
+ * structure to break down complex interceptors.
  * <p>
  * {@link org.apache.ldap.server.jndi.JndiProvider#invoke(Invocation)}
  * redirects {@link Invocation}s to {@link #process(Invocation)} and
@@ -38,13 +41,43 @@
  * @author Trustin Lee (trustin@apache.org)
  * @version $Rev$, $Date$
  */
-public class InterceptorChain
+public class InterceptorChain implements Interceptor
 {
+    /**
+     * 'Preprocess chain' passes the invocation to the next interceptor
+     * of the parent chain after processing children.
+     */
+    public static final ChainType PREPROCESS = new ChainType();
+
+    /**
+     * 'Postprocess chain' passes the invocation to the next interceptor
+     * of the parent chain before processing children.
+     */
+    public static final ChainType POSTPROCESS = new ChainType();
+    
+    public static InterceptorChain newDefaultChain()
+    {
+        return newDefaultChain( PREPROCESS );
+    }
+    
+    public static InterceptorChain newDefaultChain( ChainType type )
+    {
+        InterceptorChain chain = new InterceptorChain( type );
+        chain.addLast( "authenticator", new Authenticator() );
+        chain.addLast( "authorizer", new Authorizer() );
+        chain.addLast( "validator", new Validator() );
+        chain.addLast( "schemaManager", new SchemaManager() );
+        chain.addLast( "operationalAttributeInterceptor", new OperationalAttributeInterceptor() );
+        return chain;
+    }
+    
     private final Interceptor FINAL_INTERCEPTOR = new Interceptor()
     {
-        public void init(Properties config) throws NamingException
+        private InterceptorContext ctx;
+        
+        public void init(InterceptorContext context) throws NamingException
         {
-            // unused
+            ctx = context;
         }
 
         public void destroy()
@@ -55,26 +88,103 @@
         public void process(NextInterceptor nextInterceptor, Invocation call)
                 throws NamingException
         {
-            call.execute( store );
+            if( parent == null )
+            {
+                // execute the actual backend operation only when this chain
+                // is root.
+                call.execute( ctx.getRootNexus() );
+            }
         }
     };
 
-    private final BackingStore store;
+    private InterceptorChain parent;
+    private final ChainType type;
     private final Map name2entry = new HashMap();
     private Entry head = new Entry( null, null, "end", FINAL_INTERCEPTOR );
     private final Entry tail = head;
 
     /**
-     * Create a new interceptor chain.
+     * Create a new interceptor chain whose type is {@link #PREPROCESS}.
      */
-    public InterceptorChain( BackingStore store )
+    public InterceptorChain()
     {
-        if( store == null )
+        this( PREPROCESS );
+    }
+    
+    /**
+     * Creates a new interceptor chain with the specified chain type.
+     */
+    public InterceptorChain( ChainType type )
+    {
+        if( type == null )
         {
-            throw new NullPointerException( "store" ) ;
+            throw new NullPointerException( "type" );
+        }
+
+        this.type = type;
+    }
+    
+    /**
+     * Initializes all interceptors this chain contains.
+     */
+    public synchronized void init( InterceptorContext context ) throws NamingException
+    {
+        ListIterator it = getAll().listIterator();
+        Interceptor interceptor = null;
+        try
+        {
+            while( it.hasNext() )
+            {
+                interceptor = ( Interceptor ) it.next();
+                interceptor.init( context );
+            }
+        }
+        catch( Throwable t )
+        {
+            while( it.hasPrevious() )
+            {
+                Interceptor i = ( Interceptor ) it.previous();
+                try
+                {
+                    i.destroy();
+                }
+                catch( Throwable t2 )
+                {
+                    t2.printStackTrace();
+                }
+            }
+            
+            if( t instanceof NamingException )
+            {
+                throw ( NamingException ) t;
+            }
+            else
+            {
+                throw new InterceptorException( 
+                        interceptor, null,
+                        "Failed to initialize interceptor chain.", t );
+            }
+        }
+    }
+    
+    /**
+     * Deinitializes all interceptors this chain contains.
+     */
+    public synchronized void destroy()
+    {
+        ListIterator it = getAllReversed().listIterator();
+        while( it.hasNext() )
+        {
+            Interceptor interceptor = ( Interceptor ) it.next();
+            try
+            {
+                interceptor.destroy();
+            }
+            catch( Throwable t )
+            {
+                t.printStackTrace();
+            }
         }
-        
-        this.store = store;
     }
 
     /**
@@ -100,13 +210,13 @@
     public synchronized void addFirst( String name,
                                        Interceptor interceptor )
     {
-        checkNewName( name );
+        checkAddable( name, interceptor );
         
         Entry newEntry = new Entry( null, head, name, interceptor );
         head.prevEntry = newEntry;
         head = newEntry;
 
-        name2entry.put( name, newEntry );
+        register(name, newEntry);
     }
 
     /**
@@ -116,7 +226,7 @@
     public synchronized void addLast( String name,
                                       Interceptor interceptor )
     {
-        checkNewName( name );
+        checkAddable( name, interceptor );
         
         Entry newEntry = new Entry( tail.prevEntry, tail, name, interceptor );
         if( tail.prevEntry != null )
@@ -129,7 +239,7 @@
         }
         tail.prevEntry = newEntry;
         
-        name2entry.put( name, newEntry );
+        register(name, newEntry);
     }
 
     /**
@@ -141,7 +251,7 @@
                                         Interceptor interceptor )
     {
         Entry baseEntry = checkOldName( baseName );
-        checkNewName( name );
+        checkAddable( name, interceptor );
 
         Entry prevEntry = baseEntry.prevEntry;
         Entry newEntry = new Entry( prevEntry, baseEntry, name, interceptor );
@@ -155,7 +265,7 @@
             prevEntry.nextEntry = newEntry;
         }
         
-        name2entry.put( name, newEntry );
+        register(name, newEntry);
     }
     
     /**
@@ -167,7 +277,7 @@
                                        Interceptor interceptor )
     {
         Entry baseEntry = checkOldName( baseName );
-        checkNewName(name);
+        checkAddable( name, interceptor );
 
         Entry nextEntry = baseEntry.nextEntry;
         Entry newEntry = new Entry( baseEntry, nextEntry, name, interceptor );
@@ -178,7 +288,7 @@
 
         nextEntry.prevEntry.nextEntry = newEntry;
         nextEntry.prevEntry = newEntry;
-        name2entry.put( name, newEntry );
+        register(name, newEntry);
     }
     
     /**
@@ -199,6 +309,13 @@
             prevEntry.nextEntry = nextEntry;
             nextEntry.prevEntry = prevEntry;
         }
+
+        name2entry.remove( name );
+        Interceptor interceptor = entry.interceptor;
+        if( interceptor instanceof InterceptorChain )
+        {
+            ( ( InterceptorChain ) interceptor ).parent = null;
+        }
     }
 
     /**
@@ -206,9 +323,20 @@
      */
     public synchronized void clear()
     {
-        tail.prevEntry = null;
-        tail.nextEntry = null;
-        head = tail;
+        Iterator it = new ArrayList( name2entry.keySet() ).iterator();
+        while( it.hasNext() )
+        {
+            this.remove( ( String ) it.next() );
+        }
+    }
+
+    private void register(String name, Entry newEntry) {
+        Interceptor interceptor = newEntry.interceptor;
+        name2entry.put( name, newEntry );
+        if( interceptor instanceof InterceptorChain )
+        {
+            ( ( InterceptorChain ) interceptor ).parent = this;
+        }
     }
 
 	/**
@@ -232,13 +360,22 @@
 	 * Checks the specified interceptor name is already taken and throws
 	 * an exception if already taken.
 	 */
-    private void checkNewName( String name )
+    private void checkAddable( String name, Interceptor interceptor )
     {
         if( name2entry.containsKey( name ) )
         {
             throw new IllegalArgumentException(
                     "Other interceptor is using name '" + name + "'" );
         }
+        
+        if( interceptor instanceof InterceptorChain )
+        {
+            if ( ( ( InterceptorChain ) interceptor ).parent != null )
+            {
+                throw new IllegalArgumentException(
+                        "This interceptor chain has its parent already." );
+            }
+        }
     }
     
     /**
@@ -246,13 +383,28 @@
      * 
      * @throws NamingException if invocation failed
      */
-    public void process( Invocation call ) throws NamingException
+    public void process( NextInterceptor nextInterceptor, Invocation invocation ) throws NamingException
     {
         Entry head = this.head;
         try
         {
-            head.interceptor.process(
-                    head.nextInterceptor, call );
+            if( type == PREPROCESS )
+            {
+                head.interceptor.process( head.nextInterceptor, invocation );
+                if( nextInterceptor != null )
+                {
+                    nextInterceptor.process( invocation );
+                }
+            }
+            else // POSTPROCESS
+            {
+                if( nextInterceptor != null )
+                {
+                    nextInterceptor.process( invocation );
+                }
+                head.interceptor.process( head.nextInterceptor, invocation );
+            }
+            
         }
         catch( NamingException ne )
         {
@@ -260,7 +412,7 @@
         }
         catch( Throwable e )
         {
-            throw new InterceptorException( head.interceptor, call,
+            throw new InterceptorException( head.interceptor, invocation,
                                             "Unexpected exception.", e );
         }
     }
@@ -349,6 +501,17 @@
                     }
                 }
             };
+        }
+    }
+    
+    /**
+     * Represents how {@link InterceptorChain} interacts with
+     * {@link NextInterceptor}.
+     */
+    public static class ChainType
+    {
+        private ChainType()
+        {
         }
     }
 }

Added: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorContext.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorContext.java?view=auto&rev=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorContext.java (added)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorContext.java Tue Mar 22 01:39:07 2005
@@ -0,0 +1,61 @@
+package org.apache.ldap.server.jndi.invocation.interceptor;
+
+import java.util.Map;
+
+import org.apache.ldap.server.RootNexus;
+import org.apache.ldap.server.SystemPartition;
+import org.apache.ldap.server.schema.GlobalRegistries;
+
+public class InterceptorContext {
+
+    /** the initial context environment that fired up the backend subsystem */
+    private final Map environment;
+    
+    /** Configuration for the interceptor. */
+    private final Map config;
+
+    /** the system partition used by the context factory */
+    private final SystemPartition systemPartition;
+
+    /** the registries for system schema objects */
+    private final GlobalRegistries globalRegistries;
+
+    /** the root nexus */
+    private final RootNexus rootNexus;
+
+    public InterceptorContext( Map environment,
+                               SystemPartition systemPartition,
+                               GlobalRegistries globalRegistries,
+                               RootNexus rootNexus,
+                               Map config )
+    {
+        this.environment = environment;
+        this.systemPartition = systemPartition;
+        this.globalRegistries = globalRegistries;
+        this.rootNexus = rootNexus;
+        this.config = config;
+    }
+
+    public Map getEnvironment() {
+        return environment;
+    }
+    
+    public Map getConfig() {
+        return config;
+    }
+    
+
+    public GlobalRegistries getGlobalRegistries() {
+        return globalRegistries;
+    }
+    
+
+    public RootNexus getRootNexus() {
+        return rootNexus;
+    }
+    
+
+    public SystemPartition getSystemPartition() {
+        return systemPartition;
+    }
+}

Propchange: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/InterceptorContext.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/OperationalAttributeInterceptor.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/OperationalAttributeInterceptor.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/OperationalAttributeInterceptor.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/OperationalAttributeInterceptor.java Tue Mar 22 01:39:07 2005
@@ -18,7 +18,6 @@
 
 
 import java.util.HashSet;
-import java.util.Properties;
 
 import javax.naming.Name;
 import javax.naming.NamingEnumeration;
@@ -48,7 +47,6 @@
 import org.apache.ldap.server.jndi.invocation.MoveAndModifyRN;
 import org.apache.ldap.server.jndi.invocation.Search;
 import org.apache.ldap.server.schema.AttributeTypeRegistry;
-import org.apache.ldap.server.schema.GlobalRegistries;
 
 
 /**
@@ -80,36 +78,23 @@
     };
 
     /** the root nexus of the system */
-    private final RootNexus nexus;
-    private final AttributeTypeRegistry registry;
+    private RootNexus nexus;
+    private AttributeTypeRegistry registry;
 
 
     /**
      * Creates the operational attribute management service interceptor.
-     *
-     * @param nexus the root nexus of the system
-     * @param globalRegistries the global schema object registries
      */
-    public OperationalAttributeInterceptor( RootNexus nexus,
-                                            GlobalRegistries globalRegistries )
+    public OperationalAttributeInterceptor()
     {
-        this.nexus = nexus;
-        if ( this.nexus == null )
-        {
-            throw new NullPointerException( "the nexus cannot be null" );
-        }
-
-        if ( globalRegistries == null )
-        {
-            throw new NullPointerException( "the global registries cannot be null" );
-        }
-        this.registry = globalRegistries.getAttributeTypeRegistry();
     }
 
-    public void destroy() {
+    public void init( InterceptorContext ctx ) throws NamingException {
+        nexus = ctx.getRootNexus();
+        registry = ctx.getGlobalRegistries().getAttributeTypeRegistry();
     }
 
-    public void init(Properties config) throws NamingException {
+    public void destroy() {
     }
 
     /**

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/SchemaManager.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/SchemaManager.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/SchemaManager.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/SchemaManager.java Tue Mar 22 01:39:07 2005
@@ -20,7 +20,6 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.Properties;
 import java.util.Set;
 
 import javax.naming.NamingEnumeration;
@@ -73,14 +72,14 @@
     private static final String BINARY_KEY = "java.naming.ldap.attributes.binary";
 
     /** the root nexus to all database partitions */
-    private final RootNexus nexus;
+    private RootNexus nexus;
     /** a binary attribute tranforming filter: String -> byte[] */
-    private final BinaryAttributeFilter binaryAttributeFilter;
+    private BinaryAttributeFilter binaryAttributeFilter;
     /** the global schema object registries */
-    private final GlobalRegistries globalRegistries;
-    private final AttributeTypeRegistry attributeRegistry;
+    private GlobalRegistries globalRegistries;
+    private AttributeTypeRegistry attributeRegistry;
     /** subschemaSubentry attribute's value from Root DSE */
-    private final String subentryDn;
+    private String subentryDn;
 
 
     /**
@@ -90,31 +89,20 @@
      * @param globalRegistries the global schema object registries
      * @param filterService
      */
-    public SchemaManager( RootNexus nexus, GlobalRegistries globalRegistries )
-            throws NamingException
+    public SchemaManager()
     {
-        this.nexus = nexus;
-        if ( this.nexus == null )
-        {
-            throw new NullPointerException( "the nexus cannot be null" );
-        }
-
-        this.globalRegistries = globalRegistries;
-        if ( this.globalRegistries == null )
-        {
-            throw new NullPointerException( "the global registries cannot be null" );
-        }
+    }
 
+    public void init( InterceptorContext ctx ) throws NamingException
+    {
+        this.nexus = ctx.getRootNexus();
+        this.globalRegistries = ctx.getGlobalRegistries();
         attributeRegistry = globalRegistries.getAttributeTypeRegistry();
         binaryAttributeFilter = new BinaryAttributeFilter();
 
         // stuff for dealing with subentries (garbage for now)
         String subschemaSubentry = ( String ) nexus.getRootDSE().get( "subschemaSubentry" ).get();
         subentryDn = new LdapName( subschemaSubentry ).toString().toLowerCase();
-    }
-
-    public void init( Properties config )
-    {
     }
     
     public void destroy()

Modified: directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Validator.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Validator.java?view=diff&r1=158585&r2=158586
==============================================================================
--- directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Validator.java (original)
+++ directory/apacheds/branches/interceptor_revamp/core/src/main/java/org/apache/ldap/server/jndi/invocation/interceptor/Validator.java Tue Mar 22 01:39:07 2005
@@ -17,8 +17,6 @@
 package org.apache.ldap.server.jndi.invocation.interceptor;
 
 
-import java.util.Properties;
-
 import javax.naming.Name;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
@@ -31,6 +29,7 @@
 import org.apache.ldap.common.exception.LdapNamingException;
 import org.apache.ldap.common.message.ResultCodeEnum;
 import org.apache.ldap.common.name.LdapName;
+import org.apache.ldap.server.BackingStore;
 import org.apache.ldap.server.RootNexus;
 import org.apache.ldap.server.jndi.invocation.Add;
 import org.apache.ldap.server.jndi.invocation.Delete;
@@ -58,21 +57,19 @@
 public class Validator extends BaseInterceptor
 {
     /** the root nexus of the system */
-    private RootNexus nexus = null;
+    private RootNexus nexus;
 
 
     /**
      * Creates an interceptor that is also the exception handling service.
-     *
-     * @param nexus the root partition nexus
      */
-    public Validator( RootNexus nexus )
+    public Validator()
     {
-        this.nexus = nexus;
     }
     
-    public void init( Properties config )
+    public void init( InterceptorContext ctx )
     {
+        this.nexus = ctx.getRootNexus();
     }
 
     public void destroy()



Mime
View raw message