View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" 
13   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.security.spi.impl.ldap;
18  
19  import java.lang.reflect.InvocationHandler;
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  import java.lang.reflect.Proxy;
23  import java.util.Properties;
24  
25  import javax.naming.CommunicationException;
26  import javax.naming.Context;
27  import javax.naming.NamingException;
28  import javax.naming.ServiceUnavailableException;
29  import javax.naming.ldap.InitialLdapContext;
30  import javax.naming.ldap.LdapContext;
31  
32  import org.apache.commons.lang.StringUtils;
33  
34  /***
35   * Proxy providing recoverable LdapContext connections.
36   * 
37   * @author <a href="mailto:ate@douma.nu">Ate Douma</a>
38   * @version $Id: LdapContextProxy.java 516448 2007-03-09 16:25:47Z ate $
39   */
40  public class LdapContextProxy implements InvocationHandler
41  {
42      private Properties env;
43      private LdapContext ctx;
44      
45      public static LdapContext createProxy(LdapBindingConfig config)
46      {
47          LdapContext proxy = config.getContext();
48          
49          if ( proxy == null || !(Proxy.getInvocationHandler(proxy) instanceof LdapContextProxy))
50          {
51              proxy = (LdapContext)Proxy.newProxyInstance(LdapContext.class.getClassLoader(),new Class[]{LdapContext.class}, new LdapContextProxy(config));
52              config.setContext(proxy);
53          }
54          return proxy;
55      }
56      
57      private LdapContextProxy(LdapBindingConfig ldapBindingConfig)
58      {
59          env = new Properties();
60          env.put(Context.INITIAL_CONTEXT_FACTORY, ldapBindingConfig.getInitialContextFactory());
61          env.put(Context.PROVIDER_URL, ldapBindingConfig.getLdapScheme() + "://" + ldapBindingConfig.getLdapServerName() + ":"
62                  + ldapBindingConfig.getLdapServerPort() + "/" + ldapBindingConfig.getRootContext());
63          env.put(Context.SECURITY_PRINCIPAL, ldapBindingConfig.getRootDn());
64          env.put(Context.SECURITY_CREDENTIALS, ldapBindingConfig.getRootPassword());
65          env.put(Context.SECURITY_AUTHENTICATION, ldapBindingConfig.getLdapSecurityLevel());
66          if ( !StringUtils.isEmpty(ldapBindingConfig.getLdapSecurityProtocol()) )
67          {
68              env.put(Context.SECURITY_PROTOCOL, ldapBindingConfig.getLdapSecurityProtocol());
69          }
70          if ( !StringUtils.isEmpty(ldapBindingConfig.getLdapSocketFactory()) )
71          {
72              env.put("java.naming.ldap.factory.socket", ldapBindingConfig.getLdapSocketFactory());
73          }
74      }
75      
76      private LdapContext getCtx() throws NamingException
77      {
78          if ( ctx == null )
79          {
80              ctx = new InitialLdapContext(env, null);
81          }
82          return ctx;
83      }
84      
85      private void closeCtx()
86      {
87          if ( ctx != null )
88          {
89              try
90              {
91                  ctx.close();
92              }
93              catch (Exception e)
94              {
95              }
96              ctx = null;
97          }
98      }
99      /*
100      * (non-Javadoc)
101      * 
102      * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
103      *      java.lang.reflect.Method, java.lang.Object[])
104      */
105     public synchronized Object invoke(Object proxy, Method m, Object[] args) throws Throwable
106     {
107         Object result = null;
108         boolean close = "close".equals(m.getName()) && args.length == 0;
109         if ( close && ctx == null )
110         {
111             // don't need to do anything
112             ;
113         }
114         else
115         {
116             LdapContext ctx = getCtx();
117             
118             try
119             {
120                 result = m.invoke(ctx,args);
121                 if ( close )
122                 {
123                     closeCtx();
124                 }
125             }
126             catch (Throwable t)
127             {
128                 closeCtx();
129                 
130                 if ( t instanceof InvocationTargetException)
131                 {
132                     t = ((InvocationTargetException)t).getTargetException();
133                 }
134                 if (t instanceof ServiceUnavailableException || t instanceof CommunicationException)
135                 {
136                     try
137                     {
138                         ctx = getCtx();
139                         result = m.invoke(ctx,args);
140                     }
141                     catch (Throwable t2)
142                     {
143                         closeCtx();
144                         if ( t2 instanceof InvocationTargetException)
145                         {
146                             t2 = ((InvocationTargetException)t2).getTargetException();
147                         }
148                         
149                         throw t2;
150                     }
151                 }
152                 throw t;
153             }
154         }
155         return result;
156     }
157 }