You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by fe...@apache.org on 2007/11/05 15:45:45 UTC

svn commit: r592021 [3/3] - in /directory/sandbox/felixk/studio-connection-core: ./ META-INF/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/directory/ src/main/java/org/apache/directory/studio/ src/...

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDIConnectionWrapper.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDIConnectionWrapper.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDIConnectionWrapper.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDIConnectionWrapper.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,946 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.studio.connection.core.io.jndi;
+
+
+import java.util.Hashtable;
+
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.InsufficientResourcesException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.ServiceUnavailableException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.StartTlsRequest;
+import javax.naming.ldap.StartTlsResponse;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSession;
+
+import org.apache.directory.studio.connection.core.Connection;
+import org.apache.directory.studio.connection.core.ConnectionCorePlugin;
+import org.apache.directory.studio.connection.core.ConnectionParameter;
+import org.apache.directory.studio.connection.core.IAuthHandler;
+import org.apache.directory.studio.connection.core.ICredentials;
+import org.apache.directory.studio.connection.core.IModificationLogger;
+import org.apache.directory.studio.connection.core.Messages;
+import org.apache.directory.studio.connection.core.StudioProgressMonitor;
+import org.apache.directory.studio.connection.core.io.ConnectionWrapper;
+
+
+/**
+ * A connection wrapper that uses JNDI.
+ * 
+ * - asychron + cancelable
+ * - SSL certificate
+ * - manages broken/closed connections
+ * - delete old RDN
+ * - exception handling 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class JNDIConnectionWrapper implements ConnectionWrapper
+{
+    private Connection connection;
+
+    private boolean useLdaps;
+
+    private boolean useStartTLS;
+
+    private String authMethod;
+
+    private String bindPrincipal;
+
+    private String bindCredentials;
+
+    private String saslRealm;
+
+    private Hashtable<String, String> environment;
+
+    private InitialLdapContext context;
+
+    private boolean isConnected;
+
+    private Thread jobThread;
+
+    private IModificationLogger modificationLogger;
+
+
+    /**
+     * Creates a new instance of JNDIConnectionContext.
+     * 
+     * @param connection the connection
+     */
+    public JNDIConnectionWrapper( Connection connection )
+    {
+        this.connection = connection;
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.io.ConnectionWrapper#connect(org.apache.directory.studio.connection.core.StudioProgressMonitor)
+     */
+    public void connect( StudioProgressMonitor monitor )
+    {
+        context = null;
+        isConnected = false;
+        jobThread = null;
+
+        try
+        {
+            doConnect( monitor );
+        }
+        catch ( NamingException ne )
+        {
+            disconnect();
+            monitor.reportError( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.io.ConnectionWrapper#disconnect()
+     */
+    public void disconnect()
+    {
+        if ( jobThread != null )
+        {
+            Thread t = jobThread;
+            jobThread = null;
+            t.interrupt();
+        }
+        if ( context != null )
+        {
+            try
+            {
+                context.close();
+            }
+            catch ( NamingException e )
+            {
+                // ignore
+            }
+            context = null;
+        }
+        isConnected = false;
+        System.gc();
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.io.ConnectionWrapper#bind(org.apache.directory.studio.connection.core.StudioProgressMonitor)
+     */
+    public void bind( StudioProgressMonitor monitor )
+    {
+        try
+        {
+            doBind( monitor );
+        }
+        catch ( NamingException ne )
+        {
+            disconnect();
+            monitor.reportError( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.io.ConnectionWrapper#unbind()
+     */
+    public void unbind()
+    {
+        disconnect();
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.io.ConnectionWrapper#isConnected()
+     */
+    public boolean isConnected()
+    {
+        return context != null;
+    }
+
+
+    /**
+     * Search.
+     * 
+     * @param searchBase the search base
+     * @param filter the filter
+     * @param searchControls the controls
+     * @param derefAliasMethod the deref alias method
+     * @param handleReferralsMethod the handle referrals method
+     * @param controls the ldap controls
+     * @param monitor the progress monitor
+     * 
+     * @return the naming enumeration or null if an exception occurs.
+     */
+    public NamingEnumeration<SearchResult> search( final String searchBase, final String filter,
+        final SearchControls searchControls, final String derefAliasMethod, final String handleReferralsMethod,
+        final Control[] controls, final StudioProgressMonitor monitor )
+    {
+        // start
+        InnerRunnable runnable = new InnerRunnable()
+        {
+            private NamingEnumeration<SearchResult> namingEnumeration = null;
+            private NamingException namingException = null;
+
+
+            public void run()
+            {
+                try
+                {
+                    LdapContext searchCtx = context.newInstance( controls );
+                    try
+                    {
+                        searchCtx.addToEnvironment( "java.naming.ldap.derefAliases", derefAliasMethod ); //$NON-NLS-1$
+                        searchCtx.addToEnvironment( Context.REFERRAL, handleReferralsMethod );
+
+                    }
+                    catch ( NamingException e )
+                    {
+                        namingException = e;
+                    }
+
+                    try
+                    {
+                        namingEnumeration = searchCtx.search( new LdapName( searchBase ), filter, searchControls );
+                    }
+                    catch ( NamingException ne )
+                    {
+                        namingException = ne;
+                    }
+
+                }
+                catch ( NamingException e )
+                {
+                    namingException = e;
+                }
+            }
+
+
+            public NamingException getException()
+            {
+                return namingException;
+            }
+
+
+            public NamingEnumeration<SearchResult> getResult()
+            {
+                return namingEnumeration;
+            }
+
+
+            public void reset()
+            {
+                namingEnumeration = null;
+                namingException = null;
+            }
+
+        };
+
+        try
+        {
+            checkConnectionAndRunAndMonitor( runnable, monitor );
+        }
+        catch ( NamingException ne )
+        {
+            monitor.reportError( ne.getMessage(), ne );
+            return null;
+        }
+
+        if ( runnable.getException() != null )
+        {
+            monitor.reportError( runnable.getException().getMessage(), runnable.getException() );
+            return null;
+        }
+        else if ( runnable.getResult() != null && runnable.getResult() instanceof NamingEnumeration )
+        {
+            return runnable.getResult();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Modify attributes.
+     * 
+     * @param dn the DN
+     * @param modificationItems the modification items
+     * @param controls the controls
+     * @param monitor the progress monitor
+     */
+    public void modifyAttributes( final String dn, final ModificationItem[] modificationItems,
+        final Control[] controls, final StudioProgressMonitor monitor )
+    {
+        InnerRunnable runnable = new InnerRunnable()
+        {
+            private NamingException namingException = null;
+
+
+            public void run()
+            {
+                try
+                {
+                    LdapContext modCtx = context.newInstance( controls );
+                    modCtx.addToEnvironment( Context.REFERRAL, "throw" ); //$NON-NLS-1$
+
+                    modCtx.modifyAttributes( new LdapName( dn ), modificationItems );
+                }
+                catch ( NamingException ne )
+                {
+                    namingException = ne;
+                }
+
+                if ( modificationLogger != null )
+                {
+                    modificationLogger.logChangetypeModify( dn, modificationItems, controls, namingException );
+                }
+            }
+
+
+            public NamingException getException()
+            {
+                return namingException;
+            }
+
+
+            public NamingEnumeration<SearchResult> getResult()
+            {
+                return null;
+            }
+
+
+            public void reset()
+            {
+                namingException = null;
+            }
+        };
+
+        try
+        {
+            checkConnectionAndRunAndMonitor( runnable, monitor );
+        }
+        catch ( NamingException ne )
+        {
+            monitor.reportError( ne.getMessage(), ne );
+        }
+
+        if ( runnable.getException() != null )
+        {
+            monitor.reportError( runnable.getException().getMessage(), runnable.getException() );
+        }
+    }
+
+
+    /**
+     * Renames an entry.
+     * 
+     * @param oldDn the old dn
+     * @param newDn the new dn
+     * @param deleteOldRdn the delete old rdn flag
+     * @param controls the controls
+     * @param monitor the monitor
+     */
+    public void rename( final String oldDn, final String newDn, final boolean deleteOldRdn, final Control[] controls,
+        final StudioProgressMonitor monitor )
+    {
+        InnerRunnable runnable = new InnerRunnable()
+        {
+            private NamingException namingException = null;
+
+
+            public void run()
+            {
+                try
+                {
+                    LdapContext modCtx = context.newInstance( controls );
+                    modCtx.addToEnvironment( Context.REFERRAL, "throw" ); //$NON-NLS-1$
+
+                    if ( deleteOldRdn )
+                    {
+                        modCtx.addToEnvironment( "java.naming.ldap.deleteRDN", "true" ); //$NON-NLS-1$ //$NON-NLS-2$
+                    }
+                    else
+                    {
+                        modCtx.addToEnvironment( "java.naming.ldap.deleteRDN", "false" ); //$NON-NLS-1$ //$NON-NLS-2$
+                    }
+
+                    modCtx.rename( new LdapName( oldDn ), new LdapName( newDn ) );
+                }
+                catch ( NamingException ne )
+                {
+                    namingException = ne;
+                }
+
+                if ( modificationLogger != null )
+                {
+                    modificationLogger.logChangetypeModDn( oldDn, newDn, deleteOldRdn, controls, namingException );
+                }
+            }
+
+
+            public NamingException getException()
+            {
+                return namingException;
+            }
+
+
+            public NamingEnumeration<SearchResult> getResult()
+            {
+                return null;
+            }
+
+
+            public void reset()
+            {
+                namingException = null;
+            }
+        };
+
+        try
+        {
+            checkConnectionAndRunAndMonitor( runnable, monitor );
+        }
+        catch ( NamingException ne )
+        {
+            monitor.reportError( ne.getMessage(), ne );
+        }
+
+        if ( runnable.getException() != null )
+        {
+            monitor.reportError( runnable.getException().getMessage(), runnable.getException() );
+        }
+    }
+
+
+    /**
+     * Creates an entry.
+     * 
+     * @param dn the dn
+     * @param attributes the attributes
+     * @param controls the controls
+     * @param monitor the monitor
+     */
+    public void createEntry( final String dn, final Attributes attributes, final Control[] controls,
+        final StudioProgressMonitor monitor )
+    {
+        InnerRunnable runnable = new InnerRunnable()
+        {
+            private NamingException namingException = null;
+
+
+            public void run()
+            {
+
+                try
+                {
+                    LdapContext modCtx = context.newInstance( controls );
+                    modCtx.addToEnvironment( Context.REFERRAL, "throw" ); //$NON-NLS-1$
+
+                    modCtx.createSubcontext( new LdapName( dn ), attributes );
+                }
+                catch ( NamingException ne )
+                {
+                    namingException = ne;
+                }
+
+                if ( modificationLogger != null )
+                {
+                    modificationLogger.logChangetypeAdd( dn, attributes, controls, namingException );
+                }
+            }
+
+
+            public NamingException getException()
+            {
+                return namingException;
+            }
+
+
+            public NamingEnumeration<SearchResult> getResult()
+            {
+                return null;
+            }
+
+
+            public void reset()
+            {
+                namingException = null;
+            }
+        };
+
+        try
+        {
+            checkConnectionAndRunAndMonitor( runnable, monitor );
+        }
+        catch ( NamingException ne )
+        {
+            monitor.reportError( ne.getMessage(), ne );
+        }
+
+        if ( runnable.getException() != null )
+        {
+            monitor.reportError( runnable.getException().getMessage(), runnable.getException() );
+        }
+    }
+
+
+    /**
+     * Deletes an entry.
+     * 
+     * @param dn the dn
+     * @param controls the controls
+     * @param monitor the monitor
+     */
+    public void deleteEntry( final String dn, final Control[] controls, final StudioProgressMonitor monitor )
+    {
+        InnerRunnable runnable = new InnerRunnable()
+        {
+            private NamingException namingException = null;
+
+
+            public void run()
+            {
+                try
+                {
+                    LdapContext modCtx = context.newInstance( controls );
+                    modCtx.addToEnvironment( Context.REFERRAL, "throw" ); //$NON-NLS-1$
+
+                    modCtx.destroySubcontext( new LdapName( dn ) );
+                }
+                catch ( NamingException ne )
+                {
+                    namingException = ne;
+                }
+
+                if ( modificationLogger != null )
+                {
+                    modificationLogger.logChangetypeDelete( dn, controls, namingException );
+                }
+            }
+
+
+            public NamingException getException()
+            {
+                return namingException;
+            }
+
+
+            public NamingEnumeration<SearchResult> getResult()
+            {
+                return null;
+            }
+
+
+            public void reset()
+            {
+                namingException = null;
+            }
+        };
+
+        try
+        {
+            checkConnectionAndRunAndMonitor( runnable, monitor );
+        }
+        catch ( NamingException ne )
+        {
+            monitor.reportError( ne.getMessage(), ne );
+        }
+
+        if ( runnable.getException() != null )
+        {
+            monitor.reportError( runnable.getException().getMessage(), runnable.getException() );
+        }
+    }
+
+
+    private void doConnect( final StudioProgressMonitor monitor ) throws NamingException
+    {
+        context = null;
+        isConnected = true;
+
+        // setup connection parameters
+        String host = connection.getConnectionParameter().getHost();
+        int port = connection.getConnectionParameter().getPort();
+
+        useLdaps = connection.getConnectionParameter().getEncryptionMethod() == ConnectionParameter.EncryptionMethod.LDAPS;
+        useStartTLS = connection.getConnectionParameter().getEncryptionMethod() == ConnectionParameter.EncryptionMethod.START_TLS;
+
+        environment = new Hashtable<String, String>();
+        environment.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" ); //$NON-NLS-1$
+        environment.put( "java.naming.ldap.version", "3" ); //$NON-NLS-1$ //$NON-NLS-2$
+
+        // timeouts
+        if ( !useLdaps )
+        {
+            environment.put( "com.sun.jndi.ldap.connect.timeout", "10000" ); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        environment.put( "com.sun.jndi.dns.timeout.initial", "2000" ); //$NON-NLS-1$ //$NON-NLS-2$
+        environment.put( "com.sun.jndi.dns.timeout.retries", "3" ); //$NON-NLS-1$ //$NON-NLS-2$
+
+        // ldaps://
+        if ( useLdaps )
+        {
+            environment.put( Context.PROVIDER_URL, "ldaps://" + host + ":" + port ); //$NON-NLS-1$ //$NON-NLS-2$
+            environment.put( Context.SECURITY_PROTOCOL, "ssl" ); //$NON-NLS-1$
+            environment.put( "java.naming.ldap.factory.socket", DummySSLSocketFactory.class.getName() ); //$NON-NLS-1$
+        }
+        else
+        {
+            environment.put( Context.PROVIDER_URL, "ldap://" + host + ":" + port ); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        InnerRunnable runnable = new InnerRunnable()
+        {
+            private NamingException namingException = null;
+
+
+            public void run()
+            {
+                try
+                {
+                    context = new InitialLdapContext( environment, null );
+
+                    if ( useStartTLS )
+                    {
+                        try
+                        {
+                            StartTlsResponse tls = ( StartTlsResponse ) context
+                                .extendedOperation( new StartTlsRequest() );
+                            tls.setHostnameVerifier( new HostnameVerifier()
+                            {
+                                public boolean verify( String arg0, SSLSession arg1 )
+                                {
+                                    return true;
+                                }
+                            } );
+                            tls.negotiate( new DummySSLSocketFactory() );
+
+                        }
+                        catch ( Exception e )
+                        {
+                            namingException = new NamingException( e.getMessage() != null ? e.getMessage()
+                                : "Error while establishing TLS session" ); //$NON-NLS-1$
+                            namingException.setRootCause( e );
+                            context.close();
+                        }
+                    }
+                }
+                catch ( NamingException ne )
+                {
+                    namingException = ne;
+                }
+            }
+
+
+            public NamingException getException()
+            {
+                return namingException;
+            }
+
+
+            public NamingEnumeration<SearchResult> getResult()
+            {
+                return null;
+            }
+
+
+            public void reset()
+            {
+                namingException = null;
+            }
+        };
+
+        runAndMonitor( runnable, monitor );
+
+        if ( runnable.getException() != null )
+        {
+            throw runnable.getException();
+        }
+        else if ( context != null )
+        {
+            // all OK
+        }
+        else
+        {
+            throw new NamingException( "???" ); //$NON-NLS-1$
+        }
+    }
+
+
+    private void doBind( final StudioProgressMonitor monitor ) throws NamingException
+    {
+        if ( context != null && isConnected )
+        {
+            // setup authentication methdod
+            authMethod = "none";
+            if ( connection.getConnectionParameter().getAuthMethod() == ConnectionParameter.AuthenticationMethod.SIMPLE )
+            {
+                authMethod = "simple";
+            }
+            else if ( connection.getConnectionParameter().getAuthMethod() == ConnectionParameter.AuthenticationMethod.SASL_DIGEST_MD5 )
+            {
+                authMethod = "DIGEST-MD5";
+                saslRealm = connection.getConnectionParameter().getSaslRealm();
+            }
+            else if ( connection.getConnectionParameter().getAuthMethod() == ConnectionParameter.AuthenticationMethod.SASL_CRAM_MD5 )
+            {
+                authMethod = "CRAM-MD5";
+            }
+            else if ( connection.getConnectionParameter().getAuthMethod() == ConnectionParameter.AuthenticationMethod.SASL_GSSAPI )
+            {
+                authMethod = "GSSAPI";
+            }
+
+            // setup credentials
+            IAuthHandler authHandler = ConnectionCorePlugin.getDefault().getAuthHandler();
+            if ( authHandler == null )
+            {
+                monitor.reportError( Messages.model__no_auth_handler, new Exception() );
+            }
+            ICredentials credentials = authHandler.getCredentials( connection.getConnectionParameter() );
+            if ( credentials == null )
+            {
+                monitor.reportError( Messages.model__no_credentials, new Exception() );
+            }
+            bindPrincipal = credentials.getBindPrincipal();
+            bindCredentials = credentials.getBindPassword();
+
+            InnerRunnable runnable = new InnerRunnable()
+            {
+                private NamingException namingException = null;
+
+
+                public void run()
+                {
+                    try
+                    {
+                        context.removeFromEnvironment( Context.SECURITY_AUTHENTICATION );
+                        context.removeFromEnvironment( Context.SECURITY_PRINCIPAL );
+                        context.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
+                        context.removeFromEnvironment( "java.naming.security.sasl.realm" );
+
+                        context.addToEnvironment( Context.SECURITY_PRINCIPAL, bindPrincipal );
+                        context.addToEnvironment( Context.SECURITY_CREDENTIALS, bindCredentials );
+                        context.addToEnvironment( Context.SECURITY_AUTHENTICATION, authMethod );
+
+                        if ( connection.getConnectionParameter().getAuthMethod() == ConnectionParameter.AuthenticationMethod.SASL_DIGEST_MD5 )
+                        {
+                            context.addToEnvironment( "java.naming.security.sasl.realm", saslRealm );
+                        }
+                        context.reconnect( context.getConnectControls() );
+                    }
+                    catch ( NamingException ne )
+                    {
+                        namingException = ne;
+                    }
+                }
+
+
+                public NamingException getException()
+                {
+                    return namingException;
+                }
+
+
+                public NamingEnumeration<SearchResult> getResult()
+                {
+                    return null;
+                }
+
+
+                public void reset()
+                {
+                    namingException = null;
+                }
+            };
+
+            runAndMonitor( runnable, monitor );
+
+            if ( runnable.getException() != null )
+            {
+                throw runnable.getException();
+            }
+            else if ( context != null )
+            {
+                // all OK
+            }
+            else
+            {
+                throw new NamingException( "???" ); //$NON-NLS-1$
+            }
+
+        }
+        else
+        {
+            throw new NamingException( "No connection" );
+        }
+    }
+
+
+    private void checkConnectionAndRunAndMonitor( final InnerRunnable runnable, final StudioProgressMonitor monitor )
+        throws NamingException
+    {
+        // check connection
+        if ( !isConnected || context == null )
+        {
+            doConnect( monitor );
+            doBind( monitor );
+        }
+        if ( context == null )
+        {
+            throw new NamingException( "No connection" );
+        }
+
+        // loop for reconnection
+        for ( int i = 0; i <= 1; i++ )
+        {
+            runAndMonitor( runnable, monitor );
+
+            // check reconnection
+            if ( i == 0
+                && runnable.getException() != null
+                && ( ( runnable.getException() instanceof CommunicationException )
+                    || ( runnable.getException() instanceof ServiceUnavailableException ) || ( runnable.getException() instanceof InsufficientResourcesException ) ) )
+            {
+
+                doConnect( monitor );
+                doBind( monitor );
+                runnable.reset();
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+
+
+    private void runAndMonitor( final InnerRunnable runnable, final StudioProgressMonitor monitor )
+        throws CancelException
+    {
+        if ( !monitor.isCanceled() )
+        {
+            // monitor
+            StudioProgressMonitor.CancelListener listener = new StudioProgressMonitor.CancelListener()
+            {
+                public void cancelRequested( StudioProgressMonitor.CancelEvent event )
+                {
+                    if ( monitor.isCanceled() )
+                    {
+                        if ( jobThread.isAlive() )
+                        {
+                            jobThread.interrupt();
+                        }
+                        if ( context != null )
+                        {
+                            try
+                            {
+                                context.close();
+                            }
+                            catch ( NamingException ne )
+                            {
+                            }
+                            isConnected = false;
+                            context = null;
+                            System.gc();
+                        }
+                        isConnected = false;
+                    }
+                }
+            };
+            monitor.addCancelListener( listener );
+            jobThread = Thread.currentThread();
+
+            // run
+            try
+            {
+                // try {
+                // Thread.sleep(5000);
+                // } catch (InterruptedException e) {
+                // System.out.println(System.currentTimeMillis() + ": sleep
+                // interrupted!");
+                // }
+                // System.out.println(System.currentTimeMillis() + ": " +
+                // runnable);
+
+                runnable.run();
+            }
+            finally
+            {
+                monitor.removeCancelListener( listener );
+                jobThread = null;
+            }
+
+            if ( monitor.isCanceled() )
+            {
+                throw new CancelException();
+            }
+        }
+    }
+
+    interface InnerRunnable extends Runnable
+    {
+
+        /**
+         * Gets the exception.
+         * 
+         * @return the exception
+         */
+        NamingException getException();
+
+
+        /**
+         * Gets the result.
+         * 
+         * @return the result
+         */
+        NamingEnumeration<SearchResult> getResult();
+
+
+        /**
+         * Reset.
+         */
+        void reset();
+    }
+
+
+    /**
+     * Sets the modification logger.
+     * 
+     * @param modificationLogger the new modification logger
+     */
+    public void setModificationLogger( IModificationLogger modificationLogger )
+    {
+        this.modificationLogger = modificationLogger;
+    }
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDIConnectionWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDISubentriesControl.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDISubentriesControl.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDISubentriesControl.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDISubentriesControl.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.studio.connection.core.io.jndi;
+
+
+import javax.naming.ldap.BasicControl;
+
+
+/**
+ * The Subentries control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class JNDISubentriesControl extends BasicControl
+{
+
+    private static final long serialVersionUID = -6614360496036854589L;
+
+    /**
+     * The Subentries control's OID is 1.3.6.1.4.1.4203.1.10.1.
+     */
+    public static final String OID = "1.3.6.1.4.1.4203.1.10.1";
+
+    /**
+     * The Subentries control's value.
+     */
+    public static final byte[] VALUE = new byte[]
+        { 0x01, 0x01, ( byte ) 0xFF };
+
+
+    /**
+     * Creates a new instance of JNDISubentriesControl.
+     */
+    public JNDISubentriesControl()
+    {
+        super( OID, false, VALUE );
+    }
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/io/jndi/JNDISubentriesControl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractAsyncBulkJob.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractAsyncBulkJob.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractAsyncBulkJob.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractAsyncBulkJob.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.studio.connection.core.jobs;
+
+
+import org.apache.directory.studio.connection.core.StudioProgressMonitor;
+import org.apache.directory.studio.connection.core.event.ConnectionEventRegistry;
+
+
+/**
+ * Base class for bulk jobs. It is used to execute large modifications without
+ * firering modification events. The notification of the listeners is done after 
+ * the job is executed.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public abstract class AbstractAsyncBulkJob extends AbstractConnectionJob
+{
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#executeAsyncJob(org.apache.directory.studio.connection.core.StudioProgressMonitor)
+     */
+    protected final void executeAsyncJob( StudioProgressMonitor pm )
+    {
+        ConnectionEventRegistry.suspendEventFireingInCurrentThread();
+
+        try
+        {
+            executeBulkJob( pm );
+        }
+        finally
+        {
+            ConnectionEventRegistry.resumeEventFireingInCurrentThread();
+        }
+
+        this.runNotification();
+    }
+
+
+    /**
+     * Executes the bulk job.
+     * 
+     * @param pm the pm
+     */
+    protected abstract void executeBulkJob( StudioProgressMonitor pm );
+
+
+    /**
+     * Notifies about changed objects.
+     */
+    protected abstract void runNotification();
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractAsyncBulkJob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractConnectionJob.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractConnectionJob.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractConnectionJob.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractConnectionJob.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,256 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.studio.connection.core.jobs;
+
+
+import org.apache.directory.studio.connection.core.Connection;
+import org.apache.directory.studio.connection.core.StudioProgressMonitor;
+import org.apache.directory.studio.connection.core.Messages;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+
+/**
+ * Base class for all connections related jobs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public abstract class AbstractConnectionJob extends Job
+{
+
+    /** The external progress monitor. */
+    private IProgressMonitor externalProgressMonitor;
+
+    /** The external result. */
+    private IStatus externalResult;
+
+
+    /**
+     * Creates a new instance of AbstractConnectionJob.
+     */
+    protected AbstractConnectionJob()
+    {
+        super( "" ); //$NON-NLS-1$
+    }
+
+
+    /**
+     * Executes the job asynchronously.
+     * 
+     * @param monitor the progress monitor
+     * 
+     * @throws Exception the exception
+     */
+    protected abstract void executeAsyncJob( StudioProgressMonitor monitor ) throws Exception;
+
+
+    /**
+     * Gets the error message.
+     * 
+     * @return the error message.
+     */
+    protected String getErrorMessage()
+    {
+        return Messages.jobs__error_occurred;
+    }
+
+
+    /**
+     * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+     */
+    protected final IStatus run( IProgressMonitor ipm )
+    {
+        StudioProgressMonitor monitor = new StudioProgressMonitor( externalProgressMonitor == null ? ipm
+            : externalProgressMonitor );
+
+        // execute job
+        if ( !monitor.errorsReported() )
+        {
+            try
+            {
+                executeAsyncJob( monitor );
+            }
+            catch ( Exception e )
+            {
+                monitor.reportError( e );
+            }
+            finally
+            {
+                monitor.done();
+                ipm.done();
+            }
+        }
+
+        // error handling
+        if ( monitor.isCanceled() )
+        {
+            // System.out.println("Job: CANCEL+CANCEL");
+            externalResult = Status.CANCEL_STATUS;
+            return Status.CANCEL_STATUS;
+        }
+        else if ( monitor.errorsReported() )
+        {
+            externalResult = monitor.getErrorStatus( getErrorMessage() );
+            if ( externalProgressMonitor == null )
+            {
+                // System.out.println("Job: ERROR+ERROR");
+                return externalResult;
+            }
+            else
+            {
+                // System.out.println("Job: ERROR+OK");
+                return Status.OK_STATUS;
+            }
+        }
+        else
+        {
+            // System.out.println("Job: OK+OK");
+            externalResult = Status.OK_STATUS;
+            return Status.OK_STATUS;
+        }
+    }
+
+
+    /**
+     * Sets the external progress monitor.
+     * 
+     * @param externalProgressMonitor the external progress monitor
+     */
+    public void setExternalProgressMonitor( IProgressMonitor externalProgressMonitor )
+    {
+        this.externalProgressMonitor = externalProgressMonitor;
+    }
+
+
+    /**
+     * Gets the result of the executed job. Either Status.OK_STATUS, 
+     * Status.CANCEL_STATUS or an error status.
+     * 
+     * @return the result of the executed job
+     */
+    public IStatus getExternalResult()
+    {
+        return this.externalResult;
+    }
+
+
+    /**
+     * Executes the job.
+     */
+    public final void execute()
+    {
+        setUser( true );
+        schedule();
+    }
+
+
+    /**
+     * Gets the locked objects.
+     * 
+     * @return the locked objects
+     */
+    protected abstract Object[] getLockedObjects();
+
+
+    /**
+     * @see org.eclipse.core.runtime.jobs.Job#shouldSchedule()
+     */
+    public boolean shouldSchedule()
+    {
+        Object[] myLockedObjects = getLockedObjects();
+        String[] myLockedObjectsIdentifiers = getLockIdentifiers( myLockedObjects );
+
+        // TODO: read, write
+
+        Job[] jobs = Platform.getJobManager().find( null );
+        for ( int i = 0; i < jobs.length; i++ )
+        {
+            Job job = jobs[i];
+
+            // if(job instanceof AbstractEclipseJob) {
+            if ( job.getClass() == this.getClass() && job != this )
+            {
+                AbstractConnectionJob otherJob = ( AbstractConnectionJob ) job;
+                Object[] otherLockedObjects = otherJob.getLockedObjects();
+                String[] otherLockedObjectIdentifiers = getLockIdentifiers( otherLockedObjects );
+
+                for ( int j = 0; j < otherLockedObjectIdentifiers.length; j++ )
+                {
+                    String other = otherLockedObjectIdentifiers[j];
+                    for ( int k = 0; k < myLockedObjectsIdentifiers.length; k++ )
+                    {
+                        String my = myLockedObjectsIdentifiers[k];
+
+                        //System.out.print( "other:" + other + ", my: " + my );
+                        if ( other.startsWith( my ) || my.startsWith( other ) )
+                        {
+                            //System.out.println( ", shouldSchedule() = " + false );
+                            return false;
+                        }
+                        else
+                        {
+                            //System.out.println();
+                        }
+
+                    }
+                }
+
+            }
+        }
+        return super.shouldSchedule();
+    }
+
+
+    private static String[] getLockIdentifiers( Object[] objects )
+    {
+        String[] identifiers = new String[objects.length];
+        for ( int i = 0; i < identifiers.length; i++ )
+        {
+            Object o = objects[i];
+            if ( o instanceof Connection )
+            {
+                identifiers[i] = getLockIdentifier( ( Connection ) o );
+            }
+            else
+            {
+                identifiers[i] = getLockIdentifier( objects[i] );
+            }
+        }
+        return identifiers;
+    }
+
+
+    private static String getLockIdentifier( Connection connection )
+    {
+        return connection.getHost() + ":" + connection.getPort();
+    }
+
+
+    private static String getLockIdentifier( Object object )
+    {
+        return object.toString();
+    }
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/AbstractConnectionJob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckBindJob.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckBindJob.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckBindJob.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckBindJob.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.studio.connection.core.jobs;
+
+
+import org.apache.directory.studio.connection.core.Connection;
+import org.apache.directory.studio.connection.core.StudioProgressMonitor;
+import org.apache.directory.studio.connection.core.Messages;
+
+
+/**
+ * Job to check binding (authentication) to a directory server
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class CheckBindJob extends AbstractConnectionJob
+{
+
+    private Connection connection;
+
+
+    /**
+     * Creates a new instance of CheckBindJob.
+     * 
+     * @param connection the connection
+     */
+    public CheckBindJob( Connection connection )
+    {
+        this.connection = connection;
+        setName( Messages.jobs__check_bind_name );
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getLockedObjects()
+     */
+    protected Object[] getLockedObjects()
+    {
+        return new Object[]
+            { connection };
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#executeAsyncJob(org.apache.directory.studio.connection.core.StudioProgressMonitor)
+     */
+    protected void executeAsyncJob( StudioProgressMonitor monitor )
+    {
+        monitor.beginTask( Messages.jobs__check_bind_task, 4 );
+        monitor.reportProgress( " " ); //$NON-NLS-1$
+        monitor.worked( 1 );
+
+        connection.getJNDIConnectionWrapper().connect( monitor );
+        connection.getJNDIConnectionWrapper().bind( monitor );
+        connection.getJNDIConnectionWrapper().disconnect();
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getErrorMessage()
+     */
+    protected String getErrorMessage()
+    {
+        return Messages.jobs__check_bind_error;
+    }
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckBindJob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckNetworkParameterJob.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckNetworkParameterJob.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckNetworkParameterJob.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckNetworkParameterJob.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.studio.connection.core.jobs;
+
+
+import org.apache.directory.studio.connection.core.Connection;
+import org.apache.directory.studio.connection.core.StudioProgressMonitor;
+import org.apache.directory.studio.connection.core.Messages;
+
+
+/**
+ * Job to check if a connection to a directory server could be established
+ * using the given connection parmeter.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class CheckNetworkParameterJob extends AbstractConnectionJob
+{
+
+    private Connection connection;
+
+
+    /**
+     * Creates a new instance of CheckNetworkParameterJob.
+     * 
+     * @param connection the connection
+     */
+    public CheckNetworkParameterJob( Connection connection )
+    {
+        this.connection = connection;
+        setName( Messages.jobs__check_network_name );
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getLockedObjects()
+     */
+    protected Object[] getLockedObjects()
+    {
+        return new Object[]
+            { connection };
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#executeAsyncJob(org.apache.directory.studio.connection.core.StudioProgressMonitor)
+     */
+    protected void executeAsyncJob( StudioProgressMonitor monitor )
+    {
+        monitor.beginTask( Messages.jobs__check_network_task, 3 );
+        monitor.reportProgress( " " ); //$NON-NLS-1$
+        monitor.worked( 1 );
+
+        connection.getJNDIConnectionWrapper().connect( monitor );
+        connection.getJNDIConnectionWrapper().disconnect();
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getErrorMessage()
+     */
+    protected String getErrorMessage()
+    {
+        return Messages.jobs__check_network_error;
+    }
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CheckNetworkParameterJob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CloseConnectionsJob.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CloseConnectionsJob.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CloseConnectionsJob.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CloseConnectionsJob.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.studio.connection.core.jobs;
+
+
+import org.apache.directory.studio.connection.core.Connection;
+import org.apache.directory.studio.connection.core.StudioProgressMonitor;
+import org.apache.directory.studio.connection.core.Messages;
+import org.apache.directory.studio.connection.core.event.ConnectionEventRegistry;
+
+
+/**
+ * Job to close a connection to a directory server.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class CloseConnectionsJob extends AbstractAsyncBulkJob
+{
+
+    private Connection[] connections;
+
+
+    /**
+     * Creates a new instance of CloseConnectionsJob.
+     * 
+     * @param connection the connection
+     */
+    public CloseConnectionsJob( Connection connection )
+    {
+        this( new Connection[]
+            { connection } );
+    }
+
+
+    /**
+     * Creates a new instance of CloseConnectionsJob.
+     * 
+     * @param connections the connections
+     */
+    public CloseConnectionsJob( Connection[] connections )
+    {
+        this.connections = connections;
+        setName( connections.length == 1 ? Messages.jobs__close_connections_name_1
+            : Messages.jobs__close_connections_name_n );
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getLockedObjects()
+     */
+    protected Object[] getLockedObjects()
+    {
+        return connections;
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getErrorMessage()
+     */
+    protected String getErrorMessage()
+    {
+        return connections.length == 1 ? Messages.jobs__close_connections_error_1
+            : Messages.jobs__close_connections_error_n;
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractAsyncBulkJob#executeBulkJob(org.apache.directory.studio.connection.core.StudioProgressMonitor)
+     */
+    protected void executeBulkJob( StudioProgressMonitor monitor )
+    {
+
+        monitor.beginTask( " ", connections.length * 6 + 1 ); //$NON-NLS-1$
+        monitor.reportProgress( " " ); //$NON-NLS-1$
+
+        for ( int i = 0; i < connections.length; i++ )
+        {
+            if ( connections[i].getJNDIConnectionWrapper().isConnected() )
+            {
+                monitor.setTaskName( Messages.bind( Messages.jobs__close_connections_task, new String[]
+                    { this.connections[i].getName() } ) );
+                monitor.worked( 1 );
+
+                connections[i].getJNDIConnectionWrapper().unbind();
+                connections[i].getJNDIConnectionWrapper().disconnect();
+            }
+        }
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractAsyncBulkJob#runNotification()
+     */
+    protected void runNotification()
+    {
+        for ( int i = 0; i < connections.length; i++ )
+        {
+            if ( !connections[i].getJNDIConnectionWrapper().isConnected() )
+            {
+                ConnectionEventRegistry.fireConnectionClosed( connections[i], this );
+            }
+        }
+    }
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/CloseConnectionsJob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/OpenConnectionsJob.java
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/OpenConnectionsJob.java?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/OpenConnectionsJob.java (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/OpenConnectionsJob.java Mon Nov  5 06:45:40 2007
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.studio.connection.core.jobs;
+
+
+import org.apache.directory.studio.connection.core.Connection;
+import org.apache.directory.studio.connection.core.StudioProgressMonitor;
+import org.apache.directory.studio.connection.core.Messages;
+import org.apache.directory.studio.connection.core.event.ConnectionEventRegistry;
+
+
+/**
+ * Job to open a connection to a directory server.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class OpenConnectionsJob extends AbstractAsyncBulkJob
+{
+
+    private Connection[] connections;
+
+
+    /**
+     * Creates a new instance of OpenConnectionsJob.
+     * 
+     * @param connection the connection
+     */
+    public OpenConnectionsJob( Connection connection )
+    {
+        this( new Connection[]
+            { connection } );
+    }
+
+
+    /**
+     * Creates a new instance of OpenConnectionsJob.
+     * 
+     * @param connections the connections
+     */
+    public OpenConnectionsJob( Connection[] connections )
+    {
+        this.connections = connections;
+        setName( connections.length == 1 ? Messages.jobs__open_connections_name_1
+            : Messages.jobs__open_connections_name_n );
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getLockedObjects()
+     */
+    protected Object[] getLockedObjects()
+    {
+        return connections;
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractConnectionJob#getErrorMessage()
+     */
+    protected String getErrorMessage()
+    {
+        return connections.length == 1 ? Messages.jobs__open_connections_error_1
+            : Messages.jobs__open_connections_error_n;
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractAsyncBulkJob#executeBulkJob(org.apache.directory.studio.connection.core.StudioProgressMonitor)
+     */
+    protected void executeBulkJob( StudioProgressMonitor monitor )
+    {
+
+        monitor.beginTask( " ", connections.length * 6 + 1 ); //$NON-NLS-1$
+        monitor.reportProgress( " " ); //$NON-NLS-1$
+
+        for ( int i = 0; i < connections.length; i++ )
+        {
+            if ( !connections[i].getJNDIConnectionWrapper().isConnected() )
+            {
+                monitor.setTaskName( Messages.bind( Messages.jobs__open_connections_task, new String[]
+                    { connections[i].getName() } ) );
+                monitor.worked( 1 );
+
+                connections[i].getJNDIConnectionWrapper().connect( monitor );
+                connections[i].getJNDIConnectionWrapper().bind( monitor );
+            }
+        }
+    }
+
+
+    /**
+     * @see org.apache.directory.studio.connection.core.jobs.AbstractAsyncBulkJob#runNotification()
+     */
+    protected void runNotification()
+    {
+        for ( int i = 0; i < connections.length; i++ )
+        {
+            if ( connections[i].getJNDIConnectionWrapper().isConnected() )
+            {
+                ConnectionEventRegistry.fireConnectionOpened( connections[i], this );
+            }
+        }
+    }
+
+}

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/java/org/apache/directory/studio/connection/core/jobs/OpenConnectionsJob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/XmlFileFormat.xslt
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/XmlFileFormat.xslt?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/XmlFileFormat.xslt (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/XmlFileFormat.xslt Mon Nov  5 06:45:40 2007
@@ -0,0 +1,48 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<xsl:stylesheet version="1.0" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output method="xml"/>
+   <xsl:param name="indent-increment" select="'   '" />
+
+   <xsl:template match="*">
+      <xsl:param name="indent" select="'&#xA;'"/>
+
+      <xsl:value-of select="$indent"/>
+      <xsl:copy>
+        <xsl:copy-of select="@*" />
+        <xsl:apply-templates>
+          <xsl:with-param name="indent"
+               select="concat($indent, $indent-increment)"/>
+        </xsl:apply-templates>
+        <xsl:if test="*">
+          <xsl:value-of select="$indent"/>
+        </xsl:if>
+      </xsl:copy>
+   </xsl:template>
+
+   <xsl:template match="comment()|processing-instruction()">
+      <xsl:copy />
+   </xsl:template>
+
+   <!-- WARNING: this is dangerous. Handle with care -->
+   <!-- <xsl:template match="text()[normalize-space(.)='']"/> -->
+
+</xsl:stylesheet>

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/XmlFileFormat.xslt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/messages.properties
URL: http://svn.apache.org/viewvc/directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/messages.properties?rev=592021&view=auto
==============================================================================
--- directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/messages.properties (added)
+++ directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/messages.properties Mon Nov  5 06:45:40 2007
@@ -0,0 +1,44 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+copy_n_of_s=Copy {0}of {1}
+
+model__no_auth_handler=No authentification handler
+model__no_credentials=No credentials
+
+jobs__error_occurred=Error occurred
+jobs__progressmonitor_check_cancellation=Check Cancellation
+jobs__progressmonitor_report_progress=Report Progress
+
+jobs__check_bind_name=Check Authentication
+jobs__check_bind_task=Checking authentication
+jobs__check_bind_error=The authentication failed
+jobs__check_network_name=Check Network Parameter
+jobs__check_network_task=Checking network parameter
+jobs__check_network_error=The connection failed
+
+jobs__open_connections_name_1=Open Connection
+jobs__open_connections_name_n=Open Connections
+jobs__open_connections_task=Opening connection {0}
+jobs__open_connections_error_1=Error while opening connection
+jobs__open_connections_error_n=Error while opening connections
+
+jobs__close_connections_name_1=Close Connection
+jobs__close_connections_name_n=Close Connections
+jobs__close_connections_task=Closing connection {0}
+jobs__close_connections_error_1=Error while closing connection
+jobs__close_connections_error_n=Error while closing connections

Propchange: directory/sandbox/felixk/studio-connection-core/src/main/resources/org/apache/directory/studio/connection/core/messages.properties
------------------------------------------------------------------------------
    svn:eol-style = native