You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2006/03/15 15:57:17 UTC

svn commit: r386087 [2/45] - in /incubator/harmony/enhanced/classlib/trunk: make/ make/patternsets/ modules/jndi/ modules/jndi/META-INF/ modules/jndi/make/ modules/jndi/make/common/ modules/jndi/src/ modules/jndi/src/main/ modules/jndi/src/main/java/ m...

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/make/common/hyproperties.xml
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/make/common/hyproperties.xml?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/make/common/hyproperties.xml (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/make/common/hyproperties.xml Wed Mar 15 06:55:38 2006
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+  
+    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.
+-->
+
+<hy>
+   <jndi location=".">
+      <src>
+         <main>
+            <java location="src/main/java" />
+        	<resources location="src/main/resources" />
+         </main>
+         <test>
+            <java location="src/test/java" />
+            <resources location="src/main/resources" />
+         </test>
+         <natives location="src/natives" />
+      </src>
+      <bin>
+        <main location="bin/main" />
+        <test location="bin/test" />
+      </bin>
+      <packaging>
+      </packaging>
+   </jndi>
+
+   <target location="../../deploy" />
+
+   <tests>
+      <reports location="../../build/test_report" />
+   </tests>
+</hy>

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/EnvironmentReader.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/EnvironmentReader.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/EnvironmentReader.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/EnvironmentReader.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,505 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 com.ibm.jndi;
+
+import java.applet.Applet;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.naming.ConfigurationException;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+
+/**
+ * This is a utility class that reads environment properties.
+ * 
+ */
+public final class EnvironmentReader {
+
+    /*
+     * -------------------------------------------------------------------
+     * Constants
+     * -------------------------------------------------------------------
+     */
+
+    // The name of application resource files
+    private static final String APPLICATION_RESOURCE_FILE = "jndi.properties"; //$NON-NLS-1$
+
+    // The name of provider resource file
+    private static final String PROVIDER_RESOURCE_FILE = "jndiprovider.properties"; //$NON-NLS-1$
+
+    /*
+     * -------------------------------------------------------------------
+     * Constructors
+     * -------------------------------------------------------------------
+     */
+
+    // Not allowed to create an instance
+    private EnvironmentReader() {
+    	super();
+    }
+
+    /*
+     * Merge additional properties with already read ones.
+     * 
+     * @param src - the source containing additional properties
+     * @param dst - the destination to put additional properties
+     * @param valueAddToList - whether to add new values of C-type properties
+     */
+    public static void mergeEnvironment(
+        final Hashtable src,
+        final Hashtable dst,
+        final boolean valueAddToList) {
+
+        Object key = null;
+        String val = null;
+        Enumeration keys = src.keys();
+
+        while (keys.hasMoreElements()) {
+            key = keys.nextElement();
+
+            if (!dst.containsKey(key)) {
+                /*
+                 * If this property doesn't exist yet, add it.
+                 */
+                dst.put(key, src.get(key));
+            } else if (
+                valueAddToList
+                    && (LdapContext.CONTROL_FACTORIES.equals(key)
+                        || Context.OBJECT_FACTORIES.equals(key)
+                        || Context.STATE_FACTORIES.equals(key)
+                        || Context.URL_PKG_PREFIXES.equals(key))) {
+                /*
+                 * Otherwise, if this property can contain a list of values, add
+                 * the additional values if the flag "valueAddToList" is true.
+                 */
+
+                // Read the original value
+                val = (String) dst.get(key);
+                // Values are combined into a single list separated by colons. 
+                val = val + ":" + (String) src.get(key); //$NON-NLS-1$
+                // The final value becomes the resulting value of that property
+                dst.put(key, val);
+            } else {
+                /*
+                 * Otherwise, ignore the found value.
+                 */
+            }
+        }
+    }
+
+    /*
+     * Get the required 7 JNDI properties from JNDI properties source.
+     * This method is designed as package visibility to improve performance
+     * when called by anonymous inner classes.
+     * 
+     * @return a hashtable holding the required properties.
+     */
+    static Hashtable filterProperties(final JNDIPropertiesSource source) {
+        final Hashtable filteredProperties = new Hashtable();
+        Object propValue = null;
+
+        propValue = source.getProperty(Context.INITIAL_CONTEXT_FACTORY);
+        if (null != propValue) {
+            filteredProperties.put(Context.INITIAL_CONTEXT_FACTORY, propValue);
+        }
+
+        propValue = source.getProperty(Context.DNS_URL);
+        if (null != propValue) {
+            filteredProperties.put(Context.DNS_URL, propValue);
+        }
+
+        propValue = source.getProperty(Context.PROVIDER_URL);
+        if (null != propValue) {
+            filteredProperties.put(Context.PROVIDER_URL, propValue);
+        }
+
+        propValue = source.getProperty(Context.OBJECT_FACTORIES);
+        if (null != propValue) {
+            filteredProperties.put(Context.OBJECT_FACTORIES, propValue);
+        }
+
+        propValue = source.getProperty(Context.STATE_FACTORIES);
+        if (null != propValue) {
+            filteredProperties.put(Context.STATE_FACTORIES, propValue);
+        }
+
+        propValue = source.getProperty(Context.URL_PKG_PREFIXES);
+        if (null != propValue) {
+            filteredProperties.put(Context.URL_PKG_PREFIXES, propValue);
+        }
+
+        propValue = source.getProperty(LdapContext.CONTROL_FACTORIES);
+        if (null != propValue) {
+            filteredProperties.put(LdapContext.CONTROL_FACTORIES, propValue);
+        }
+
+        return filteredProperties;
+    }
+
+    /*
+     * Read the required 7 JNDI properties from system properties and merge with
+     * existing properties. Note that the values of C-type properties are only
+     * included when no corresponding value is presented in existing properties. 
+     * 
+     * @param existingProps - existing properties
+     */
+    public static void readSystemProperties(final Hashtable existingProps) {
+        /*
+         * Privileged code is used to access system properties. This is 
+         * required if JNDI is run in Applet or other applications which 
+         * only have limited permissions to access certain resources.
+         */
+        Hashtable systemProperties =
+            (Hashtable) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return filterProperties(new SystemPropertiesSource());
+            }
+        });
+        mergeEnvironment(systemProperties, existingProps, false);
+    }
+
+    /*
+     * Read the required 7 JNDI properties from applet parameters and merge with
+     * existing properties. Note that the values of C-type properties are only
+     * included when no corresponding value is presented in existing properties. 
+     * 
+     * @param applet - the applet object
+     * @param existingProps - existing properties
+     */
+    public static void readAppletParameters(Object applet, Hashtable existingProps) {
+        if (null != applet) {
+            Hashtable appletParameters =
+                filterProperties(new AppletParametersSource((Applet) applet));
+            mergeEnvironment(appletParameters, existingProps, false);
+        }
+    }
+
+    /*
+     * Read multiple resource files from the classpaths given the file name.
+     * This method is designed as package visibility to improve performance
+     * when called by anonymous inner classes.
+     * 
+     * @param name - the name of the resource file
+     * @param existingProps - existing properties, cannot be null
+     * @param filter - to filter properties
+     */
+    static Hashtable readMultipleResourceFiles(
+        final String name,
+        final Hashtable existingProps,
+        ClassLoader cl)
+        throws NamingException {
+
+        if (null == cl) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+
+        Enumeration e = null;
+        try {
+            // Load all resource files
+            e = cl.getResources(name);
+        } catch (IOException ex) {
+            // Unexpected ClassLoader exception
+            ConfigurationException newEx =
+                new ConfigurationException("Failed to load JNDI resource files."); //$NON-NLS-1$
+            newEx.setRootCause(ex);
+            throw newEx;
+        }
+
+        // Read all the loaded properties and merge
+        URL url = null;
+        InputStream is = null;
+        final Properties p = new Properties();
+        while (e.hasMoreElements()) {
+            url = (URL) e.nextElement();
+            try {
+                if (null != (is = url.openStream())) {
+                    p.load(is);
+                    mergeEnvironment(p, existingProps, true);
+                    p.clear();
+                }
+            } catch (IOException ex) {
+                // Can't read this resource file
+                ConfigurationException newEx =
+                    new ConfigurationException("Failed to read JNDI resource files."); //$NON-NLS-1$
+                newEx.setRootCause(ex);
+                throw newEx;
+            } finally {
+                try {
+                    if (null != is) {
+                        is.close();
+                    }
+                } catch (IOException ex) {
+                    // Ignore closing exception
+                } finally {
+                    is = null;
+                }
+            }
+        }
+        return existingProps;
+    }
+
+    /*
+     * Read application/applet resource files.
+     * 
+     * @param existingProps - existing properties, cannot be null.
+     */
+    public static Hashtable readApplicationResourceFiles(final Hashtable existingProps)
+        throws NamingException {
+        // Use privileged code to read the application resource files
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws NamingException {
+                    readMultipleResourceFiles(
+                        APPLICATION_RESOURCE_FILE,
+                        existingProps,
+                        Thread.currentThread().getContextClassLoader());
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            Exception rootCause = e.getException();
+            if (rootCause instanceof NamingException) {
+                throw (NamingException) rootCause;
+            } else if (rootCause instanceof RuntimeException) {
+                throw (RuntimeException) rootCause;
+            } else {
+                // This should not happen.
+            }
+        }
+        return existingProps;
+    }
+
+    /*
+     * Read the properties file "java.home"/lib/jndi.properties.
+     * Pay attention to the privileged code for accessing this external resource
+     * file. This is required if JNDI is run in Applet or other applications
+     * which only have limited permissions to access certain resources.
+     * 
+     * @param existingProps - existing properties, cannot be null.
+     */
+    public static Hashtable readLibraryResourceFile(final Hashtable existingProps)
+        throws NamingException {
+        final String sep = System.getProperty("file.separator"); //$NON-NLS-1$
+
+        String resPath = null;
+        // Construct the full filename of "java.home"/lib/jndi.properties
+        resPath = System.getProperty("java.home"); //$NON-NLS-1$
+        if (!resPath.endsWith(sep)) {
+            resPath += sep;
+        }
+        resPath += "lib" + sep + APPLICATION_RESOURCE_FILE; //$NON-NLS-1$
+
+        // Try to read this properties if it exists
+        InputStream is = null;
+        final File resFile = new File(resPath);
+        final Properties p = new Properties();
+        // Use privileged code to determine whether the file exists
+        Boolean resFileExists =
+            (Boolean) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return new Boolean(resFile.exists());
+            }
+        });
+        if (resFileExists.booleanValue()) {
+            try {
+                // Use privileged code to read the file
+                is =
+                    (
+                        FileInputStream) AccessController
+                            .doPrivileged(new PrivilegedExceptionAction() {
+                    public Object run() throws IOException {
+                        InputStream localInputStream = new FileInputStream(resFile);
+                        p.load(localInputStream);
+                        return localInputStream;
+                    }
+                });
+                mergeEnvironment(p, existingProps, true);
+            } catch (PrivilegedActionException e) {
+                // Can't read "java.home"/lib/jndi.properties
+                ConfigurationException newEx =
+                    new ConfigurationException("Failed to read JNDI resource files in java home library."); //$NON-NLS-1$
+                newEx.setRootCause(e.getException());
+                throw newEx;
+            } finally {
+                try {
+                    if (null != is) {
+                        is.close();
+                    }
+                } catch (IOException ex) {
+                    // Ignore closing exception
+                }
+            }
+        }
+        return existingProps;
+    }
+
+    /*
+     * Read the service provider resource file.
+     * 
+     * @param context - the context
+     * @param existingProps - existing properties, cannot be null.
+     */
+    public static Hashtable readProviderResourceFiles(
+        final Context context,
+        final Hashtable existingProps)
+        throws NamingException {
+
+        String factory = context.getClass().getName();
+        String resPath = null;
+        int len = factory.lastIndexOf('.');
+
+        // Construct the full filename of the service provider resource file
+        if (-1 == len) {
+            // Default package
+            resPath = PROVIDER_RESOURCE_FILE;
+        } else {
+            // Replace "." with '/' 
+            resPath = factory.substring(0, len + 1);
+            resPath = resPath.replace('.', '/');
+            resPath += PROVIDER_RESOURCE_FILE;
+        }
+
+        // Use privileged code to read the provider resource files
+        try {
+            final String finalResPath = resPath;
+            AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws NamingException {
+                    readMultipleResourceFiles(
+                        finalResPath,
+                        existingProps,
+                        context.getClass().getClassLoader());
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            Exception rootCause = e.getException();
+            if (rootCause instanceof NamingException) {
+                throw (NamingException) rootCause;
+            } else if (rootCause instanceof RuntimeException) {
+                throw (RuntimeException) rootCause;
+            } else {
+                // This should not happen.
+            }
+        }
+        return existingProps;
+    }
+
+    /*
+     * Get the list of the specified factory names from the supplied environment
+     * and the resource provider files of the given Context.
+     * 
+     * @param envmt The supplied environment.
+     * @param ctx The Context whose resource provider files will be read.
+     * @param key The name of the factory.
+     * @return The list of the desired factory names.
+     * @throws NamingException If an error occurs when reading the provider 
+     * resource files.
+     */
+    public static String[] getFactoryNamesFromEnvironmentAndProviderResource(
+        Hashtable envmt,
+        Context ctx,
+        String key)
+        throws NamingException {
+
+        ArrayList fnames = new ArrayList();
+
+        // collect tokens from envmt with key
+        if (null != envmt) {
+            String str = (String) envmt.get(key);
+            if (null != str) {
+                StringTokenizer st = new StringTokenizer(str, ":"); //$NON-NLS-1$
+                while (st.hasMoreTokens()) {
+                    fnames.add(st.nextToken());
+                }
+            }
+        }
+        // collect tokens from ctx's provider resource file
+        if (null != ctx) {
+            Hashtable h = new Hashtable();
+            // read provider resource file from ctx's package
+            EnvironmentReader.readProviderResourceFiles(ctx, h);
+            String str = (String) h.get(key);
+            if (null != str) {
+                StringTokenizer st = new StringTokenizer(str, ":"); //$NON-NLS-1$
+                while (st.hasMoreTokens()) {
+                    fnames.add(st.nextToken());
+                }
+            }
+        }
+        // if key is Context.URL_PKG_PREFIXES, append "com.sun.jndi.url" at the end
+        if (Context.URL_PKG_PREFIXES.equals(key)) {
+            fnames.add("com.sun.jndi.url"); //$NON-NLS-1$
+        }
+        // return factory names
+        return (String[]) fnames.toArray(new String[fnames.size()]);
+    }
+
+    /*
+     * Wrapper interface for JNDI properties source.
+     */
+    private interface JNDIPropertiesSource {
+        // Get a JNDI property with the specified name
+        Object getProperty(final String propName);
+    }
+
+    /*
+     * Wrapper class for system properties source.
+     */
+    private static class SystemPropertiesSource implements JNDIPropertiesSource {
+
+        public SystemPropertiesSource() {
+        	super();
+        }
+
+        public Object getProperty(final String propName) {
+            return System.getProperty(propName);
+        }
+    }
+
+    /*
+     * Wrapper class for applet parameters source.
+     */
+    private static class AppletParametersSource implements JNDIPropertiesSource {
+
+        private Applet applet;
+
+        public AppletParametersSource(Applet applet) {
+            this.applet = applet;
+        }
+
+        public Object getProperty(final String propName) {
+            return applet.getParameter(propName);
+        }
+    }
+
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/UrlParser.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/UrlParser.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/UrlParser.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/com/ibm/jndi/UrlParser.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,70 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 com.ibm.jndi;
+
+/**
+ * Identifies the simplest URL syntax: <code>{scheme}:{scheme specific part}</code>.
+ * 
+ */
+public class UrlParser {
+    
+    /*
+     * Prevent instantiate.
+     */
+    private UrlParser() {
+    	super();
+    }
+
+    /**
+     * Returns an URL's scheme part, in lower case. If the url is not a valid 
+     * URL, null is returned.
+     * 
+     * @param url   a url string
+     * @return      the URL's scheme part, in lower case. If the url is not a 
+     *              valid URL, null is returned.
+     */
+    public static String getScheme(String url) {
+        if (null == url) {
+            return null;
+        }
+        int colPos = url.indexOf(':');
+        if (colPos < 0) {
+            return null;
+        }
+        String scheme = url.substring(0, colPos);
+        char c;
+        boolean inCharSet;
+        for (int i = 0; i < scheme.length(); i++) {
+            c = scheme.charAt(i);
+            inCharSet =
+                (c >= 'A' && c <= 'Z')
+                    || (c >= 'a' && c <= 'z')
+                    || (c >= '0' && c <= '9')
+                    || c == '+'
+                    || c == '.'
+                    || c == '-'
+                    || c == '_';
+            if (!inCharSet) {
+                return null;
+            }
+        }
+        return scheme;
+    }
+
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/java/applet/Applet.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/java/applet/Applet.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/java/applet/Applet.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/java/applet/Applet.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,22 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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.
+ */
+
+/* Just a stub. */
+
+package java.applet;
+
+public class Applet {
+    public String getParameter(String s) { return null; }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationException.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationException.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationException.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationException.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,57 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 javax.naming;
+
+/**
+ * An <code>AuthenticationException</code> is the 
+ * <code>NamingSecurityException</code> used when authentication fails.
+ * <p>
+ * Multithreaded access to an <code>AuthenticationException</code> instance
+ * is only safe when client code locks the object first.</p>
+ * 
+ */
+public class AuthenticationException extends NamingSecurityException {
+
+    static final long serialVersionUID = 3678497619904568096L;
+
+    /*
+     * -------------------------------------------------------------------
+     * Constructors
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Constructs an <code>AuthenticationException</code> instance
+     * with all data initialized to null.
+     */
+    public AuthenticationException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>AuthenticationException</code> instance 
+     * using the specified message.
+     * 
+     * @param s The detail message for the exception. It may be null.
+     */
+    public AuthenticationException(String s) {
+        super(s);
+    }
+
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationNotSupportedException.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationNotSupportedException.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationNotSupportedException.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/AuthenticationNotSupportedException.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,58 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 javax.naming;
+
+/**
+ * An <code>AuthenticationNotSupportedException</code> is the 
+ * <code>NamingSecurityException</code> used
+ * when the authentication required is not available.
+ * <p>
+ * Multithreaded access to an <code>AuthenticationNotSupportedException</code> 
+ * instance is only safe when client code locks the object first.</p>
+ * 
+ */
+public class AuthenticationNotSupportedException extends NamingSecurityException {
+
+    static final long serialVersionUID = -7149033933259492300L;
+
+    /*
+     * -------------------------------------------------------------------
+     * Constructors
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Constructs an <code>AuthenticationNotSupportedException</code> instance
+     * with all data initialized to null.
+     */
+    public AuthenticationNotSupportedException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>AuthenticationNotSupportedException</code> instance
+     * using the specified message.
+     * 
+     * @param s The detail message for the exception. It may be null.
+     */
+    public AuthenticationNotSupportedException(String s) {
+        super(s);
+    }
+
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/BinaryRefAddr.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/BinaryRefAddr.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/BinaryRefAddr.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/BinaryRefAddr.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,177 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 javax.naming;
+
+import java.util.Arrays;
+
+/**
+ * A <code>BinaryRefAddr</code> refers to an address which is represented by a
+ * binary address. 
+ *
+ * 
+ */
+public class BinaryRefAddr extends RefAddr {
+
+    /*
+     * -------------------------------------------------------------------
+     * Constants
+     * -------------------------------------------------------------------
+     */
+
+    /*
+     * This constant is used during deserialization to check the J2SE version
+     * which created the serialized object.
+     */
+    static final long serialVersionUID = -3415254970957330361L; //J2SE 1.4.2
+
+    /*
+     * -------------------------------------------------------------------
+     * Instance variables
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * The buffer for the binary address itself.
+     * 
+     * @serial
+     */
+    private byte[] buf;
+
+    /*
+     * -------------------------------------------------------------------
+     * Constructors
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Constructs a <code>BinaryRefAddr</code> using the specified address type
+     * and the full details of the supplied byte array.
+     * 
+     * @param type     the address type which cannot be null
+     * @param address  the address itself which cannot be null
+     */
+    public BinaryRefAddr(String type, byte[] address) {
+        this(type, address, 0, address.length);
+    }
+
+    /**
+     * Constructs a <code>BinaryRefAddr</code> using the specified address type
+     * and part of the supplied byte array.
+     * The number of bytes to be taken is specified by <code>size</code>. 
+     * Additionally these bytes are taken from a starting point specified by 
+     * <code>index</code>.  
+     *
+     * @param type      the address type. It cannot be null.
+     * @param address   the address itself. It cannot be null.
+     * @param index     the starting point to copy bytes from. It must be 
+     *                  greater than or equal to zero and must be less than or 
+     *                  equal to the size of the byte array.
+     * @param size      the number of bytes to copy. It must be greater than or 
+     *                  equal to zero and must be less than or equal to the 
+     *                  size of the byte array less the starting position.
+     * @throws ArrayIndexOutOfBoundsException
+     *                  If <code>size</code> or <code>index</code> does not meet
+     *                  the constraints.
+     */
+    public BinaryRefAddr(String type, byte[] address, int index, int size) {
+        super(type);
+        this.buf = new byte[size];
+        System.arraycopy(address, index, this.buf, 0, size);
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods override parent class RefAddr
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Gets the content of this address.
+     * 
+     * @return          an array of bytes containing the address. 
+     *                  It cannot be null.
+     */
+    public Object getContent() {
+        return buf;
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods override parent class Object
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Returns true if this address is equal to the supplied object 
+     * <code>o</code>.
+     * They are considered equal if the address types are equal and the data in
+     * the buffers is of the same length and contains the same bytes.
+     *
+     * @param o         the object to compare with
+     * @return          true if this address is equal to <code>o</code>,
+     *                  otherwise false
+     */
+    public boolean equals(Object o) {
+        if (o instanceof BinaryRefAddr) {
+            BinaryRefAddr a = (BinaryRefAddr) o;
+            return this.addrType.equals(a.addrType)
+                && Arrays.equals(this.buf, a.buf);
+        }
+        return false;
+    }
+
+    /**
+     * Returns the hashcode of this address.
+     * The result is the hashcode of the address type added to each byte 
+     * from the data buffer.
+     * 
+     * @return          the hashcode of this address
+     */
+    public int hashCode() {
+        int i = this.addrType.hashCode();
+
+        for (int j = 0; j < this.buf.length; j++) {
+            i += this.buf[j];
+        }
+        return i;
+    }
+
+    /**
+     * Returns the string representation of this address. 
+     * The string includes the address type and a maximum of 128 bytes address
+     * content expressed in hexical form. 
+     * 
+     * @return          the string representation of this address
+     */
+    public String toString() {
+        String s =
+            "The type of the address is: " //$NON-NLS-1$
+                + this.addrType
+                + "\nThe content of the address is: "; //$NON-NLS-1$
+        int max = this.buf.length > 128 ? 128 : this.buf.length;
+
+        for (int i = 0; i < max; i++) {
+            s += Integer.toHexString(this.buf[i]) + " "; //$NON-NLS-1$
+        }
+        s = s.substring(0, s.length() - 1) + "\n"; //$NON-NLS-1$
+
+        return s;
+    }
+
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/Binding.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/Binding.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/Binding.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/Binding.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,176 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 javax.naming;
+
+/**
+ * Binding extends <code>NameClassPair</code> to associate an object in a
+ * naming service with its name, specified class name and relative flag.
+ * As with <code>NameClassPair</code>, a class name is only specified when 
+ * it is necessary to override the real class name of the associated object.
+ * <p>
+ * Multithreaded access to a <code>Binding</code> instance is only safe when 
+ * client code locks the object first.</p>
+ * 
+ */
+public class Binding extends NameClassPair {
+
+    /*
+     * -------------------------------------------------------------------
+     * Constants
+     * -------------------------------------------------------------------
+     */
+
+    // J2SE 1.4.2
+    private static final long serialVersionUID = 8839217842691845890L;
+
+    /*
+     * -------------------------------------------------------------------
+     * Instance variables
+     * -------------------------------------------------------------------
+     */
+
+    private Object boundObj;
+
+    /*
+     * -------------------------------------------------------------------
+     * Constructors
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Construct a <code>Binding</code> from a name and a class.
+     * The name and class parameters may be null.
+     * Relative flag is true.
+     *
+     * @param name  a name
+     * @param obj   an object bound with the name
+     */
+    public Binding(String name, Object obj) {
+        this(name, null, obj, true);
+    }
+
+    /**
+     * Construct a <code>Binding</code> from a name, an object and a relative
+     * flag. The name and object parameters may be null.
+     *
+     * @param name      a name
+     * @param obj       an object bound with the name
+     * @param relative  a relative flag
+     */
+    public Binding(String name, Object obj, boolean relative) {
+        this(name, null, obj, relative);
+    }
+
+    /**
+     * Construct a <code>Binding</code> from a name, a class, and an object.
+     * The name, class and object parameters may be null.
+     * Relative flag is true.
+     *
+     * @param name      a name
+     * @param className a class name
+     * @param obj       an object bound with the name
+     */
+    public Binding(String name, String className, Object obj) {
+        this(name, className, obj, true);
+    }
+
+    /**
+     * Construct a <code>Binding</code> from a name, a class, an object and a
+     * relative flag. The name, class and object parameters may be null.
+     *
+     * @param name      a name
+     * @param className a class name
+     * @param obj       an object bound with the name
+     * @param relative  a relative flag
+     */
+    public Binding(
+        String name,
+        String className,
+        Object obj,
+        boolean relative) {
+        super(name, className, relative);
+        this.boundObj = obj;
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Get the class name of this <code>Binding</code>.
+     * It may have been specified, in which case the class name field is set,
+     * and that is the string returned by this method.
+     * If the class name field has not been specified then the object 
+     * associated with this <code>Binding</code> is interrogated to find its 
+     * actual class name. If there is no class name field specified and no 
+     * associated object then this method returns null.
+     *
+     * @return the class name
+     */
+    public String getClassName() {
+        if (super.getClassName() != null) {
+            return super.getClassName();
+        }
+        if (boundObj != null) {
+            return boundObj.getClass().getName();
+        }
+        return null;
+    }
+
+    /**
+     * Get the object associated with this <code>Binding</code>. May return 
+     * null.
+     * 
+     * @return the object associated with this <code>Binding</code>. 
+     *          May return null.
+     */
+    public Object getObject() {
+        return boundObj;
+    }
+
+    /**
+     * Set the object o associated with this <code>Binding</code>. The object
+     * may be null.
+     * 
+     * @param object    an object
+     */
+    public void setObject(Object object) {
+        this.boundObj = object;
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods override parent class Object
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Provide a string representation of this object. This is the same as for
+     * <code>NameClassPair</code> but with the string representation of the 
+     * <code>Binding</code> object appended to the end.
+     * 
+     * @return a string representation of this <code>Binding</code>
+     */
+    public String toString() {
+        return super.toString() + ":" + boundObj; //$NON-NLS-1$
+    }
+
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CannotProceedException.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CannotProceedException.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CannotProceedException.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CannotProceedException.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,238 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 javax.naming;
+
+import java.util.Hashtable;
+
+/**
+ * Naming operations throw a <code>CannotProceedException</code> when the 
+ * service provider context implementation is resolving a name but reaches a 
+ * name component that does not belong to the namespace of the current context.
+ * <p>
+ * The service provider is able to create a <code>CannotProceedException</code> 
+ * object and use methods on that object (including baseclass methods) to 
+ * provide full details of how far name resolution had progressed.</p>
+ * <p>
+ * Typically, the methods used might include:
+ * <ul>
+ * <li><code>setEnvironment</code> to record the environment from the current 
+ * context</li>
+ * <li>
+ * <code>setAltNameCtx</code> to record the current context</li>
+ * <li>
+ * <code>setResolvedObj</code> to record the resolved object for the next 
+ * naming system</li>
+ * <li>
+ * <code>setAltName</code> to record the name of the resolved object</li>
+ * <li>
+ * <code>setRemainingName</code> to record the remaining unresolved name</li>
+ * </ul></p>
+ * <p>
+ * If the incomplete naming operation is <code>rename</code>, the service 
+ * provider should also use the <code>setRemainingNewName</code> method to 
+ * record the unresolved part of the new name.</p>
+ * <p>
+ * The service provider can pass the <code>CannotProceedException</code> as a 
+ * parameter to <code>NamingManager</code> methods such as 
+ * <code>getContinuationContext</code> to attempt to locate another service 
+ * provider for the next naming system. If successful, that service provider 
+ * can return a new <code>Context</code> object on which the naming operation
+ * can proceed further. If unsuccessful, the <code>CannotProceedException</code>
+ * can be thrown by the service provider so that the JNDI application can
+ * handle it and take appropriate action.</p>
+ * <p>
+ * Multithreaded access to a single <code>CannotProceedException</code> 
+ * instance is only safe when client code uses appropriate synchronization 
+ * and locking.</p>
+ * 
+ */
+public class CannotProceedException extends NamingException {
+
+    /*
+     * -----------------------------------------
+     * Constants
+     * -----------------------------------------
+     */
+    
+    /*
+     * This constant is used during deserialization to check the J2SE version
+     * which created the serialized object.
+     */
+    private final static long serialVersionUID = 1219724816191576813L;
+
+    /*
+     * -------------------------------------------------------------------
+     * Instance variables
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Contains a composite name that is the name of the resolved object which
+     * is relative to the context in <code>altNameCtx</code>. This field may 
+     * be null and is initially null. This field should be accessed and 
+     * modified using only <code>getAltName</code> and <code>setAltName</code>.
+     */
+    protected Name altName = null;
+
+    /**
+     * Contains the context to which the <code>altName</code> field is relative.
+     * This field may be null and is initially null. A null value implies the 
+     * default initial context.  This field should be accessed and modified 
+     * using only <code>getAltNameCtx</code> and <code>setAltNameCtx</code>.
+     */
+    protected Context altNameCtx = null;
+
+    /**
+     * Contains the environment of the context in which name resolution for the
+     * naming operation could not proceed further. Initially null. Should only
+     * be manipulated using <code>getEnvironment</code> 
+     * and <code>setEnvironment methods</code>. 
+     */
+    protected Hashtable environment = null;
+
+    /**
+     * Contains a composite name that is the unresolved part of the new name 
+     * that was specified in a <code>Context.rename</code> operation and may 
+     * be used to continue the <code>rename</code> operation. This field may 
+     * be null and is initially null. This field should be accessed and 
+     * modified using only <code>getRemainingNewName</code> 
+     * and <code>setRemainingNewName</code>.
+     */
+    protected Name remainingNewName = null;
+
+    /*
+     * =======
+     * Constructors
+     * =======
+     */
+
+    /**
+     * Constructs a <code>CannotProceedException</code> object. 
+     * All unspecified fields are initialized to null.
+     */
+    public CannotProceedException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>CannotProceedException</code> object with an 
+     * optionally specified <code>String</code> parameter containing a 
+     * detailed explanation message. The <code>String</code> parameter may
+     * be null. All unspecified fields are initialized to null.
+     * 
+     * @param s The detailed explanation message for the exception. 
+     * It may be null.
+     */
+    public CannotProceedException(String s) {
+        super(s);
+    }
+
+    /*
+     * =======
+     * Methods
+     * =======
+     */
+
+    /**
+     * Retrieves the value of the <code>altName</code> field.
+     * 
+     * @return the value of the <code>altName</code> field.
+     * @see javax.naming.spi.ObjectFactory#getObjectInstance(Object, Name, Context, Hashtable)
+     */
+    public Name getAltName() {
+        return altName;
+    }
+
+    /**
+     * Retrieves the value of the <code>altNameCtx</code> field.
+     * 
+     * @return the value of the <code>altNameCtx</code> field.
+     * @see javax.naming.spi.ObjectFactory#getObjectInstance(Object, Name, Context, Hashtable)
+     */
+    public Context getAltNameCtx() {
+        return altNameCtx;
+    }
+
+    /**
+     * Retrieves the value of the protected field <code>environment</code> 
+     * which may be null.
+     * 
+     * @return the value of the protected field <code>environment</code> 
+     * which may be null.
+     */
+    public Hashtable getEnvironment() {
+        return environment;
+    }
+
+    /**
+     * Retrieves the value of the <code>remainingNewName</code> field.
+     * 
+     * @return the value of the <code>remainingNewName</code> field.
+     */
+    public Name getRemainingNewName() {
+        return remainingNewName;
+    }
+
+    /**
+     * Modifies the value of the <code>altName</code> field to the specified 
+     * <code>Name</code> parameter which is a composite name and may be null.
+     * 
+     * @param name the name to set.
+     */
+    public void setAltName(Name name) {
+        altName = name;
+    }
+
+    /**
+     * Modifies the value of the <code>altNameCtx</code> field to the specified
+     * <code>Context</code> parameter which may be null.
+     * 
+     * @param context the new context to set.
+     */
+    public void setAltNameCtx(Context context) {
+        altNameCtx = context;
+    }
+
+    /**
+     * Sets the value of the protected field <code>environment</code> from the 
+     * <code>environment</code> parameter which may be null.
+     * 
+     * @param hashtable the new environment to set.
+     */
+    public void setEnvironment(Hashtable hashtable) {
+        environment = hashtable;
+    }
+
+    /**
+     * Modifies the value of the <code>remainingNewName</code> field to the 
+     * specified parameter which may be null. But otherwise is a composite 
+     * name. When needing to specify other names, first convert them into a 
+     * composite name with a single component, and then specify that composite
+     * name when invoking this method.
+     * <p>
+     * When a non-null name is specified, a clone of the composite name is 
+     * stored in the <code>remainingNewName</code> field that becomes 
+     * independent of the specified name.</p>
+     *  
+     * @param name the new name to set.
+     */
+    public void setRemainingNewName(Name name) {
+        remainingNewName = (null == name) ? null : (Name) name.clone();
+    }
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CommunicationException.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CommunicationException.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CommunicationException.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CommunicationException.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,55 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 javax.naming;
+
+/**
+ * This is the <code>NamingException</code> used when communication with the 
+ * naming or directory service fails.
+ * <p>
+ * Multithreaded access to an instance is only safe when client code locks the
+ * object first.</p>
+ * 
+ */
+public class CommunicationException extends NamingException {
+    
+	/*
+     * This constant is used during deserialization to check the J2SE version
+     * which created the serialized object.
+     */
+	static final long serialVersionUID = 3618507780299986611L; // J2SE 1.4.2	
+
+    /**
+     * Constructs a <code>CommunicationException</code> instance with all 
+     * data initialized to null.
+     */
+    public CommunicationException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>CommunicationException</code> instance using the 
+     * specified message.
+     * 
+     * @param s The detail message for the exception. It may be null.
+     */
+    public CommunicationException(String s) {
+        super(s);
+    }
+
+}
+
+

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CompositeName.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CompositeName.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CompositeName.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/CompositeName.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,652 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 javax.naming;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * A <code>CompositeName</code> represents a name in a naming service which 
+ * spans multiple namespaces. For example the name 
+ * "www.eclipse.org/index.html" spans the DNS and file system namespaces.
+ * <p>
+ * A <code>CompositeName</code> is a series of string elements. A composite 
+ * name has a sequence of zero or more elements delimited by the '/' char.
+ * Each element can be accessed using its position. The first element is at 
+ * position 0.</p>
+ * <p>
+ * A <code>CompositeName</code> may be empty. An empty composite name has no 
+ * elements. Elements may also be empty.</p>
+ * <p>
+ * <code>CompositeName</code>s are read from left to right unlike 
+ * <code>CompoundName</code>s which may have their direction of ordering 
+ * specified by properties.</p>
+ * <p>
+ * Special characters are as follows:</p>
+ * <ul>
+ * <li>The separator is /</li>
+ * <li>The escape character is \</li>
+ * <li>Quotes can be used - both single quotes and double quotes are allowed.
+ * This allows you to quote strings which contain chars such as / which are
+ * part of a <code>CompositeName</code> element to avoid them being read as a 
+ * separator.</li>
+ * </ul>
+ * <p>
+ * See the examples for further clarification.</p>
+ * <p>
+ * Some Examples:<br />
+ * ==============</p>
+ * <p>
+ * The composite name "www.eclipse.org/index.html" has 2 elements.
+ * "www.eclipse.org" is a name from the DNS namespace.
+ * "index.html" is a name from the file system namespace.</p>
+ * <p>
+ * Another example of a composite name is:
+ * "www.eclipse.org/org/index.html".
+ * This name has 3 elements "www.eclipse.org", "org" and "index.html".
+ * www.eclipse.org is a name from the DNS namespace.
+ * The last 2 elements are each from the file system namespace.</p>
+ * <p>
+ * Some more examples to clarify empty names and elements:</p>
+ * <p>
+ * An empty CompositeName is the name "" and has no elements.</p>
+ * <p>
+ * A CompositeName with just one empty element is the name "/".</p>
+ * <p>
+ * The name "/org/" has 3 elements. The first and last are empty.</p>
+ * <p>
+ * The name "/a" has 2 elements. The first element is empty
+ * and the second element is "a".</p>
+ * <p>
+ * The name "a//a" has 3 elements. The middle element is empty
+ * and the first & third elements are both "a".</p>
+ * <p>
+ * The name "a/'b/a" is invalid as there is no closing quote for the ' 
+ * character.</p>
+ * <p>
+ * The name "a/'a/b/b" is invalid as there is no closing quote for the ' 
+ * character.</p>
+ * <p>
+ * The name "a/\"b/a" is interpreted as a/"b/a and is invalid as there is no
+ * closing quote for the embedded escaped " character.</p>
+ * <p>
+ * The name "a/'b/c'/a" has 3 elements. The middle element is b/c.
+ * <p>
+ * The name "a/a'a/b'/b" has 4 elements:
+ * Element 0 is "a".
+ * Element 1 is "a'a".
+ * Element 2 is "b'".
+ * Element 3 is "b".</p>
+ * <p>
+ * Interestingly the name "a/a'a/b/b" is valid and has 4 elements. This is 
+ * beacuse the single quote char ' is not a leading quote and is embedded in 
+ * an element so is treated as a character.
+ * Element 0 is "a".
+ * Element 1 is "a'a".
+ * Element 2 is "b".
+ * Element 3 is "b".</p>
+ * <p>
+ * The name "\"abcd" gives an <code>InvalidNameException</code> as there is 
+ * no closing quote.</p>
+ * <p>
+ * The name "'\"abcd'" gives one element of value "abcd.</p>
+ * <p>
+ * The name "\\abcd" gives one element of value \abcd.</p>
+ * <p>
+ * "" is empty. It has no elements.
+ * "/" has one empty element.
+ * "//" has 2 empty elements.
+ * "/a/" has 3 elements the middle one is set to a.
+ * "///" has 3 empty elements.
+ * "//a/" has 4 elements, the last but one is set to a.</p>
+ *
+ */
+public class CompositeName implements Name {
+
+    /*
+     * -------------------------------------------------------------------
+     * Constants
+     * -------------------------------------------------------------------
+     */
+
+    // J2SE 1.4.2
+    private static final long serialVersionUID = 1667768148915813118L;
+    
+    // status used by parse()
+    private static final int OUT_OF_QUOTE = 0;
+    private static final int IN_SINGLE_QUOTE = 1;
+    private static final int IN_DOUBLE_QUOTE = 2;
+    private static final int QUOTE_ENDED = 3;
+
+    /*
+     * -------------------------------------------------------------------
+     * Instance variables
+     * -------------------------------------------------------------------
+     */
+
+    /* a list holding elements */
+    private transient Vector elems;
+
+    /*
+     * -------------------------------------------------------------------
+     * Constructors
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Private copy constructor.
+     *
+     * @param elements  a list of name elements
+     */
+    private CompositeName(List elements) {
+        elems = new Vector(elements);
+    }
+
+    /**
+     * Construct a composite name with given elements.
+     *
+     * @param elements  an enumeration of name elements
+     */
+    protected CompositeName(Enumeration elements) {
+        elems = new Vector();
+        while (elements.hasMoreElements()) {
+            elems.add(elements.nextElement());
+        }
+    }
+    
+    /**
+     * Default constructor, creates an empty name with zero elements.
+     */
+    public CompositeName() {
+        elems = new Vector();
+    }
+
+    /**
+     * This constructor takes the supplied name and breaks it down into its
+     * elements.
+     *
+     * @param name  a string containing the full composite name
+     * @throws InvalidNameException if the supplied name is invalid
+     */
+    public CompositeName(String name) throws InvalidNameException {
+        elems = parseName(name);
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods
+     * -------------------------------------------------------------------
+     */
+
+    /*
+     * Parse string name elements. Delimiter is "/".
+     * Escape is "\" and both single quote and double quote are supported.
+     */
+    private static Vector parseName(String name) throws InvalidNameException {
+
+        Vector l = new Vector();
+
+        // special case: all '/', means same number of empty elements
+        if (isAllSlash(name)) {
+            for (int i = 0; i < name.length(); i++) {
+                l.add(""); //$NON-NLS-1$
+            }
+            return l;
+        }
+
+        // general simple case, without escape and quote
+        if (name.indexOf('"') < 0
+            && name.indexOf('\'') < 0
+            && name.indexOf('\\') < 0) {
+            int i = 0, j = 0;
+            while ((j = name.indexOf('/', i)) >= 0) {
+                l.add(name.substring(i, j));
+                i = j + 1;
+            }
+            l.add(name.substring(i));
+            return l;
+        }
+
+        // general complicated case, consider escape and quote
+        char c;
+        char chars[] = name.toCharArray();
+        StringBuffer buf = new StringBuffer();
+        int status = OUT_OF_QUOTE;
+        for (int i = 0; i < chars.length; i++) {
+            c = chars[i];
+
+            // check end quote violation
+            if (status == QUOTE_ENDED) {
+                if (c == '/') {
+                    l.add(buf.toString());
+                    buf.setLength(0);
+                    status = OUT_OF_QUOTE;
+                    continue;
+                }
+				throw new InvalidNameException("End quote is not at the end of element"); //$NON-NLS-1$
+            }
+
+            if (c == '\\') {
+                // escape char
+                try {
+                    char nc = chars[++i];
+                    if (nc == '\\' || nc == '\'' || nc == '"' || nc == '/') {
+                        buf.append(nc);
+                    } else {
+                        buf.append(c);
+                        buf.append(nc);
+                    }
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    throw new InvalidNameException("Escape cannot be at the end of element"); //$NON-NLS-1$
+                }
+                continue;
+            }
+            if (c != '/' && c != '"' && c != '\'') {
+                // normal char
+                buf.append(c);
+                continue;
+            }
+
+            // special char
+            if (status == OUT_OF_QUOTE && c == '/') {
+                l.add(buf.toString());
+                buf.setLength(0);
+            } else if (status == OUT_OF_QUOTE && c == '\'' && buf.length() == 0) {
+                status = IN_SINGLE_QUOTE;
+            } else if (status == OUT_OF_QUOTE && c == '"' && buf.length() == 0) {
+                status = IN_DOUBLE_QUOTE;
+            } else if (status == IN_SINGLE_QUOTE && c == '\'') {
+                status = QUOTE_ENDED;
+            } else if (status == IN_DOUBLE_QUOTE && c == '"') {
+                status = QUOTE_ENDED;
+            } else {
+                buf.append(c);
+            }
+        }
+        l.add(buf.toString());
+
+        // check end status
+        if (status != OUT_OF_QUOTE && status != QUOTE_ENDED) {
+            throw new InvalidNameException("Wrong quote usage."); //$NON-NLS-1$
+        }
+        return l;
+    }
+
+    private static boolean isAllSlash(String name) {
+        for (int i = 0; i < name.length(); i++) {
+            if (name.charAt(i) != '/') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Format name elements to its string representation.
+     */
+    private static String formatName(Vector elems) {
+
+        // special case: all empty elements
+        if (isAllEmptyElements(elems)) {
+            StringBuffer buf = new StringBuffer();
+            for (int i = 0; i < elems.size(); i++) {
+                buf.append("/"); //$NON-NLS-1$
+            }
+            return buf.toString();
+        }
+
+        // general case
+        StringBuffer buf = new StringBuffer();
+        for (int i = 0; i < elems.size(); i++) {
+            String elem = (String) elems.get(i);
+            if (i > 0) {
+                buf.append("/"); //$NON-NLS-1$
+            }
+            if (elem.indexOf('/') < 0
+                && elem.indexOf('\\') < 0
+                && elem.indexOf('\'') < 0
+                && elem.indexOf('"') < 0) {
+                buf.append(elem);
+            } else {
+                char chars[] = elem.toCharArray();
+                for (int j = 0; j < chars.length; j++) {
+                    char c = chars[j];
+                    if (c == '/' || c == '\\' || c == '\'' || c == '"') {
+                        buf.append('\\');
+                    }
+                    buf.append(c);
+                }
+            }
+        }
+        return buf.toString();
+    }
+
+    private static boolean isAllEmptyElements(Vector elems) {
+        for (int i = 0; i < elems.size(); i++) {
+            String elem = (String) elems.get(i);
+            if (elem.length() > 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods of interface Name
+     * -------------------------------------------------------------------
+     */
+
+    public Enumeration getAll() {
+        return elems.elements();
+    }
+
+    public String get(int index) {
+        return (String) elems.get(index);
+    }
+
+    public Name getPrefix(int index) {
+        if (index < 0 || index > elems.size()) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        return new CompositeName(elems.subList(0, index));
+    }
+
+    public Name getSuffix(int index) {
+        if (index < 0 || index > elems.size()) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        return new CompositeName(elems.subList(index, elems.size()));
+    }
+
+    public Name addAll(Name name) throws InvalidNameException {
+        if (null == name) {
+            throw new NullPointerException();
+        }
+        if (!(name instanceof CompositeName)) {
+            throw new InvalidNameException("Must be a CompositeName"); //$NON-NLS-1$
+        }
+
+        Enumeration enumeration = name.getAll();
+        while (enumeration.hasMoreElements()) {
+            elems.add(enumeration.nextElement());
+        }
+        return this;
+    }
+
+    public Name addAll(int index, Name name) throws InvalidNameException {
+        if (null == name) {
+            throw new NullPointerException();
+        }
+        if (!(name instanceof CompositeName)) {
+            throw new InvalidNameException("Must be a CompositeName"); //$NON-NLS-1$
+        }
+
+        if (index < 0 || index > elems.size()) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        Enumeration enumeration = name.getAll();
+        while (enumeration.hasMoreElements()) {
+            elems.add(index++, enumeration.nextElement());
+        }
+        return this;
+    }
+
+    public Name add(String element) throws InvalidNameException {
+        elems.add(element);
+        return this;
+    }
+
+    public Name add(int index, String element) throws InvalidNameException {
+        if (index < 0 || index > elems.size()) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        elems.add(index, element);
+        return this;
+    }
+
+    public Object remove(int index) throws InvalidNameException {
+        if (index < 0 || index >= elems.size()) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        return elems.remove(index);
+    }
+
+    public int size() {
+        return elems.size();
+    }
+
+    public boolean isEmpty() {
+        return elems.isEmpty();
+    }
+
+    public boolean startsWith(Name name) {
+        if (!(name instanceof CompositeName)) {
+            return false;
+        }
+
+        // check size
+        if (name.size() > elems.size()) {
+            return false;
+        }
+
+        // compare 1 by 1
+        Enumeration enumeration = name.getAll();
+        Object me, he;
+        for (int i = 0; enumeration.hasMoreElements(); i++) {
+            me = elems.get(i);
+            he = enumeration.nextElement();
+            if (!(null == me ? null == he : me.equals(he))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean endsWith(Name name) {
+        if (!(name instanceof CompositeName)) {
+            return false;
+        }
+
+        // check size
+        if (name.size() > elems.size()) {
+            return false;
+        }
+
+        // compare 1 by 1
+        Enumeration enumeration = name.getAll();
+        Object me, he;
+        for (int i = elems.size() - name.size(); enumeration.hasMoreElements(); i++) {
+            me = elems.get(i);
+            he = enumeration.nextElement();
+            if (!(null == me ? null == he : me.equals(he))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Compare this <code>Name</code> with the one supplied as a parameter.
+     * The elements of the names are compared in the same way as strings are
+     * compared to determine whether this <code>CompositeName</code> is less 
+     * than, greater than or equal to the supplied object <code>o</code>.
+     * 
+     * @param o the object to compare, cannot be null
+     * @return  a negative number means this is less than the supplied object;
+     *          a positive number means this is greater than the supplied 
+     *          object; zero means this CompositeName equals the object as 
+     *          specified in the description for the equals method of 
+     *          <code>CompositeName</code>.
+     * @throws ClassCastException when <code>o</code> is not a 
+     *          <code>CompositeName</code>.
+     */
+    public int compareTo(Object o) {
+        if (o instanceof CompositeName) {
+            CompositeName he = (CompositeName) o;
+            int r;
+            for (int i = 0; i < elems.size() && i < he.elems.size(); i++) {
+                r = ((String) elems.get(i)).compareTo(he.elems.get(i));
+                if (r != 0) {
+                    return r;
+                }
+            }
+            if (elems.size() == he.elems.size()) {
+                return 0;
+            } else if (elems.size() < he.elems.size()) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+        throw new ClassCastException();
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods override parent class Object
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Create a copy of this composite name, a complete (deep) copy of the object.
+     *
+     * @return a complete (deep) copy of the object.
+     */
+    public Object clone() {
+        // Object.clone()
+        CompositeName copy = null;
+        try {
+            copy = (CompositeName) super.clone();
+        } catch (CloneNotSupportedException e) {
+            // should never happen
+            throw new InternalError(
+                "Failed to clone object of " //$NON-NLS-1$
+                    + this.getClass().getName()
+                    + " class."); //$NON-NLS-1$
+        }
+
+        // replicate fields
+        copy.elems = new Vector(elems);
+        return copy;
+    }
+
+    /**
+     * Returns the string representation of this <code>CompositeName</code>. 
+     * This is generated by concatenating the elements together with the '/' 
+     * char added as the separator between each of them. It may be necessary 
+     * to add quotes and escape chars to preserve the meaning. The resulting 
+     * string should produce an equivalent <code>CompositeName</code> when 
+     * used to create a new instance.
+     *
+     * @return the string representation of this composite name.
+     */
+    public String toString() {
+        return formatName(elems);
+    }
+
+    /**
+     * Check if this <code>Name</code> is equal to the supplied object.
+     *
+     * @param o the <code>CompositeName</code> to compare - can be null but 
+     *          then returns false.
+     * @return  true if they have the same number of elements all of
+     *          which are equal. false if they are not equal.
+     */
+    public boolean equals(Object o) {
+        // check type
+        if (!(o instanceof CompositeName)) {
+            return false;
+        }
+
+        // check size
+        Name name = (Name) o;
+        if (elems.size() != name.size()) {
+            return false;
+        }
+
+        // compare 1 by 1
+        Enumeration enumeration = name.getAll();
+        Object me, he;
+        for (int i = 0; enumeration.hasMoreElements(); i++) {
+            me = elems.get(i);
+            he = enumeration.nextElement();
+            if (!(null == me ? null == he : me.equals(he))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Calculate the hashcode of this <code>CompositeName</code> by summing 
+     * the hashcodes of all of its elements.
+     *
+     * @return the hashcode of this object.
+     */
+    public int hashCode() {
+        int sum = 0;
+        for (int i = 0; i < elems.size(); i++) {
+            sum += elems.get(i).hashCode();
+        }
+        return sum;
+    }
+
+    /*
+     * Writes a serialized representation of the CompositeName. It starts with
+     * an int which is the number of elements in the name, and is followed by a
+     * String for each element.
+     * 
+     * @param oos
+     * @throws java.io.IOException if an error is encountered writing to the stream.
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+
+        oos.writeInt(elems.size());
+        for (Iterator iter = elems.iterator(); iter.hasNext();) {
+            oos.writeObject(iter.next());
+        }
+    }
+
+    /*
+     * Recreate a CompositeName from the data in the supplied stream.
+     * 
+     * @param ois
+     * @throws java.io.IOException if an error is encountered reading from the stream.
+     * @throws ClassNotFoundException.
+     */
+    private void readObject(ObjectInputStream ois)
+        throws OptionalDataException, ClassNotFoundException, IOException {
+        ois.defaultReadObject();
+
+        int size = ois.readInt();
+        elems = new Vector();
+        for (int i = 0; i < size; i++) {
+            elems.add(ois.readObject());
+        }
+    }
+
+}
+
+