Source Code Cross Referenced for LdapContextImpl.java in  » Apache-Harmony-Java-SE » org-package » org » apache » harmony » jndi » provider » ldap » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Apache Harmony Java SE » org package » org.apache.harmony.jndi.provider.ldap 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* 
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more 
0003:         *  contributor license agreements.  See the NOTICE file distributed with 
0004:         *  this work for additional information regarding copyright ownership. 
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0 
0006:         *  (the "License"); you may not use this file except in compliance with 
0007:         *  the License.  You may obtain a copy of the License at 
0008:         * 
0009:         *     http://www.apache.org/licenses/LICENSE-2.0 
0010:         * 
0011:         *  Unless required by applicable law or agreed to in writing, software 
0012:         *  distributed under the License is distributed on an "AS IS" BASIS, 
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
0014:         *  See the License for the specific language governing permissions and 
0015:         *  limitations under the License. 
0016:         */
0017:
0018:        package org.apache.harmony.jndi.provider.ldap;
0019:
0020:        import java.io.ByteArrayInputStream;
0021:        import java.io.ByteArrayOutputStream;
0022:        import java.io.IOException;
0023:        import java.io.ObjectInputStream;
0024:        import java.io.ObjectOutputStream;
0025:        import java.io.Serializable;
0026:        import java.util.ArrayList;
0027:        import java.util.Enumeration;
0028:        import java.util.EventObject;
0029:        import java.util.HashMap;
0030:        import java.util.HashSet;
0031:        import java.util.Hashtable;
0032:        import java.util.Iterator;
0033:        import java.util.List;
0034:        import java.util.Map;
0035:        import java.util.Set;
0036:        import java.util.StringTokenizer;
0037:        import java.util.TreeMap;
0038:
0039:        import javax.naming.AuthenticationNotSupportedException;
0040:        import javax.naming.Binding;
0041:        import javax.naming.CannotProceedException;
0042:        import javax.naming.CommunicationException;
0043:        import javax.naming.CompositeName;
0044:        import javax.naming.ConfigurationException;
0045:        import javax.naming.Context;
0046:        import javax.naming.InvalidNameException;
0047:        import javax.naming.LimitExceededException;
0048:        import javax.naming.Name;
0049:        import javax.naming.NameClassPair;
0050:        import javax.naming.NameNotFoundException;
0051:        import javax.naming.NameParser;
0052:        import javax.naming.NamingEnumeration;
0053:        import javax.naming.NamingException;
0054:        import javax.naming.PartialResultException;
0055:        import javax.naming.RefAddr;
0056:        import javax.naming.Reference;
0057:        import javax.naming.Referenceable;
0058:        import javax.naming.ReferralException;
0059:        import javax.naming.StringRefAddr;
0060:        import javax.naming.directory.Attribute;
0061:        import javax.naming.directory.Attributes;
0062:        import javax.naming.directory.BasicAttribute;
0063:        import javax.naming.directory.BasicAttributes;
0064:        import javax.naming.directory.DirContext;
0065:        import javax.naming.directory.InvalidSearchFilterException;
0066:        import javax.naming.directory.ModificationItem;
0067:        import javax.naming.directory.SearchControls;
0068:        import javax.naming.directory.SearchResult;
0069:        import javax.naming.event.EventContext;
0070:        import javax.naming.event.EventDirContext;
0071:        import javax.naming.event.NamespaceChangeListener;
0072:        import javax.naming.event.NamingEvent;
0073:        import javax.naming.event.NamingExceptionEvent;
0074:        import javax.naming.event.NamingListener;
0075:        import javax.naming.event.ObjectChangeListener;
0076:        import javax.naming.ldap.Control;
0077:        import javax.naming.ldap.ControlFactory;
0078:        import javax.naming.ldap.ExtendedRequest;
0079:        import javax.naming.ldap.ExtendedResponse;
0080:        import javax.naming.ldap.LdapContext;
0081:        import javax.naming.ldap.LdapName;
0082:        import javax.naming.ldap.ManageReferralControl;
0083:        import javax.naming.ldap.Rdn;
0084:        import javax.naming.ldap.UnsolicitedNotificationEvent;
0085:        import javax.naming.ldap.UnsolicitedNotificationListener;
0086:        import javax.naming.spi.DirectoryManager;
0087:        import javax.naming.spi.NamingManager;
0088:        import javax.naming.spi.DirStateFactory.Result;
0089:
0090:        import org.apache.harmony.jndi.internal.nls.Messages;
0091:        import org.apache.harmony.jndi.internal.parser.AttributeTypeAndValuePair;
0092:        import org.apache.harmony.jndi.internal.parser.LdapNameParser;
0093:        import org.apache.harmony.jndi.provider.ldap.asn1.Utils;
0094:        import org.apache.harmony.jndi.provider.ldap.event.ECNotificationControl;
0095:        import org.apache.harmony.jndi.provider.ldap.event.PersistentSearchResult;
0096:        import org.apache.harmony.jndi.provider.ldap.ext.StartTlsResponseImpl;
0097:        import org.apache.harmony.jndi.provider.ldap.parser.FilterParser;
0098:        import org.apache.harmony.jndi.provider.ldap.parser.LdapUrlParser;
0099:        import org.apache.harmony.jndi.provider.ldap.parser.ParseException;
0100:        import org.apache.harmony.jndi.provider.ldap.sasl.SaslBind;
0101:
0102:        /**
0103:         * This context implements LdapContext, it's main entry point of all JNDI ldap
0104:         * operations.
0105:         */
0106:        public class LdapContextImpl implements  LdapContext, EventDirContext {
0107:
0108:            /**
0109:             * ldap connection
0110:             */
0111:            private LdapClient client;
0112:
0113:            private boolean isClosed;
0114:
0115:            /**
0116:             * name of the context
0117:             */
0118:            protected Name contextDn;
0119:
0120:            private Control[] requestControls;
0121:
0122:            private Control[] responseControls;
0123:
0124:            /**
0125:             * environment properties for this context
0126:             */
0127:            protected Hashtable<Object, Object> env;
0128:
0129:            /**
0130:             * name parser for this context
0131:             */
0132:            private NameParser parser;
0133:
0134:            /**
0135:             * connection controls for this context
0136:             */
0137:            private Control[] connCtls;
0138:
0139:            private HashMap<NamingListener, List<Integer>> listeners;
0140:
0141:            private List<UnsolicitedNotificationListener> unls;
0142:
0143:            private static final Control NON_CRITICAL_MANAGE_REF_CONTROL = new ManageReferralControl(
0144:                    Control.NONCRITICAL);
0145:
0146:            private static final String LDAP_DELETE_RDN = "java.naming.ldap.deleteRDN"; //$NON-NLS-1$
0147:
0148:            private static final String LDAP_DEREF_ALIASES = "java.naming.ldap.derefAliases"; //$NON-NLS-1$
0149:
0150:            private static final String LDAP_CONTROL_CONNECT = "java.naming.ldap.control.connect"; //$NON-NLS-1$
0151:
0152:            private static final String LDAP_TYPES_ONLY = "java.naming.ldap.typesOnly"; //$NON-NLS-1$
0153:
0154:            /**
0155:             * Some properties, such as 'java.naming.security.authentication', changed
0156:             * by <code>Context.addToEnvironment</code> or
0157:             * <code>Context.removeFromEnvironment</code> may affect connection with
0158:             * LDAP server. This variable contains all such properties, which need
0159:             * re-communication with LDAP server after changing.
0160:             */
0161:            private static final HashSet<String> connectionProperties = new HashSet<String>();
0162:
0163:            static {
0164:                connectionProperties.add(Context.SECURITY_AUTHENTICATION);
0165:                connectionProperties.add(Context.SECURITY_CREDENTIALS);
0166:                connectionProperties.add(Context.SECURITY_PRINCIPAL);
0167:                connectionProperties.add(Context.SECURITY_PROTOCOL);
0168:                connectionProperties.add("java.naming.ldap.factory.socket"); //$NON-NLS-1$
0169:            }
0170:
0171:            /**
0172:             * construct a new inherit <code>LdapContextImpl</code>
0173:             * 
0174:             * @param context
0175:             * @param environment
0176:             * @param dn
0177:             * @throws InvalidNameException
0178:             */
0179:            public LdapContextImpl(LdapContextImpl context,
0180:                    Hashtable<Object, Object> environment, String dn)
0181:                    throws InvalidNameException {
0182:                initial(context.client, environment, dn);
0183:
0184:                // connection request controls are inheritied
0185:                connCtls = context.connCtls;
0186:                // request controls are not inheritied
0187:            }
0188:
0189:            /**
0190:             * construct a new <code>LdapContextImpl</code> with a fresh
0191:             * <code>LdapClient</code> which didn't do ldap bind operation yet.
0192:             * 
0193:             * @param client
0194:             * @param environment
0195:             * @param dn
0196:             * @throws NamingException
0197:             */
0198:            public LdapContextImpl(LdapClient client,
0199:                    Hashtable<Object, Object> environment, String dn)
0200:                    throws NamingException {
0201:                initial(client, environment, dn);
0202:
0203:                try {
0204:                    doBindOperation(connCtls);
0205:                } catch (IOException e) {
0206:                    CommunicationException ex = new CommunicationException();
0207:                    ex.setRootCause(e);
0208:                    throw ex;
0209:                }
0210:            }
0211:
0212:            private void initial(LdapClient ldapClient,
0213:                    Hashtable<Object, Object> environment, String dn)
0214:                    throws InvalidNameException {
0215:                this .client = ldapClient;
0216:                if (environment == null) {
0217:                    this .env = new Hashtable<Object, Object>();
0218:                } else {
0219:                    this .env = (Hashtable<Object, Object>) environment.clone();
0220:                }
0221:
0222:                contextDn = new LdapName(dn);
0223:                parser = new LdapNameParser(dn);
0224:
0225:                if (env.get(Context.REFERRAL) == null
0226:                        || env.get(Context.REFERRAL).equals("ignore")) { //$NON-NLS-1$
0227:                    requestControls = new Control[] { NON_CRITICAL_MANAGE_REF_CONTROL };
0228:                }
0229:
0230:                connCtls = (Control[]) env.get(LDAP_CONTROL_CONNECT);
0231:            }
0232:
0233:            /**
0234:             * Perform a LDAP Bind operation.
0235:             * 
0236:             * @param env
0237:             * @throws IOException
0238:             * @throws IOException
0239:             * @throws NamingException
0240:             * @throws ParseException
0241:             */
0242:            private void doBindOperation(Control[] connCtsl)
0243:                    throws IOException, NamingException {
0244:
0245:                SaslBind saslBind = new SaslBind();
0246:                LdapResult result = null;
0247:
0248:                SaslBind.AuthMech authMech = saslBind.valueAuthMech(env);
0249:                if (authMech == SaslBind.AuthMech.None) {
0250:                    BindOp bind = new BindOp("", "", null, null);
0251:                    client.doOperation(bind, connCtsl);
0252:                    result = bind.getResult();
0253:                } else if (authMech == SaslBind.AuthMech.Simple) {
0254:                    String principal = (String) env
0255:                            .get(Context.SECURITY_PRINCIPAL);
0256:                    String credential = Utils.getString(env
0257:                            .get(Context.SECURITY_CREDENTIALS));
0258:                    BindOp bind = new BindOp(principal, credential, null, null);
0259:                    client.doOperation(bind, connCtsl);
0260:                    result = bind.getResult();
0261:                } else if (authMech == SaslBind.AuthMech.SASL) {
0262:                    result = saslBind
0263:                            .doSaslBindOperation(env, client, connCtsl);
0264:                }
0265:
0266:                if (LdapUtils.getExceptionFromResult(result) != null) {
0267:                    throw LdapUtils.getExceptionFromResult(result);
0268:                }
0269:            }
0270:
0271:            public ExtendedResponse extendedOperation(ExtendedRequest request)
0272:                    throws NamingException {
0273:                ExtendedOp op = new ExtendedOp(request);
0274:                try {
0275:                    doBasicOperation(op);
0276:                } catch (ReferralException e) {
0277:                    if (isFollowReferral(e)) {
0278:                        LdapContext referralContext = (LdapContext) getReferralContext(e);
0279:                        return referralContext.extendedOperation(request);
0280:                    }
0281:                    throw e;
0282:                }
0283:                ExtendedResponse response = op.getExtendedResponse();
0284:                // set existing underlying socket to startTls extended response
0285:                if (response instanceof  StartTlsResponseImpl) {
0286:                    ((StartTlsResponseImpl) response).setSocket(client
0287:                            .getSocket());
0288:                }
0289:                return response;
0290:            }
0291:
0292:            public Control[] getConnectControls() throws NamingException {
0293:                return copyControls(connCtls);
0294:            }
0295:
0296:            public Control[] getRequestControls() throws NamingException {
0297:                return copyControls(requestControls);
0298:            }
0299:
0300:            public Control[] getResponseControls() throws NamingException {
0301:                return copyControls(responseControls);
0302:            }
0303:
0304:            private Control[] copyControls(Control[] controls) {
0305:                if (controls == null) {
0306:                    return null;
0307:                }
0308:
0309:                Control[] rtValue = new Control[controls.length];
0310:                System.arraycopy(controls, 0, rtValue, 0, controls.length);
0311:                return rtValue;
0312:            }
0313:
0314:            public LdapContext newInstance(Control[] reqCtrls)
0315:                    throws NamingException {
0316:                LdapContextImpl instance = new LdapContextImpl(this , env,
0317:                        contextDn.toString());
0318:                instance.setRequestControls(reqCtrls);
0319:                return instance;
0320:            }
0321:
0322:            public void reconnect(Control[] ac) throws NamingException {
0323:                connCtls = ac;
0324:                try {
0325:                    doBindOperation(connCtls);
0326:                } catch (IOException e) {
0327:                    CommunicationException ex = new CommunicationException();
0328:                    ex.setRootCause(e);
0329:                    throw ex;
0330:                }
0331:            }
0332:
0333:            public void setRequestControls(Control[] controls)
0334:                    throws NamingException {
0335:                boolean hasManageDsaITConntrol = false;
0336:
0337:                if (env.get(Context.REFERRAL) == null
0338:                        || env.get(Context.REFERRAL).equals("ignore")) {
0339:                    hasManageDsaITConntrol = true;
0340:                }
0341:
0342:                if (controls == null) {
0343:                    if (hasManageDsaITConntrol) {
0344:                        requestControls = new Control[] { NON_CRITICAL_MANAGE_REF_CONTROL };
0345:                    } else {
0346:                        requestControls = null;
0347:                    }
0348:                    return;
0349:                }
0350:
0351:                if (hasManageDsaITConntrol) {
0352:                    requestControls = new Control[controls.length + 1];
0353:                    System.arraycopy(controls, 0, requestControls, 0,
0354:                            controls.length);
0355:                    requestControls[controls.length] = NON_CRITICAL_MANAGE_REF_CONTROL;
0356:                } else {
0357:                    requestControls = new Control[controls.length];
0358:                    System.arraycopy(controls, 0, requestControls, 0,
0359:                            controls.length);
0360:                }
0361:            }
0362:
0363:            public void bind(Name name, Object obj, Attributes attributes)
0364:                    throws NamingException {
0365:                checkName(name);
0366:
0367:                if (name instanceof  CompositeName && name.size() > 1) {
0368:                    /*
0369:                     * multi ns, find next ns context, delegate operation to the next
0370:                     * contex
0371:                     */
0372:                    DirContext nns = (DirContext) findNnsContext(name);
0373:                    Name remainingName = name.getSuffix(1);
0374:                    nns.bind(remainingName, attributes);
0375:                    return;
0376:                }
0377:
0378:                /*
0379:                 * there is only one ldap ns
0380:                 */
0381:                if (obj == null && attributes == null) {
0382:                    // ldap.2E=cannot bind null object without attributes
0383:                    throw new IllegalArgumentException(Messages
0384:                            .getString("ldap.2E")); //$NON-NLS-1$
0385:                }
0386:
0387:                if (obj == null) {
0388:                    createSubcontext(name, attributes);
0389:                    return;
0390:                }
0391:
0392:                Result result = DirectoryManager.getStateToBind(obj, name,
0393:                        this , env, attributes);
0394:                Object o = result.getObject();
0395:
0396:                Attributes attrs = null;
0397:
0398:                if (o instanceof  Reference) {
0399:                    attrs = convertRefToAttribute((Reference) o);
0400:                } else if (o instanceof  Referenceable) {
0401:                    attrs = convertRefToAttribute(((Referenceable) o)
0402:                            .getReference());
0403:                } else if (o instanceof  Serializable) {
0404:                    attrs = convertSerialToAttribute((Serializable) o);
0405:                } else if (o instanceof  DirContext) {
0406:                    DirContext cxt = (DirContext) o;
0407:                    attrs = cxt.getAttributes("");
0408:                } else {
0409:                    throw new IllegalArgumentException(Messages
0410:                            .getString("ldap.24")); //$NON-NLS-1$
0411:                }
0412:
0413:                NamingEnumeration<? extends Attribute> enu = attrs.getAll();
0414:                if (result.getAttributes() != null) {
0415:                    Attributes resultAttributes = result.getAttributes();
0416:
0417:                    while (enu.hasMore()) {
0418:                        Attribute element = enu.next();
0419:                        if (element.getID().equalsIgnoreCase("objectClass")) {
0420:                            element = mergeAttribute(resultAttributes
0421:                                    .get("objectClass"), element);
0422:                            if (resultAttributes.get("objectClass") != null) {
0423:                                element.remove("javaContainer");
0424:                            }
0425:                            resultAttributes.put(element);
0426:                        } else if (resultAttributes.get(element.getID()) == null) {
0427:                            resultAttributes.put(element);
0428:                        }
0429:                    }
0430:
0431:                    createSubcontext(name, resultAttributes);
0432:                } else {
0433:                    createSubcontext(name, attrs);
0434:                }
0435:            }
0436:
0437:            private Attributes convertSerialToAttribute(
0438:                    Serializable serializable) throws NamingException {
0439:                Attributes attrs = new BasicAttributes();
0440:
0441:                Attribute objectClass = new BasicAttribute("objectClass");
0442:                objectClass.add("top");
0443:                objectClass.add("javaContainer");
0444:                objectClass.add("javaObject");
0445:                objectClass.add("javaSerializedObject");
0446:                attrs.put(objectClass);
0447:
0448:                Attribute javaClassNames = new BasicAttribute("javaClassNames");
0449:                javaClassNames.add(serializable.getClass().getName());
0450:                javaClassNames.add(Object.class.getName());
0451:
0452:                Class[] cs = serializable.getClass().getInterfaces();
0453:                for (Class c : cs) {
0454:                    javaClassNames.add(c.getName());
0455:                }
0456:
0457:                // add all ancestors class
0458:                Class sup = serializable.getClass().getSuperclass();
0459:                while (sup != null
0460:                        && !sup.getName().equals(Object.class.getName())) {
0461:                    javaClassNames.add(sup.getName());
0462:                    sup = sup.getSuperclass();
0463:                }
0464:                attrs.put(javaClassNames);
0465:
0466:                attrs.put("javaClassName", serializable.getClass().getName());
0467:
0468:                ByteArrayOutputStream bout = new ByteArrayOutputStream();
0469:
0470:                try {
0471:                    ObjectOutputStream out = new ObjectOutputStream(bout);
0472:                    out.writeObject(serializable);
0473:                    out.close();
0474:                } catch (IOException e) {
0475:                    // TODO need add more detail messages?
0476:                    NamingException ex = new NamingException();
0477:                    ex.setRootCause(e);
0478:                    throw ex;
0479:                }
0480:
0481:                byte[] bytes = bout.toByteArray();
0482:                attrs.put("javaSerializedData", bytes);
0483:
0484:                return attrs;
0485:            }
0486:
0487:            private Attributes convertRefToAttribute(Reference ref) {
0488:                Attributes attrs = new BasicAttributes();
0489:
0490:                Attribute objectClass = new BasicAttribute("objectClass");
0491:                objectClass.add("top");
0492:                objectClass.add("javaContainer");
0493:                objectClass.add("javaObject");
0494:                objectClass.add("javaNamingReference");
0495:                attrs.put(objectClass);
0496:
0497:                Attribute className = new BasicAttribute("javaClassName");
0498:                className.add(ref.getClassName());
0499:                attrs.put(className);
0500:
0501:                Attribute address = new BasicAttribute("javaReferenceAddress");
0502:                Enumeration<RefAddr> enu = ref.getAll();
0503:                int index = 0;
0504:                String separator = (String) env
0505:                        .get("java.naming.ldap.ref.separator");
0506:                if (separator == null) {
0507:                    // use default separator '#'
0508:                    separator = "#";
0509:                }
0510:                while (enu.hasMoreElements()) {
0511:                    RefAddr addr = enu.nextElement();
0512:                    StringBuilder builder = new StringBuilder();
0513:                    builder.append(separator + index);
0514:                    builder.append(separator + addr.getType());
0515:                    builder.append(separator + addr.getContent());
0516:                    address.add(builder.toString());
0517:                    index++;
0518:                }
0519:                attrs.put(address);
0520:
0521:                return attrs;
0522:            }
0523:
0524:            public void bind(String s, Object obj, Attributes attributes)
0525:                    throws NamingException {
0526:                bind(convertFromStringToName(s), obj, attributes);
0527:            }
0528:
0529:            public DirContext createSubcontext(Name name, Attributes attributes)
0530:                    throws NamingException {
0531:                checkName(name);
0532:
0533:                if (name instanceof  CompositeName && name.size() > 1) {
0534:                    /*
0535:                     * multi ns, find next ns context, delegate operation to the next
0536:                     * context
0537:                     */
0538:                    DirContext nns = (DirContext) findNnsContext(name);
0539:                    Name remainingName = name.getSuffix(1);
0540:                    return nns.createSubcontext(remainingName, attributes);
0541:                }
0542:
0543:                /*
0544:                 * there is only one ldap ns
0545:                 */
0546:
0547:                if (attributes == null) {
0548:                    attributes = new BasicAttributes();
0549:                    Attribute attr = new LdapAttribute("objectClass", this );
0550:                    attr.add("top");
0551:                    attr.add("javaContainer");
0552:                    attributes.put(attr);
0553:                }
0554:
0555:                // get absolute dn name
0556:                String targetDN = getTargetDN(name, contextDn);
0557:                // merge attributes from dn and args
0558:                Attributes attrs = mergeAttributes(attributes,
0559:                        getAttributesFromDN(name));
0560:
0561:                // convert to LdapAttribute
0562:                List<LdapAttribute> la = new ArrayList<LdapAttribute>(attrs
0563:                        .size());
0564:                NamingEnumeration<? extends Attribute> enu = attrs.getAll();
0565:                while (enu.hasMore()) {
0566:                    la.add(new LdapAttribute(enu.next(), this ));
0567:                }
0568:
0569:                // do add operation
0570:                AddOp op = new AddOp(targetDN, la);
0571:                try {
0572:                    doBasicOperation(op);
0573:                } catch (ReferralException e) {
0574:                    if (isFollowReferral(e)) {
0575:                        DirContext referralContext = getReferralContext(e);
0576:                        return referralContext.createSubcontext(name,
0577:                                attributes);
0578:                    }
0579:                    throw e;
0580:                }
0581:
0582:                LdapResult result = op.getResult();
0583:                return new LdapContextImpl(this , env, result.getMachedDN());
0584:            }
0585:
0586:            private DirContext getReferralContext(ReferralException e)
0587:                    throws LimitExceededException, NamingException {
0588:                int limit = 0;
0589:                if (env.get("java.naming.ldap.referral.limit") != null) {
0590:                    limit = Integer
0591:                            .valueOf(
0592:                                    (String) env
0593:                                            .get("java.naming.ldap.referral.limit"))
0594:                            .intValue();
0595:                }
0596:
0597:                if (limit == -1) {
0598:                    throw new LimitExceededException(Messages
0599:                            .getString("ldap.25")); //$NON-NLS-1$
0600:                }
0601:
0602:                if (limit == 1) {
0603:                    limit = -1;
0604:                } else if (limit != 0) {
0605:                    limit -= 1;
0606:                }
0607:
0608:                Hashtable<Object, Object> newEnv = (Hashtable<Object, Object>) env
0609:                        .clone();
0610:                newEnv.put("java.naming.ldap.referral.limit", String
0611:                        .valueOf(limit));
0612:                DirContext referralContext = null;
0613:
0614:                while (true) {
0615:                    try {
0616:                        referralContext = (DirContext) e
0617:                                .getReferralContext(newEnv);
0618:                        break;
0619:                    } catch (NamingException ex) {
0620:                        if (e.skipReferral()) {
0621:                            continue;
0622:                        }
0623:                        throw ex;
0624:                    }
0625:                }
0626:
0627:                return referralContext;
0628:            }
0629:
0630:            /**
0631:             * merge two instanceof <code>Attributes</code> to one
0632:             * 
0633:             * @param first
0634:             * @param second
0635:             * @return
0636:             * @throws NamingException
0637:             */
0638:            private Attributes mergeAttributes(Attributes first,
0639:                    Attributes second) throws NamingException {
0640:                if (first == null) {
0641:                    return second;
0642:                }
0643:
0644:                if (second == null) {
0645:                    return first;
0646:                }
0647:
0648:                BasicAttributes attrs = new BasicAttributes();
0649:                NamingEnumeration<? extends Attribute> enu = first.getAll();
0650:                while (enu.hasMore()) {
0651:                    attrs.put(enu.next());
0652:                }
0653:
0654:                enu = second.getAll();
0655:                while (enu.hasMore()) {
0656:                    Attribute element = enu.next();
0657:                    element = mergeAttribute(element, attrs
0658:                            .get(element.getID()));
0659:                    attrs.put(element);
0660:                }
0661:
0662:                return attrs;
0663:            }
0664:
0665:            /**
0666:             * merge two instance of <code>Attribute</code> to one
0667:             * 
0668:             * @param first
0669:             * @param second
0670:             * @return
0671:             * @throws NamingException
0672:             */
0673:            private Attribute mergeAttribute(Attribute first, Attribute second)
0674:                    throws NamingException {
0675:                if (first == null) {
0676:                    return second;
0677:                }
0678:
0679:                if (second == null) {
0680:                    return first;
0681:                }
0682:
0683:                Attribute attr = new LdapAttribute(first.getID(), this );
0684:                NamingEnumeration<?> enu = first.getAll();
0685:                while (enu.hasMore()) {
0686:                    attr.add(enu.next());
0687:                }
0688:
0689:                enu = second.getAll();
0690:                while (enu.hasMore()) {
0691:                    attr.add(enu.next());
0692:                }
0693:
0694:                return attr;
0695:            }
0696:
0697:            public DirContext createSubcontext(String s, Attributes attributes)
0698:                    throws NamingException {
0699:                return createSubcontext(convertFromStringToName(s), attributes);
0700:            }
0701:
0702:            public Attributes getAttributes(Name name) throws NamingException {
0703:                return getAttributes(name, null);
0704:            }
0705:
0706:            public Attributes getAttributes(Name name, String[] as)
0707:                    throws NamingException {
0708:                checkName(name);
0709:
0710:                if (name instanceof  CompositeName && name.size() > 1) {
0711:                    if (!(name.getPrefix(0) instanceof  LdapName)) {
0712:                        throw new InvalidNameException(Messages
0713:                                .getString("ldap.26")); //$NON-NLS-1$
0714:                    }
0715:                    /*
0716:                     * multi ns, find next ns context, delegate operation to the next
0717:                     * context
0718:                     */
0719:                    DirContext nns = (DirContext) findNnsContext(name);
0720:                    Name remainingName = name.getSuffix(1);
0721:                    return nns.getAttributes(remainingName, as);
0722:                }
0723:
0724:                /*
0725:                 * there is only one ldap ns
0726:                 */
0727:                // absolute dn name to list
0728:                String targetDN = getTargetDN(name, contextDn);
0729:
0730:                // construct one-level search using filter "(objectclass=*)"
0731:                SearchControls controls = new SearchControls();
0732:                controls.setSearchScope(SearchControls.OBJECT_SCOPE);
0733:
0734:                /*
0735:                 * none should be retrieved, send OID "1.1" to server, according to RFC
0736:                 * 2251, 4.5.1
0737:                 */
0738:                if (as != null && as.length == 0) {
0739:                    // "1.1" means no attributes should return
0740:                    as = new String[] { "1.1" }; //$NON-NLS-1$
0741:                }
0742:                controls.setReturningAttributes(as);
0743:
0744:                Filter filter = new Filter(Filter.PRESENT_FILTER);
0745:                filter.setValue("objectClass");
0746:
0747:                LdapSearchResult result = doSearch(targetDN, filter, controls);
0748:                Iterator<Attributes> it = result.getEntries().values()
0749:                        .iterator();
0750:                if (it.hasNext()) {
0751:                    Attributes attributes = it.next();
0752:                    NamingEnumeration<String> ids = attributes.getIDs();
0753:                    while (ids.hasMore()) {
0754:                        LdapAttribute attribute = (LdapAttribute) attributes
0755:                                .get(ids.next());
0756:                        attribute.setContext(this );
0757:                    }
0758:
0759:                    // FIXME: there must be only one Attributes?
0760:                    return attributes;
0761:                } else if (result.getException() != null) {
0762:                    throw result.getException();
0763:                }
0764:
0765:                // no attribute retrieved from server, return a empty Attributes
0766:                return new BasicAttributes();
0767:            }
0768:
0769:            public Attributes getAttributes(String s) throws NamingException {
0770:                return getAttributes(convertFromStringToName(s));
0771:            }
0772:
0773:            public Attributes getAttributes(String s, String[] as)
0774:                    throws NamingException {
0775:                return getAttributes(convertFromStringToName(s), as);
0776:            }
0777:
0778:            public static Hashtable<String, Hashtable<String, Hashtable<String, Object>>> schemaTree = new Hashtable<String, Hashtable<String, Hashtable<String, Object>>>();
0779:
0780:            private LdapSchemaContextImpl ldapSchemaCtx = null;
0781:
0782:            protected String subschemasubentry = null;
0783:
0784:            public DirContext getSchema(Name name) throws NamingException {
0785:                checkName(name);
0786:                if (null != ldapSchemaCtx)
0787:                    return ldapSchemaCtx;
0788:
0789:                SearchControls searchControls = new SearchControls();
0790:                SearchOp search = null;
0791:                Filter filter = null;
0792:                FilterParser filterParser = null;
0793:                LdapSearchResult sre = null;
0794:                Map<String, Attributes> names = null;
0795:                Set<String> keyset = null;
0796:
0797:                if (name.size() != 0) {
0798:                    subschemasubentry = name.toString() + ","
0799:                            + contextDn.toString();
0800:                }
0801:                if (null == subschemasubentry) {
0802:                    filterParser = new FilterParser("(objectClass=*)");
0803:                    try {
0804:                        filter = filterParser.parse();
0805:                    } catch (ParseException e) {
0806:                        InvalidSearchFilterException ex = new InvalidSearchFilterException(
0807:                                Messages.getString("ldap.29")); //$NON-NLS-1$
0808:                        ex.setRootCause(e);
0809:                        throw ex;
0810:                    }
0811:
0812:                    searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
0813:                    searchControls
0814:                            .setReturningAttributes(new String[] {
0815:                                    "namingContexts", "subschemaSubentry",
0816:                                    "altServer", });
0817:                    search = new SearchOp("", searchControls, filter);
0818:
0819:                    try {
0820:                        client.doOperation(search, requestControls);
0821:                    } catch (IOException e) {
0822:                        CommunicationException ex = new CommunicationException(
0823:                                e.getMessage());
0824:                        ex.setRootCause(e);
0825:                        if (search.getSearchResult().isEmpty()) {
0826:                            throw ex;
0827:                        }
0828:                        search.getSearchResult().setException(ex);
0829:                    }
0830:
0831:                    sre = search.getSearchResult();
0832:                    names = sre.getEntries();
0833:
0834:                    keyset = names.keySet();
0835:                    schemaRoot: for (Iterator<String> iterator = keyset
0836:                            .iterator(); iterator.hasNext();) {
0837:                        String key = iterator.next();
0838:                        Attributes as = names.get(key);
0839:                        NamingEnumeration<String> ids = as.getIDs();
0840:                        while (ids.hasMore()) {
0841:                            String id = ids.next();
0842:                            if (id.equalsIgnoreCase("subschemasubentry")) {
0843:                                subschemasubentry = (String) as.get(id).get();
0844:                                break schemaRoot;
0845:                            }
0846:                        }
0847:                    }
0848:                }
0849:
0850:                searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
0851:                searchControls.setReturningAttributes(new String[] {
0852:                        "objectclasses", "attributetypes", "matchingrules",
0853:                        "ldapsyntaxes" });
0854:                searchControls.setReturningObjFlag(true);
0855:                filterParser = new FilterParser("(objectClass=subschema)");
0856:                try {
0857:                    filter = filterParser.parse();
0858:                } catch (ParseException e) {
0859:                    InvalidSearchFilterException ex = new InvalidSearchFilterException(
0860:                            Messages.getString("ldap.29")); //$NON-NLS-1$
0861:                    ex.setRootCause(e);
0862:                    throw ex;
0863:                }
0864:                search = new SearchOp(subschemasubentry, searchControls, filter);
0865:
0866:                try {
0867:                    client.doOperation(search, requestControls);
0868:                } catch (IOException e) {
0869:                    CommunicationException ex = new CommunicationException(e
0870:                            .getMessage());
0871:                    ex.setRootCause(e);
0872:                    if (search.getSearchResult().isEmpty()) {
0873:                        throw ex;
0874:                    }
0875:                    search.getSearchResult().setException(ex);
0876:                }
0877:                if (search.getResult().getResultCode() == LdapResult.INVALID_DN_SYNTAX) {
0878:                    throw new InvalidNameException(Messages
0879:                            .getString("ldap.34"));
0880:                }
0881:                sre = search.getSearchResult();
0882:                names = sre.getEntries();
0883:
0884:                keyset = names.keySet();
0885:                for (Iterator<String> iterator = keyset.iterator(); iterator
0886:                        .hasNext();) {
0887:                    String key = iterator.next();
0888:                    Attributes as = names.get(key);
0889:                    NamingEnumeration<String> ids = as.getIDs();
0890:
0891:                    while (ids.hasMoreElements()) {
0892:                        String schemaType = ids.nextElement();
0893:                        if (!schemaTree.contains(schemaType.toLowerCase())) {
0894:                            schemaTree
0895:                                    .put(
0896:                                            schemaType.toLowerCase(),
0897:                                            new Hashtable<String, Hashtable<String, Object>>());
0898:                        }
0899:                        Hashtable<String, Hashtable<String, Object>> schemaDefs = schemaTree
0900:                                .get(schemaType.toLowerCase());
0901:                        LdapAttribute attribute = (LdapAttribute) as
0902:                                .get(schemaType);
0903:                        for (int i = 0; i < attribute.size(); i++) {
0904:                            String value = (String) attribute.get(i);
0905:                            parseValue(schemaType, value.toLowerCase(),
0906:                                    schemaDefs);
0907:                        }
0908:                    }
0909:                }
0910:                ldapSchemaCtx = new LdapSchemaContextImpl(this , env, name);
0911:                return ldapSchemaCtx;
0912:            }
0913:
0914:            Hashtable<String, Object> findSchemaDefInfo(String schemaType,
0915:                    String className) {
0916:                Hashtable<String, Hashtable<String, Object>> schemaDefs = schemaTree
0917:                        .get(schemaType);
0918:                Hashtable<String, Object> schemaDef = schemaDefs.get(className);
0919:                return schemaDef;
0920:            }
0921:
0922:            /*
0923:             * Sample schema value from Openldap server is ( 2.5.13.8 NAME
0924:             * 'numericStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 ) TODO check
0925:             * with RFC to see whether all the schema definition has been catered for
0926:             */
0927:            private static void parseValue(String schemaType, String value,
0928:                    Hashtable<String, Hashtable<String, Object>> schemaDefs) {
0929:                StringTokenizer st = new StringTokenizer(value);
0930:                // Skip (
0931:                st.nextToken();
0932:
0933:                String oid = st.nextToken();
0934:
0935:                Hashtable<String, Object> schemaDef = new Hashtable<String, Object>();
0936:                schemaDef.put("orig", value);
0937:                schemaDef.put("numericoid", oid);
0938:                String token = null;
0939:                ArrayList<String> values = null;
0940:                StringBuilder desc = new StringBuilder();
0941:                while (st.hasMoreTokens()) {
0942:                    String attrName = st.nextToken();
0943:                    if (attrName.startsWith("x-")) {
0944:                        token = st.nextToken();
0945:                        // remove the ending ' symbol
0946:                        token = token.substring(0, token.length() - 1);
0947:                        schemaDef.put(attrName, token);
0948:                    }
0949:                    if (attrName.equals("usage") || attrName.equals("equality")
0950:                            || attrName.equals("syntax")
0951:                            || attrName.equals("ordering")
0952:                            || attrName.equals("substr")) {
0953:                        token = st.nextToken();
0954:                        schemaDef.put(attrName, token);
0955:                    }
0956:                    if (attrName.equals("desc")) {
0957:                        token = st.nextToken();
0958:
0959:                        // remove the leading ' symbol
0960:                        if (token.startsWith("'"))
0961:                            token = token.substring(1);
0962:                        while (!token.endsWith("'")) {
0963:                            desc.append(token).append(" ");
0964:                            token = st.nextToken();
0965:                        }
0966:
0967:                        // remove the ending ' symbol
0968:                        desc.append(token.substring(0, token.length() - 1));
0969:                        schemaDef.put(attrName, desc.toString());
0970:                        desc.delete(0, desc.length());
0971:                    }
0972:                    if (attrName.equals("name")) {
0973:                        token = st.nextToken();
0974:                        values = new ArrayList<String>();
0975:                        // Name has multiple values
0976:                        if (token.startsWith("(")) {
0977:                            token = st.nextToken();
0978:                            while (!token.equals(")")) {
0979:                                // remove the leading ' symbol
0980:                                if (token.startsWith("'"))
0981:                                    token = token.substring(1);
0982:                                while (!token.endsWith("'")) {
0983:                                    desc.append(token).append(" ");
0984:                                    token = st.nextToken();
0985:                                }
0986:
0987:                                // remove the ending ' symbol
0988:                                desc.append(token.substring(0,
0989:                                        token.length() - 1));
0990:                                values.add(desc.toString());
0991:                                desc.delete(0, desc.length());
0992:
0993:                                token = st.nextToken();
0994:                            }
0995:                        } else {
0996:                            // remove the leading ' symbol
0997:                            if (token.startsWith("'"))
0998:                                token = token.substring(1);
0999:                            while (!token.endsWith("'")) {
1000:                                desc.append(token).append(" ");
1001:                                token = st.nextToken();
1002:                            }
1003:
1004:                            // remove the ending ' symbol
1005:                            desc.append(token.substring(0, token.length() - 1));
1006:                            values.add(desc.toString());
1007:                            desc.delete(0, desc.length());
1008:                        }
1009:                        schemaDef.put(attrName, values);
1010:                        if (schemaType
1011:                                .equalsIgnoreCase(LdapSchemaContextImpl.LDAP_SYNTAXES)) {
1012:                            schemaDefs.put(oid, schemaDef);
1013:                        } else {
1014:                            schemaDefs.put(values.get(0), schemaDef);
1015:                        }
1016:                    }
1017:                    if (attrName.equals("must") || attrName.equals("sup")
1018:                            || attrName.equals("may")) {
1019:                        token = st.nextToken();
1020:                        values = new ArrayList<String>();
1021:                        // has multiple values
1022:                        if (token.startsWith("(")) {
1023:                            token = st.nextToken();
1024:                            while (!token.equals(")")) {
1025:                                if (!token.equals("$"))
1026:                                    values.add(token);
1027:                                token = st.nextToken();
1028:                            }
1029:                        } else {
1030:                            values.add(token);
1031:                        }
1032:                        schemaDef.put(attrName, values);
1033:                    }
1034:                    if (attrName.equals("abstract")
1035:                            || attrName.equals("structual")
1036:                            || attrName.equals("auxiliary")
1037:                            || attrName.equals("single-value")
1038:                            || attrName.equals("no-user-modification")) {
1039:                        schemaDef.put(attrName, "true");
1040:                    }
1041:                }
1042:                if (!schemaDef.keySet().contains("name")) {
1043:                    schemaDefs.put(oid, schemaDef);
1044:                }
1045:            }
1046:
1047:            public DirContext getSchema(String s) throws NamingException {
1048:                return getSchema(new CompositeName(s));
1049:            }
1050:
1051:            DirContext getSchemaAttributeDefinition(String name)
1052:                    throws NamingException {
1053:                if (null == ldapSchemaCtx) {
1054:                    getSchema("");
1055:                }
1056:                Hashtable<String, Object> attrDef = findSchemaDefInfo(
1057:                        LdapSchemaContextImpl.ATTRIBUTE_TYPES, name);
1058:
1059:                return new LdapSchemaAttrDefContextImpl(
1060:                        new CompositeName(name), env, attrDef, this );
1061:            }
1062:
1063:            public DirContext getSchemaClassDefinition(Name name)
1064:                    throws NamingException {
1065:                if (null == ldapSchemaCtx) {
1066:                    getSchema("");
1067:                }
1068:
1069:                Hashtable<String, ArrayList<String>> classTree = new Hashtable<String, ArrayList<String>>();
1070:
1071:                SearchControls searchControls = new SearchControls();
1072:                searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
1073:                searchControls
1074:                        .setReturningAttributes(new String[] { "objectClass", });
1075:                searchControls.setReturningObjFlag(false);
1076:                FilterParser parser = new FilterParser("(objectClass=*)");
1077:                Filter filter = null;
1078:                try {
1079:                    filter = parser.parse();
1080:                } catch (ParseException e1) {
1081:                    // Should not throw this excption
1082:                }
1083:                String targetDN = getTargetDN(name, contextDn);
1084:                SearchOp search = new SearchOp(targetDN, searchControls, filter);
1085:
1086:                try {
1087:                    client.doOperation(search, requestControls);
1088:                } catch (IOException e) {
1089:                    CommunicationException ex = new CommunicationException(e
1090:                            .getMessage());
1091:                    ex.setRootCause(e);
1092:                    if (search.getSearchResult().isEmpty()) {
1093:                        throw ex;
1094:                    }
1095:                    search.getSearchResult().setException(ex);
1096:                }
1097:                LdapSearchResult sre = search.getSearchResult();
1098:                Map<String, Attributes> names = sre.getEntries();
1099:
1100:                Set<String> keyset = names.keySet();
1101:                for (Iterator<String> iterator = keyset.iterator(); iterator
1102:                        .hasNext();) {
1103:                    String key = iterator.next();
1104:                    Attributes as = names.get(key);
1105:                    NamingEnumeration<String> ids = as.getIDs();
1106:
1107:                    while (ids.hasMoreElements()) {
1108:                        String schemaType = ids.nextElement();
1109:                        if (!classTree.contains(schemaType)) {
1110:                            classTree.put(schemaType, new ArrayList());
1111:                        }
1112:                        ArrayList<String> classDefs = classTree.get(schemaType);
1113:                        LdapAttribute attribute = (LdapAttribute) as
1114:                                .get(schemaType);
1115:                        for (int i = 0; i < attribute.size(); i++) {
1116:                            String value = (String) attribute.get(i);
1117:                            classDefs.add(value);
1118:                        }
1119:                    }
1120:                }
1121:
1122:                return new LdapSchemaClassDefContextImpl(new CompositeName(
1123:                        targetDN), env, classTree, this );
1124:            }
1125:
1126:            public DirContext getSchemaClassDefinition(String s)
1127:                    throws NamingException {
1128:                return getSchemaClassDefinition(convertFromStringToName(s));
1129:            }
1130:
1131:            public void modifyAttributes(Name name, int i, Attributes attributes)
1132:                    throws NamingException {
1133:                checkName(name);
1134:                if (attributes == null) {
1135:                    // jndi.13=Non-null attribute is required for modification
1136:                    throw new NullPointerException(Messages
1137:                            .getString("jndi.13")); //$NON-NLS-1$
1138:                }
1139:
1140:                if (i != DirContext.ADD_ATTRIBUTE
1141:                        && i != DirContext.REMOVE_ATTRIBUTE
1142:                        && i != DirContext.REPLACE_ATTRIBUTE) {
1143:                    /*
1144:                     * jndi.14=Modification code {0} must be one of
1145:                     * DirContext.ADD_ATTRIBUTE, DirContext.REPLACE_ATTRIBUTE and
1146:                     * DirContext.REMOVE_ATTRIBUTE
1147:                     */
1148:                    throw new IllegalArgumentException(Messages.getString(
1149:                            "jndi.14", i)); //$NON-NLS-1$
1150:                }
1151:
1152:                NamingEnumeration<? extends Attribute> enu = attributes
1153:                        .getAll();
1154:                ModificationItem[] items = new ModificationItem[attributes
1155:                        .size()];
1156:                int index = 0;
1157:                while (enu.hasMore()) {
1158:                    items[index++] = new ModificationItem(i, enu.next());
1159:                }
1160:
1161:                modifyAttributes(name, items);
1162:            }
1163:
1164:            public void modifyAttributes(Name name,
1165:                    ModificationItem[] modificationItems)
1166:                    throws NamingException {
1167:                checkName(name);
1168:
1169:                if (modificationItems == null) {
1170:                    // FIXME: spec say ModificationItem may not be null, but ri
1171:                    // silence in this case
1172:                    throw new NullPointerException(Messages
1173:                            .getString("ldap.27")); //$NON-NLS-1$
1174:                }
1175:
1176:                if (name instanceof  CompositeName && name.size() > 1) {
1177:                    /*
1178:                     * multi ns, find next ns context, delegate operation to the next
1179:                     * context
1180:                     */
1181:                    DirContext nns = (DirContext) findNnsContext(name);
1182:                    Name remainingName = name.getSuffix(1);
1183:                    nns.modifyAttributes(remainingName, modificationItems);
1184:                    return;
1185:                }
1186:
1187:                /*
1188:                 * there is only one ldap ns
1189:                 */
1190:                // get absolute dn name
1191:                String targetDN = getTargetDN(name, contextDn);
1192:                ModifyOp op = new ModifyOp(targetDN);
1193:                for (ModificationItem item : modificationItems) {
1194:                    switch (item.getModificationOp()) {
1195:                    case DirContext.ADD_ATTRIBUTE:
1196:                        op.addModification(0, new LdapAttribute(item
1197:                                .getAttribute(), this ));
1198:                        break;
1199:                    case DirContext.REMOVE_ATTRIBUTE:
1200:                        op.addModification(1, new LdapAttribute(item
1201:                                .getAttribute(), this ));
1202:                        break;
1203:                    case DirContext.REPLACE_ATTRIBUTE:
1204:                        op.addModification(2, new LdapAttribute(item
1205:                                .getAttribute(), this ));
1206:                        break;
1207:                    default:
1208:                        throw new IllegalArgumentException(Messages.getString(
1209:                                "jndi.14", item.getModificationOp())); //$NON-NLS-1$
1210:                    }
1211:                }
1212:
1213:                try {
1214:                    doBasicOperation(op);
1215:                } catch (ReferralException e) {
1216:                    if (isFollowReferral(e)) {
1217:                        DirContext referralContext = getReferralContext(e);
1218:                        referralContext.modifyAttributes(name,
1219:                                modificationItems);
1220:                        return;
1221:                    }
1222:                    throw e;
1223:                }
1224:            }
1225:
1226:            public void modifyAttributes(String s, int i, Attributes attributes)
1227:                    throws NamingException {
1228:                modifyAttributes(convertFromStringToName(s), i, attributes);
1229:            }
1230:
1231:            public void modifyAttributes(String s,
1232:                    ModificationItem[] modificationItems)
1233:                    throws NamingException {
1234:                modifyAttributes(convertFromStringToName(s), modificationItems);
1235:            }
1236:
1237:            public void rebind(Name name, Object obj, Attributes attributes)
1238:                    throws NamingException {
1239:                Attributes attrs = null;
1240:                try {
1241:                    attrs = getAttributes(name);
1242:                } catch (NameNotFoundException e) {
1243:                    // entry does not exist, just do bind
1244:                    bind(name, obj, attributes);
1245:                    return;
1246:                }
1247:
1248:                if (attributes == null && obj instanceof  DirContext) {
1249:                    attributes = ((DirContext) obj).getAttributes("");
1250:                    if (attributes == null) {
1251:                        attributes = attrs;
1252:                    }
1253:                }
1254:
1255:                destroySubcontext(name);
1256:
1257:                bind(name, obj, attributes);
1258:            }
1259:
1260:            public void rebind(String s, Object obj, Attributes attributes)
1261:                    throws NamingException {
1262:                rebind(convertFromStringToName(s), obj, attributes);
1263:            }
1264:
1265:            public NamingEnumeration<SearchResult> search(Name name,
1266:                    Attributes attributes) throws NamingException {
1267:                return search(name, attributes, null);
1268:            }
1269:
1270:            public NamingEnumeration<SearchResult> search(Name name,
1271:                    Attributes attributes, String[] as) throws NamingException {
1272:                checkName(name);
1273:
1274:                if (name instanceof  CompositeName && name.size() > 1) {
1275:                    /*
1276:                     * multi ns, find next ns context, delegate operation to the next
1277:                     * context
1278:                     */
1279:                    DirContext nns = (DirContext) findNnsContext(name);
1280:                    Name remainingName = name.getSuffix(1);
1281:                    return nns.search(remainingName, attributes, as);
1282:                }
1283:
1284:                /*
1285:                 * there is only one ldap ns
1286:                 */
1287:                // get absolute dn name
1288:                String targetDN = getTargetDN(name, contextDn);
1289:                Filter filter = null;
1290:
1291:                // construct filter
1292:                if (attributes == null || attributes.size() == 0) {
1293:                    filter = new Filter(Filter.PRESENT_FILTER);
1294:                    filter.setValue("objectClass");
1295:                } else {
1296:                    NamingEnumeration<? extends Attribute> attrs = attributes
1297:                            .getAll();
1298:                    filter = new Filter(Filter.AND_FILTER);
1299:                    while (attrs.hasMore()) {
1300:                        Attribute attr = attrs.next();
1301:                        String type = attr.getID();
1302:                        NamingEnumeration<?> enuValues = attr.getAll();
1303:                        while (enuValues.hasMore()) {
1304:                            Object value = enuValues.next();
1305:                            Filter child = new Filter(
1306:                                    Filter.EQUALITY_MATCH_FILTER);
1307:                            child.setValue(new AttributeTypeAndValuePair(type,
1308:                                    value));
1309:                            filter.addChild(child);
1310:                        }
1311:                    }
1312:                }
1313:
1314:                SearchControls controls = new SearchControls();
1315:                controls.setReturningAttributes(as);
1316:                LdapSearchResult result = doSearch(targetDN, filter, controls);
1317:
1318:                List<SearchResult> list = new ArrayList<SearchResult>();
1319:                Map<String, Attributes> entries = result.getEntries();
1320:                Name tempName = new LdapName(contextDn.toString());
1321:                tempName.addAll(name);
1322:                String baseDN = tempName.toString();
1323:                for (String dn : entries.keySet()) {
1324:                    SearchResult sr = null;
1325:                    if (dn.startsWith("ldap://")) {
1326:                        sr = new SearchResult(dn, null, entries.get(dn), false);
1327:                        int index = dn.indexOf("/", 7);
1328:                        sr.setNameInNamespace(dn.substring(index + 1, dn
1329:                                .length()));
1330:                        list.add(sr);
1331:                    } else {
1332:                        String relativeName = convertToRelativeName(dn, baseDN);
1333:                        sr = new SearchResult(relativeName, null, entries
1334:                                .get(dn));
1335:                        sr.setNameInNamespace(dn);
1336:                    }
1337:                    list.add(sr);
1338:                }
1339:
1340:                if (list.size() == 0 && result.getException() != null) {
1341:                    throw result.getException();
1342:                }
1343:
1344:                return new LdapNamingEnumeration<SearchResult>(list, result
1345:                        .getException());
1346:            }
1347:
1348:            public NamingEnumeration<SearchResult> search(Name name,
1349:                    String filter, Object[] objs, SearchControls searchControls)
1350:                    throws NamingException {
1351:                checkName(name);
1352:
1353:                if (name instanceof  CompositeName && name.size() > 1) {
1354:                    /*
1355:                     * multi ns, find next ns context, delegate operation to the next
1356:                     * context
1357:                     */
1358:                    DirContext nns = (DirContext) findNnsContext(name);
1359:                    Name remainingName = name.getSuffix(1);
1360:                    return nns.search(remainingName, filter, objs,
1361:                            searchControls);
1362:                }
1363:
1364:                /*
1365:                 * there is only one ldap ns
1366:                 */
1367:
1368:                if (searchControls == null) {
1369:                    searchControls = new SearchControls();
1370:                }
1371:
1372:                // get absolute dn name
1373:                String targetDN = getTargetDN(name, contextDn);
1374:
1375:                Filter f = LdapUtils.parseFilter(filter, objs);
1376:
1377:                LdapSearchResult result = doSearch(targetDN, f, searchControls);
1378:
1379:                List<SearchResult> list = new ArrayList<SearchResult>();
1380:                Map<String, Attributes> entries = result.getEntries();
1381:                Name tempName = new LdapName(contextDn.toString());
1382:                tempName.addAll(name);
1383:                String baseDN = tempName.toString();
1384:                for (String dn : entries.keySet()) {
1385:                    SearchResult sr = null;
1386:                    if (dn.startsWith("ldap://")) {
1387:                        sr = new SearchResult(dn, null, entries.get(dn), false);
1388:                        int index = dn.indexOf("/", 7);
1389:                        sr.setNameInNamespace(dn.substring(index + 1, dn
1390:                                .length()));
1391:                        list.add(sr);
1392:                    } else {
1393:                        String relativeName = convertToRelativeName(dn, baseDN);
1394:                        sr = new SearchResult(relativeName, null, entries
1395:                                .get(dn));
1396:                        sr.setNameInNamespace(dn);
1397:                    }
1398:                    list.add(sr);
1399:                }
1400:
1401:                if (list.size() == 0 && result.getException() != null) {
1402:                    throw result.getException();
1403:                }
1404:
1405:                return new LdapNamingEnumeration<SearchResult>(list, result
1406:                        .getException());
1407:            }
1408:
1409:            public NamingEnumeration<SearchResult> search(Name name,
1410:                    String filter, SearchControls searchControls)
1411:                    throws NamingException {
1412:                return search(name, filter, new Object[0], searchControls);
1413:            }
1414:
1415:            public NamingEnumeration<SearchResult> search(String name,
1416:                    Attributes attributes) throws NamingException {
1417:                return search(convertFromStringToName(name), attributes);
1418:            }
1419:
1420:            public NamingEnumeration<SearchResult> search(String name,
1421:                    Attributes attributes, String[] as) throws NamingException {
1422:                return search(convertFromStringToName(name), attributes, as);
1423:            }
1424:
1425:            public NamingEnumeration<SearchResult> search(String name,
1426:                    String filter, Object[] objs, SearchControls searchControls)
1427:                    throws NamingException {
1428:                return search(convertFromStringToName(name), filter, objs,
1429:                        searchControls);
1430:            }
1431:
1432:            public NamingEnumeration<SearchResult> search(String name,
1433:                    String filter, SearchControls searchControls)
1434:                    throws NamingException {
1435:                return search(convertFromStringToName(name), filter,
1436:                        searchControls);
1437:            }
1438:
1439:            LdapSearchResult doSearch(SearchOp op) throws NamingException {
1440:                if (env.get(LDAP_DEREF_ALIASES) != null) {
1441:                    String derefAliases = (String) env.get(LDAP_DEREF_ALIASES);
1442:                    if (derefAliases.equals("always")) {
1443:                        op.setDerefAliases(0);
1444:                    } else if (derefAliases.equals("never")) {
1445:                        op.setDerefAliases(1);
1446:                    } else if (derefAliases.equals("finding")) {
1447:                        op.setDerefAliases(2);
1448:                    } else if (derefAliases.equals("searching")) {
1449:                        op.setDerefAliases(3);
1450:                    } else {
1451:                        throw new IllegalArgumentException(
1452:                                Messages
1453:                                        .getString(
1454:                                                "ldap.30", new Object[] { env.get(LDAP_DEREF_ALIASES), //$NON-NLS-1$
1455:                                                        LDAP_DEREF_ALIASES }));
1456:                    }
1457:
1458:                }
1459:
1460:                if (env.containsKey(LDAP_TYPES_ONLY)) {
1461:                    String typesOnly = (String) env.get(LDAP_TYPES_ONLY);
1462:                    if ("true".equals(typesOnly)) {
1463:                        op.setTypesOnly(true);
1464:                    } else if ("false".equals(typesOnly)) {
1465:                        op.setTypesOnly(false);
1466:                    } else {
1467:                        throw new IllegalArgumentException(
1468:                                Messages
1469:                                        .getString(
1470:                                                "ldap.30", new Object[] { env.get(LDAP_TYPES_ONLY), //$NON-NLS-1$
1471:                                                        LDAP_TYPES_ONLY }));
1472:                    }
1473:                }
1474:
1475:                LdapMessage message = null;
1476:                try {
1477:                    message = client.doOperation(op, requestControls);
1478:                } catch (IOException e) {
1479:                    CommunicationException ex = new CommunicationException(e
1480:                            .getMessage());
1481:                    ex.setRootCause(e);
1482:                    if (op.getSearchResult() == null
1483:                            || op.getSearchResult().isEmpty()) {
1484:                        throw ex;
1485:                    }
1486:                    op.getSearchResult().setException(ex);
1487:                    // occurs errors, just return, doesn't deal with referral and
1488:                    // controls
1489:                    return op.getSearchResult();
1490:                }
1491:
1492:                // TODO: assume response controls returned in last message, it may
1493:                // be not correct
1494:                Control[] rawControls = message.getControls();
1495:                responseControls = narrowingControls(rawControls);
1496:
1497:                LdapResult result = op.getResult();
1498:
1499:                op.getSearchResult().setException(
1500:                        LdapUtils.getExceptionFromResult(result));
1501:
1502:                // has error, not deal with referrals
1503:                if (result.getResultCode() != LdapResult.REFERRAL
1504:                        && op.getSearchResult().getException() != null) {
1505:                    return op.getSearchResult();
1506:                }
1507:
1508:                // baseObject is not located at the server
1509:                if (result.getResultCode() == LdapResult.REFERRAL) {
1510:                    ReferralException ex = new ReferralExceptionImpl(contextDn
1511:                            .toString(), result.getReferrals(), env);
1512:                    try {
1513:                        if (isFollowReferral(ex)) {
1514:                            LdapContextImpl ctx = (LdapContextImpl) getReferralContext(ex);
1515:                            return ctx.doSearch(op);
1516:                        } else {
1517:                            op.getSearchResult().setException(ex);
1518:                            return op.getSearchResult();
1519:                        }
1520:                    } catch (PartialResultException e) {
1521:                        op.getSearchResult().setException(e);
1522:                        return op.getSearchResult();
1523:                    }
1524:                }
1525:
1526:                // there are SearchResultReference in search result
1527:                if (op.getSearchResult().getRefURLs() != null
1528:                        && op.getSearchResult().getRefURLs().size() != 0) {
1529:                    ReferralException ex = new ReferralExceptionImpl(contextDn
1530:                            .toString(), op.getSearchResult().getRefURLs()
1531:                            .toArray(new String[0]), env);
1532:                    try {
1533:                        if (isFollowReferral(ex)) {
1534:                            processSearchRef(op, ex);
1535:                        } else {
1536:                            op.getSearchResult().setException(ex);
1537:                            return op.getSearchResult();
1538:                        }
1539:                    } catch (PartialResultException e) {
1540:                        op.getSearchResult().setException(e);
1541:                        return op.getSearchResult();
1542:                    }
1543:                }
1544:
1545:                return op.getSearchResult();
1546:            }
1547:
1548:            /**
1549:             * Follow referrals in SearchResultReference. Referrals in
1550:             * SearchResultReference is different with LDAPResult, which may contians
1551:             * filter parts. Filter and dn part of url will overwrite filter and
1552:             * baseObject of last search operation.
1553:             * 
1554:             * @param op
1555:             *            last search operation
1556:             * @param ex
1557:             */
1558:            private void processSearchRef(SearchOp op, ReferralException ex) {
1559:                LdapSearchResult result = op.getSearchResult();
1560:                List<String> urls = result.getRefURLs();
1561:
1562:                // clean referrals
1563:                result.setRefURLs(null);
1564:
1565:                try {
1566:                    for (String url : urls) {
1567:
1568:                        LdapUrlParser urlParser = LdapUtils
1569:                                .parserURL(url, true);
1570:                        // if url has dn part overwrite baseObject of last search
1571:                        // operation
1572:                        if (!urlParser.getBaseObject().equals("")) {
1573:                            op.setBaseObject(urlParser.getBaseObject());
1574:                        }
1575:                        // if url has filter part overwrite filter of last search
1576:                        // operation
1577:                        if (urlParser.hasFilter()) {
1578:                            op.setFilter(urlParser.getFilter());
1579:                        }
1580:                        LdapContextImpl ctx = (LdapContextImpl) getReferralContext(ex);
1581:                        result.setAddress("ldap://" + urlParser.getHost() + ":"
1582:                                + urlParser.getPort() + "/");
1583:                        ctx.doSearch(op);
1584:                        result.setAddress(null);
1585:                    }
1586:                } catch (NamingException e) {
1587:                    /*
1588:                     * occrus exception, set to search result and return, not continue
1589:                     * to follow referral
1590:                     * 
1591:                     * TODO test the behavior of ri
1592:                     * 
1593:                     */
1594:                    result.setException(e);
1595:                    return;
1596:                }
1597:            }
1598:
1599:            LdapSearchResult doSearch(String dn, Filter filter,
1600:                    SearchControls controls) throws NamingException {
1601:                SearchOp op = new SearchOp(dn, controls, filter);
1602:                return doSearch(op);
1603:            }
1604:
1605:            public Object addToEnvironment(String s, Object o)
1606:                    throws NamingException {
1607:                Object preValue = env.put(s, o);
1608:
1609:                // if preValue equals o, do nothing
1610:                if ((preValue != null && preValue.equals(o))
1611:                        || (preValue == null && o == null)) {
1612:                    return preValue;
1613:                }
1614:
1615:                updateEnvironment(s);
1616:
1617:                return preValue;
1618:            }
1619:
1620:            public void bind(Name n, Object o) throws NamingException {
1621:                bind(n, o, null);
1622:            }
1623:
1624:            public void bind(String s, Object o) throws NamingException {
1625:                bind(convertFromStringToName(s), o);
1626:            }
1627:
1628:            public void close() throws NamingException {
1629:                if (!isClosed) {
1630:                    isClosed = true;
1631:                    client = null;
1632:                }
1633:            }
1634:
1635:            /**
1636:             * Only instance of LdapName or CompositeName are acceptable. If both
1637:             * <code>name</code> and <code>prefix</code> are LdapName, a new
1638:             * LdapName instance composed of the two name will be return , else a
1639:             * CompositeName will be return.
1640:             */
1641:            public Name composeName(Name name, Name prefix)
1642:                    throws NamingException {
1643:                if (name == null || prefix == null) {
1644:                    // jndi.2E=The name is null
1645:                    throw new NullPointerException(Messages
1646:                            .getString("jndi.2E")); //$NON-NLS-1$
1647:                }
1648:
1649:                Name result = null;
1650:                if (name instanceof  LdapName && prefix instanceof  LdapName) {
1651:                    result = (LdapName) prefix.clone();
1652:                    result.addAll(name);
1653:                } else if (name instanceof  LdapName
1654:                        && prefix instanceof  CompositeName) {
1655:                    result = new CompositeName();
1656:                    result.addAll(prefix);
1657:                    result.add(name.toString());
1658:                } else if (prefix instanceof  LdapName
1659:                        && name instanceof  CompositeName) {
1660:                    result = new CompositeName();
1661:                    result.add(prefix.toString());
1662:                    result.addAll(name);
1663:                } else if (prefix instanceof  CompositeName
1664:                        && name instanceof  CompositeName) {
1665:                    result = new CompositeName();
1666:                    result.addAll(prefix);
1667:                    result.addAll(name);
1668:                } else {
1669:                    throw new NamingException(Messages.getString("ldap.26")); //$NON-NLS-1$
1670:                }
1671:                return result;
1672:            }
1673:
1674:            public String composeName(String s, String pfx)
1675:                    throws NamingException {
1676:                return composeName(convertFromStringToName(s),
1677:                        convertFromStringToName(pfx)).toString();
1678:            }
1679:
1680:            public Context createSubcontext(Name name) throws NamingException {
1681:                return createSubcontext(name, null);
1682:            }
1683:
1684:            private Attributes getAttributesFromDN(Name name)
1685:                    throws InvalidNameException {
1686:                if (name instanceof  LdapName) {
1687:                    Rdn rdn = ((LdapName) name).getRdn(name.size() - 1);
1688:                    return rdn.toAttributes();
1689:                }
1690:
1691:                if (name instanceof  CompositeName) {
1692:                    LdapName lname = new LdapName(name.get(0));
1693:                    Rdn rdn = lname.getRdn(lname.size() - 1);
1694:                    return rdn.toAttributes();
1695:                }
1696:
1697:                throw new InvalidNameException(Messages.getString("ldap.26")); //$NON-NLS-1$
1698:            }
1699:
1700:            public Context createSubcontext(String s) throws NamingException {
1701:                return createSubcontext(convertFromStringToName(s));
1702:            }
1703:
1704:            public void destroySubcontext(Name name) throws NamingException {
1705:                checkName(name);
1706:
1707:                if (name instanceof  CompositeName && name.size() > 1) {
1708:                    if (!(name.getPrefix(0) instanceof  LdapName)) {
1709:                        throw new InvalidNameException(Messages
1710:                                .getString("ldap.26")); //$NON-NLS-1$
1711:                    }
1712:                    /*
1713:                     * multi ns, find next ns context, delegate operation to the next
1714:                     * context
1715:                     */
1716:                    Context nns = findNnsContext(name);
1717:                    Name remainingName = name.getSuffix(1);
1718:                    nns.destroySubcontext(remainingName);
1719:                    return;
1720:                }
1721:
1722:                /*
1723:                 * there is only one ldap ns
1724:                 */
1725:                // absolute dn name to list
1726:                String targetDN = getTargetDN(name, contextDn);
1727:                DeleteOp op = new DeleteOp(targetDN);
1728:                try {
1729:                    doBasicOperation(op);
1730:                } catch (ReferralException e) {
1731:                    if (isFollowReferral(e)) {
1732:                        DirContext referralContext = getReferralContext(e);
1733:                        referralContext.destroySubcontext(name);
1734:                        return;
1735:                    }
1736:                    throw e;
1737:                } catch (NameNotFoundException e) {
1738:                    // target dn doesn't exist, do nothing
1739:                }
1740:            }
1741:
1742:            public void destroySubcontext(String s) throws NamingException {
1743:                destroySubcontext(convertFromStringToName(s));
1744:            }
1745:
1746:            public Hashtable<?, ?> getEnvironment() throws NamingException {
1747:                return (Hashtable<?, ?>) env.clone();
1748:            }
1749:
1750:            public String getNameInNamespace() throws NamingException {
1751:                return contextDn.toString();
1752:            }
1753:
1754:            public NameParser getNameParser(Name name) throws NamingException {
1755:                if (name instanceof  CompositeName && name.size() > 1) {
1756:                    if (!(name.getPrefix(0) instanceof  LdapName)) {
1757:                        throw new InvalidNameException(Messages
1758:                                .getString("ldap.26")); //$NON-NLS-1$
1759:                    }
1760:                    /*
1761:                     * multi ns, find next ns context, delegate operation to the next
1762:                     * context
1763:                     */
1764:                    Context nns = findNnsContext(name);
1765:                    Name remainingName = name.getSuffix(1);
1766:                    return nns.getNameParser(remainingName);
1767:                }
1768:
1769:                return parser;
1770:            }
1771:
1772:            public NameParser getNameParser(String s) throws NamingException {
1773:                return getNameParser(convertFromStringToName(s));
1774:            }
1775:
1776:            public NamingEnumeration<NameClassPair> list(Name name)
1777:                    throws NamingException {
1778:                checkName(name);
1779:
1780:                if (name instanceof  CompositeName && name.size() > 1) {
1781:                    if (!(name.getPrefix(0) instanceof  LdapName)) {
1782:                        throw new InvalidNameException(Messages
1783:                                .getString("ldap.26")); //$NON-NLS-1$
1784:                    }
1785:                    /*
1786:                     * multi ns, find next ns context, delegate operation to the next
1787:                     * context
1788:                     */
1789:                    Context nns = findNnsContext(name);
1790:                    Name remainingName = name.getSuffix(1);
1791:                    return nns.list(remainingName);
1792:                }
1793:
1794:                /*
1795:                 * there is only one ldap ns
1796:                 */
1797:                // absolute dn name to list
1798:                String targetDN = getTargetDN(name, contextDn);
1799:
1800:                // construct one-level search using filter "(objectclass=*)"
1801:                SearchControls controls = new SearchControls();
1802:                controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
1803:                Filter filter = new Filter(Filter.PRESENT_FILTER);
1804:                filter.setValue("objectClass");
1805:
1806:                LdapSearchResult result = doSearch(targetDN, filter, controls);
1807:
1808:                List<NameClassPair> list = new ArrayList<NameClassPair>();
1809:                Map<String, Attributes> entries = result.getEntries();
1810:                Name tempName = new LdapName(contextDn.toString());
1811:                tempName.addAll(name);
1812:                String baseDN = tempName.toString();
1813:                for (String dn : entries.keySet()) {
1814:                    String relativeName = convertToRelativeName(dn, baseDN);
1815:                    Attributes attrs = entries.get(dn);
1816:                    Attribute attrClass = attrs.get("javaClassName");
1817:                    String className = null;
1818:                    if (attrClass != null) {
1819:                        className = (String) attrClass.get(0);
1820:                    } else {
1821:                        className = DirContext.class.getName();
1822:                    }
1823:                    NameClassPair pair = new NameClassPair(relativeName,
1824:                            className, true);
1825:                    pair.setNameInNamespace(dn);
1826:                    list.add(pair);
1827:                }
1828:
1829:                // no entries return
1830:                if (list.size() == 0 && result.getException() != null) {
1831:                    throw result.getException();
1832:                }
1833:
1834:                return new LdapNamingEnumeration<NameClassPair>(list, result
1835:                        .getException());
1836:            }
1837:
1838:            /**
1839:             * convert absolute dn to the dn relatived to the dn of
1840:             * <code>targetContextDN</code>.
1841:             * 
1842:             * @param dn
1843:             *            absolute dn
1844:             * @param base
1845:             *            base dn of the relative name
1846:             * @return dn relatived to the <code>dn</code> of <code>base</code>
1847:             */
1848:            protected String convertToRelativeName(String dn, String base) {
1849:
1850:                if (base.equals("")) {
1851:                    return dn;
1852:                }
1853:
1854:                int index = dn.lastIndexOf(base);
1855:                if (index == 0) {
1856:                    return "";
1857:                }
1858:
1859:                return dn.substring(0, index - 1);
1860:            }
1861:
1862:            protected String getTargetDN(Name name, Name prefix)
1863:                    throws NamingException, InvalidNameException {
1864:                Name target = null;
1865:                if (name.size() == 0) {
1866:                    target = prefix;
1867:                } else if (name instanceof  LdapName) {
1868:                    target = composeName(name, prefix);
1869:                } else if (name instanceof  CompositeName) {
1870:                    LdapName alt = new LdapName(name.get(0));
1871:                    target = composeName(alt, prefix);
1872:                } else {
1873:                    throw new InvalidNameException(Messages
1874:                            .getString("ldap.26")); //$NON-NLS-1$
1875:                }
1876:                return target.toString();
1877:            }
1878:
1879:            protected Context findNnsContext(Name name) throws NamingException {
1880:                CannotProceedException cpe = null;
1881:                if (env.containsKey(NamingManager.CPE)) {
1882:                    cpe = (CannotProceedException) env.get(NamingManager.CPE);
1883:                } else {
1884:                    cpe = new CannotProceedException();
1885:                }
1886:
1887:                Name remainingName = name.getSuffix(1);
1888:                Name altName = name.getPrefix(0);
1889:                Name targetName = composeName(altName, contextDn);
1890:
1891:                Name resolvedName = cpe.getResolvedName();
1892:                if (resolvedName == null) {
1893:                    resolvedName = new CompositeName();
1894:
1895:                } else if (resolvedName.size() >= 2
1896:                        && resolvedName.get(resolvedName.size() - 1).equals("")) {
1897:                    // remove the last component if it is ""
1898:                    // (the sign of the next naming system), so there must be at least
1899:                    // one name before "".
1900:                    resolvedName.remove(resolvedName.size() - 1);
1901:                }
1902:
1903:                resolvedName.add(targetName.toString());
1904:                // add empty component name to indicate nns pointer
1905:                resolvedName.add("");
1906:
1907:                cpe.setAltName(altName);
1908:                cpe.setAltNameCtx(this );
1909:                cpe.setEnvironment((Hashtable<Object, Object>) env.clone());
1910:                cpe.setRemainingName(remainingName);
1911:                cpe.setResolvedName(resolvedName);
1912:
1913:                final LdapContextImpl context = new LdapContextImpl(this , env,
1914:                        composeName(altName, contextDn).toString());
1915:
1916:                RefAddr addr = new RefAddr("nns") { //$NON-NLS-1$
1917:
1918:                    private static final long serialVersionUID = -5428706819217461955L;
1919:
1920:                    @Override
1921:                    public Object getContent() {
1922:                        return context;
1923:                    }
1924:
1925:                };
1926:
1927:                Reference ref = new Reference(context.getClass().getName(),
1928:                        addr);
1929:                cpe.setResolvedObj(ref);
1930:
1931:                return DirectoryManager.getContinuationDirContext(cpe);
1932:            }
1933:
1934:            public NamingEnumeration<NameClassPair> list(String s)
1935:                    throws NamingException {
1936:                return list(convertFromStringToName(s));
1937:            }
1938:
1939:            public NamingEnumeration<Binding> listBindings(Name name)
1940:                    throws NamingException {
1941:                checkName(name);
1942:
1943:                if (name instanceof  CompositeName && name.size() > 1) {
1944:                    /*
1945:                     * multi ns, find next ns context, delegate operation to the next
1946:                     * contex
1947:                     */
1948:                    DirContext nns = (DirContext) findNnsContext(name);
1949:                    Name remainingName = name.getSuffix(1);
1950:                    return nns.listBindings(remainingName);
1951:                }
1952:
1953:                /*
1954:                 * there is only one ldap ns
1955:                 */
1956:
1957:                NamingEnumeration<NameClassPair> enu = list(name);
1958:
1959:                List<Binding> bindings = new ArrayList<Binding>();
1960:
1961:                while (enu.hasMore()) {
1962:                    NameClassPair pair = enu.next();
1963:                    Object bound = null;
1964:                    if (!pair.getClassName().equals(DirContext.class.getName())) {
1965:                        bound = lookup(pair.getName());
1966:                    } else {
1967:                        bound = new LdapContextImpl(this , env, contextDn
1968:                                .toString());
1969:                    }
1970:
1971:                    Binding binding = new Binding(pair.getName(), bound
1972:                            .getClass().getName(), bound);
1973:                    binding.setNameInNamespace(pair.getNameInNamespace());
1974:                    bindings.add(binding);
1975:
1976:                }
1977:
1978:                // FIXME: deal with exception
1979:                return new LdapNamingEnumeration<Binding>(bindings, null);
1980:            }
1981:
1982:            public NamingEnumeration<Binding> listBindings(String s)
1983:                    throws NamingException {
1984:                return listBindings(convertFromStringToName(s));
1985:            }
1986:
1987:            public Object lookup(Name name) throws NamingException {
1988:                checkName(name);
1989:
1990:                if (name instanceof  CompositeName && name.size() > 1) {
1991:                    /*
1992:                     * multi ns, find next ns context, delegate operation to the next
1993:                     * context
1994:                     */
1995:                    DirContext nns = (DirContext) findNnsContext(name);
1996:                    Name remainingName = name.getSuffix(1);
1997:                    return nns.lookup(remainingName);
1998:                }
1999:
2000:                /*
2001:                 * there is only one ldap ns
2002:                 */
2003:                Attributes attributes = getAttributes(name);
2004:                if (!hasAttribute(attributes, "objectClass", "javaContainer")
2005:                        && !hasAttribute(attributes, "objectClass",
2006:                                "javaObject")) {
2007:                    // this is no java object, return the context
2008:
2009:                    // get absolute dn name
2010:                    String targetDN = getTargetDN(name, contextDn);
2011:                    return new LdapContextImpl(this , env, targetDN);
2012:                }
2013:
2014:                Object boundObject = null;
2015:                // serializable object
2016:                if (hasAttribute(attributes, "objectClass",
2017:                        "javaSerializedObject")) {
2018:                    byte[] data = (byte[]) attributes.get("javaSerializedData")
2019:                            .get();
2020:                    ObjectInputStream in = null;
2021:                    try {
2022:                        in = new ObjectInputStream(new ByteArrayInputStream(
2023:                                data));
2024:                        boundObject = in.readObject();
2025:                    } catch (IOException e) {
2026:                        NamingException ex = new NamingException();
2027:                        ex.setRootCause(e);
2028:                        throw ex;
2029:                    } catch (ClassNotFoundException e) {
2030:                        // TODO use javaCodebase attribute to load class defination
2031:                    } finally {
2032:                        if (in != null) {
2033:                            try {
2034:                                in.close();
2035:                            } catch (IOException e) {
2036:                                // ignore
2037:                            }
2038:                        }
2039:                    }
2040:                } else if (hasAttribute(attributes, "objectClass",
2041:                        "javaNamingReference")) {
2042:                    String className = (String) attributes.get("javaClassName")
2043:                            .get();
2044:
2045:                    Attribute temp = attributes.get("javaFactory");
2046:                    String factory = null;
2047:                    if (temp != null) {
2048:                        factory = (String) temp.get();
2049:                    }
2050:
2051:                    temp = attributes.get("javaCodebase");
2052:                    String location = null;
2053:                    if (temp != null) {
2054:                        location = (String) temp.get();
2055:                    }
2056:
2057:                    Reference ref = new Reference(className, factory, location);
2058:                    Attribute refAddress = attributes
2059:                            .get("javaReferenceAddress");
2060:                    if (refAddress != null) {
2061:                        NamingEnumeration<?> enu = refAddress.getAll();
2062:                        String separator = (String) env
2063:                                .get("java.naming.ldap.ref.separator");
2064:                        if (separator == null) {
2065:                            separator = "#";
2066:                        }
2067:                        TreeMap<Integer, StringRefAddr> addrsMap = new TreeMap<Integer, StringRefAddr>();
2068:
2069:                        // sort addresses to TreeMap
2070:                        while (enu.hasMore()) {
2071:                            String address = (String) enu.next();
2072:                            StringTokenizer st = new StringTokenizer(address,
2073:                                    separator);
2074:                            int index = Integer.parseInt(st.nextToken());
2075:                            String type = st.nextToken();
2076:                            String content = st.nextToken();
2077:                            StringRefAddr refAddr = new StringRefAddr(type,
2078:                                    content);
2079:                            addrsMap.put(Integer.valueOf(index), refAddr);
2080:                            // ref.add(index, refAddr);
2081:                        }
2082:
2083:                        for (StringRefAddr addr : addrsMap.values()) {
2084:                            ref.add(addr);
2085:                        }
2086:                    }
2087:                    boundObject = ref;
2088:                }
2089:
2090:                try {
2091:                    boundObject = DirectoryManager.getObjectInstance(
2092:                            boundObject, name, this , env);
2093:                    if (boundObject == null) {
2094:                        boundObject = new LdapContextImpl(this , env,
2095:                                getTargetDN(name, contextDn));
2096:                    }
2097:                    return boundObject;
2098:
2099:                } catch (NamingException e) {
2100:                    throw e;
2101:                } catch (Exception e) {
2102:                    // jndi.83=NamingManager.getObjectInstance() failed
2103:                    throw (NamingException) new NamingException(Messages
2104:                            .getString("jndi.83")).initCause(e); //$NON-NLS-1$
2105:                }
2106:            }
2107:
2108:            private boolean hasAttribute(Attributes attributes, String type,
2109:                    Object value) throws NamingException {
2110:                Attribute attr = attributes.get(type);
2111:                if (attr == null) {
2112:                    return false;
2113:                }
2114:
2115:                NamingEnumeration<?> enu = attr.getAll();
2116:                while (enu.hasMore()) {
2117:                    Object o = enu.next();
2118:                    if (value.equals(o)) {
2119:                        return true;
2120:                    }
2121:                }
2122:
2123:                return false;
2124:            }
2125:
2126:            public Object lookup(String s) throws NamingException {
2127:                return lookup(convertFromStringToName(s));
2128:            }
2129:
2130:            /**
2131:             * convert <code>String</code> name to <code>Name</code> instance, we
2132:             * assume the <code>String</code> name parameter is using composite name
2133:             * syntax (see LDAP service providers guidlines, part 4).
2134:             * 
2135:             * @param s
2136:             *            <code>String</code> name to be converted
2137:             * @return <code>Name</code> instance equivalent to <code>s</code>
2138:             * @throws InvalidNameException
2139:             *             occurs error while converting
2140:             */
2141:            protected Name convertFromStringToName(String s)
2142:                    throws InvalidNameException {
2143:                if (s == null) {
2144:                    // jndi.2E=The name is null
2145:                    throw new NullPointerException(Messages
2146:                            .getString("jndi.2E")); //$NON-NLS-1$
2147:                }
2148:
2149:                CompositeName name = new CompositeName(s);
2150:                if (name.size() == 0) {
2151:                    // return empty name
2152:                    return new LdapName(""); //$NON-NLS-1$
2153:                }
2154:
2155:                return name;
2156:            }
2157:
2158:            public Object lookupLink(Name name) throws NamingException {
2159:                return lookup(name);
2160:            }
2161:
2162:            public Object lookupLink(String s) throws NamingException {
2163:                return lookupLink(convertFromStringToName(s));
2164:            }
2165:
2166:            public void rebind(Name n, Object o) throws NamingException {
2167:                rebind(n, o, null);
2168:            }
2169:
2170:            public void rebind(String s, Object o) throws NamingException {
2171:                rebind(convertFromStringToName(s), o);
2172:            }
2173:
2174:            public Object removeFromEnvironment(String s)
2175:                    throws NamingException {
2176:                Object preValue = env.remove(s);
2177:
2178:                // if s doesn't exist in env
2179:                if (preValue == null) {
2180:                    return preValue;
2181:                }
2182:
2183:                updateEnvironment(s);
2184:
2185:                return preValue;
2186:            }
2187:
2188:            private void updateEnvironment(String propName)
2189:                    throws NamingException,
2190:                    AuthenticationNotSupportedException,
2191:                    CommunicationException, ConfigurationException {
2192:                if (connectionProperties.contains(propName)) {
2193:                    if (propName.equals("java.naming.ldap.factory.socket")) {
2194:                        // use new socket factory to connect server
2195:                        String address = client.getAddress();
2196:                        int port = client.getPort();
2197:
2198:                        client = LdapClient.newInstance(address, port, env);
2199:                        try {
2200:                            doBindOperation(connCtls);
2201:                        } catch (IOException e) {
2202:                            CommunicationException ex = new CommunicationException();
2203:                            ex.setRootCause(e);
2204:                            throw ex;
2205:                        }
2206:                    } else {
2207:
2208:                        reconnect(connCtls);
2209:                    }
2210:                }
2211:            }
2212:
2213:            public void rename(Name nOld, Name nNew) throws NamingException {
2214:                checkName(nOld);
2215:                checkName(nNew);
2216:
2217:                if (!isInSameNamespace(nOld, nNew)) {
2218:                    throw new InvalidNameException(Messages
2219:                            .getString("ldap.2A")); //$NON-NLS-1$
2220:                }
2221:
2222:                if (nOld instanceof  CompositeName && nOld.size() > 1
2223:                        && nNew instanceof  CompositeName && nNew.size() > 1) {
2224:                    Context context = findNnsContext(nOld);
2225:                    context.rename(nOld.getSuffix(1), nNew.getSuffix(1));
2226:                    return;
2227:                }
2228:
2229:                // get absolute dn name
2230:                String oldTargetDN = getTargetDN(nOld, contextDn);
2231:                String newTargetDN = getTargetDN(nNew, contextDn);
2232:                LdapName name = new LdapName(newTargetDN);
2233:                Rdn rdn = name.getRdn(name.size() - 1);
2234:                String value = (String) env.get(LDAP_DELETE_RDN);
2235:                // true is default value
2236:                boolean isDeleteRdn = true;
2237:                if (value != null) {
2238:                    isDeleteRdn = Boolean.getBoolean(value);
2239:                }
2240:
2241:                ModifyDNOp op = new ModifyDNOp(oldTargetDN, rdn.toString(),
2242:                        isDeleteRdn, name.getPrefix(name.size() - 1).toString());
2243:
2244:                try {
2245:                    doBasicOperation(op);
2246:                } catch (ReferralException e) {
2247:                    if (isFollowReferral(e)) {
2248:                        DirContext referralContext = getReferralContext(e);
2249:                        referralContext.rename(nOld, nNew);
2250:                        return;
2251:                    }
2252:                    throw e;
2253:                }
2254:            }
2255:
2256:            private boolean isInSameNamespace(Name first, Name second) {
2257:                if (first instanceof  CompositeName
2258:                        && second instanceof  CompositeName) {
2259:                    // TODO need more test in detail
2260:                    return first.size() == second.size();
2261:                }
2262:
2263:                if (first instanceof  LdapName && second instanceof  LdapName) {
2264:                    return true;
2265:                }
2266:
2267:                return false;
2268:            }
2269:
2270:            public void rename(String sOld, String sNew) throws NamingException {
2271:                rename(convertFromStringToName(sOld),
2272:                        convertFromStringToName(sNew));
2273:            }
2274:
2275:            public void unbind(Name n) throws NamingException {
2276:                // unbind and destroySubcontext do the same thing
2277:                destroySubcontext(n);
2278:            }
2279:
2280:            public void unbind(String s) throws NamingException {
2281:                unbind(convertFromStringToName(s));
2282:            }
2283:
2284:            /**
2285:             * Do operations with one request and one response which contains
2286:             * LdapResult. This is the convenience way to do the most of ldap operation
2287:             * except search opeartion which has multi-response, bind operation, abandon
2288:             * and unbind operations which have no response.
2289:             * 
2290:             * @param op
2291:             * @throws NamingException
2292:             */
2293:            protected void doBasicOperation(LdapOperation op)
2294:                    throws NamingException {
2295:                LdapMessage message = null;
2296:                try {
2297:                    message = client.doOperation(op, requestControls);
2298:                } catch (IOException e) {
2299:                    CommunicationException ex = new CommunicationException();
2300:                    ex.setRootCause(e);
2301:                    // operation failed, clear responseControls
2302:                    responseControls = null;
2303:                    throw ex;
2304:                }
2305:
2306:                Control[] rawControls = message.getControls();
2307:                responseControls = narrowingControls(rawControls);
2308:
2309:                LdapResult result = op.getResult();
2310:                if (result.getResultCode() == LdapResult.REFERRAL) {
2311:                    throw new ReferralExceptionImpl(contextDn.toString(),
2312:                            result.getReferrals(), env);
2313:                }
2314:
2315:                if (LdapUtils.getExceptionFromResult(result) != null) {
2316:                    throw LdapUtils.getExceptionFromResult(result);
2317:                }
2318:            }
2319:
2320:            private boolean isFollowReferral(ReferralException e)
2321:                    throws ReferralException, PartialResultException {
2322:                // ignore referral
2323:                String action = (String) env.get(Context.REFERRAL);
2324:                if (action == null) {
2325:                    action = "ignore";
2326:                }
2327:
2328:                if ("follow".equals(action)) {
2329:                    return true;
2330:                } else if ("throw".equals(action)) {
2331:                    return false;
2332:
2333:                } else if ("ignore".equals(action)) {
2334:                    // ldap.1A=[LDAP: error code 10 - Referral]
2335:                    throw new PartialResultException(Messages
2336:                            .getString("ldap.1A"));
2337:
2338:                } else {
2339:                    throw new IllegalArgumentException(Messages.getString(
2340:                            "ldap.30", new Object[] { //$NON-NLS-1$
2341:                            env.get(Context.REFERRAL), Context.REFERRAL }));
2342:                }
2343:            }
2344:
2345:            /**
2346:             * convert raw controls to particular type of controls using
2347:             * <code>getControlInstance(Control, Context,
2348:             Hashtable<?, ?>)</code>
2349:             * 
2350:             * @param rawControls
2351:             *            raw controls
2352:             * @return particular type of controls
2353:             * 
2354:             * @throws NamingException
2355:             */
2356:            private Control[] narrowingControls(Control[] rawControls)
2357:                    throws NamingException {
2358:                if (rawControls == null) {
2359:                    return null;
2360:                }
2361:
2362:                Control[] controls = new Control[rawControls.length];
2363:                for (int i = 0; i < rawControls.length; ++i) {
2364:                    controls[i] = ControlFactory.getControlInstance(
2365:                            rawControls[i], this , env);
2366:                }
2367:
2368:                return controls;
2369:            }
2370:
2371:            private void checkName(Name name) {
2372:                if (name == null) {
2373:                    // jndi.2E=The name is null
2374:                    throw new NullPointerException(Messages
2375:                            .getString("jndi.2E")); //$NON-NLS-1$
2376:                }
2377:            }
2378:
2379:            @Override
2380:            protected void finalize() {
2381:                try {
2382:                    close();
2383:                } catch (NamingException e) {
2384:                    // ignore
2385:                }
2386:            }
2387:
2388:            public void addNamingListener(Name name, String filter,
2389:                    Object[] filterArgs, SearchControls searchControls,
2390:                    NamingListener namingListener) throws NamingException {
2391:                checkName(name);
2392:
2393:                if (namingListener == null) {
2394:                    return;
2395:                }
2396:
2397:                if (!(name instanceof  LdapName)) {
2398:                    if (name instanceof  CompositeName && name.size() == 1) {
2399:                        name = name.getPrefix(1);
2400:                    } else {
2401:                        // FIXME: read message from file
2402:                        throw new InvalidNameException(
2403:                                "Target cannot span multiple namespaces: "
2404:                                        + name.toString());
2405:                    }
2406:                }
2407:
2408:                if (namingListener instanceof  UnsolicitedNotificationListener) {
2409:                    if (unls == null) {
2410:                        unls = new ArrayList<UnsolicitedNotificationListener>();
2411:                        addUnsolicitedListener();
2412:                    }
2413:
2414:                    unls.add((UnsolicitedNotificationListener) namingListener);
2415:
2416:                    if (!(namingListener instanceof  NamespaceChangeListener)
2417:                            && !(namingListener instanceof  ObjectChangeListener)) {
2418:                        return;
2419:                    }
2420:                }
2421:
2422:                if (searchControls == null) {
2423:                    searchControls = new SearchControls();
2424:                }
2425:
2426:                Filter f = LdapUtils.parseFilter(filter, filterArgs);
2427:
2428:                String targetDN = getTargetDN(name, contextDn);
2429:
2430:                Name tempName = new LdapName(contextDn.toString());
2431:                tempName.addAll(name);
2432:                String baseDN = tempName.toString();
2433:
2434:                int messageId = doPersistentSearch(targetDN, baseDN, f,
2435:                        searchControls, namingListener);
2436:
2437:                if (listeners == null) {
2438:                    listeners = new HashMap<NamingListener, List<Integer>>();
2439:                }
2440:
2441:                List<Integer> idList = listeners.get(namingListener);
2442:                if (idList == null) {
2443:                    idList = new ArrayList<Integer>();
2444:                }
2445:
2446:                idList.add(Integer.valueOf(messageId));
2447:            }
2448:
2449:            public void addNamingListener(Name name, String filter,
2450:                    SearchControls searchControls, NamingListener namingListener)
2451:                    throws NamingException {
2452:                addNamingListener(name, filter, new Object[0], searchControls,
2453:                        namingListener);
2454:            }
2455:
2456:            public void addNamingListener(String name, String filter,
2457:                    Object[] filterArgs, SearchControls searchControls,
2458:                    NamingListener namingListener) throws NamingException {
2459:                addNamingListener(convertFromStringToName(name), filter,
2460:                        filterArgs, searchControls, namingListener);
2461:            }
2462:
2463:            public void addNamingListener(String name, String filter,
2464:                    SearchControls searchControls, NamingListener namingListener)
2465:                    throws NamingException {
2466:                addNamingListener(convertFromStringToName(name), filter,
2467:                        searchControls, namingListener);
2468:            }
2469:
2470:            public static interface UnsolicitedListener {
2471:                public void receiveNotification(UnsolicitedNotificationImpl un,
2472:                        Control[] cs);
2473:            }
2474:
2475:            public void addNamingListener(Name name, int scope,
2476:                    NamingListener namingListener) throws NamingException {
2477:                checkName(name);
2478:
2479:                if (namingListener == null) {
2480:                    return;
2481:                }
2482:
2483:                // only ldap name is supportted
2484:                if (!(name instanceof  LdapName)) {
2485:                    if (name instanceof  CompositeName && name.size() == 1) {
2486:                        name = name.getPrefix(0);
2487:                    } else {
2488:                        // ldap.32=Target cannot span multiple namespaces: {0}
2489:                        throw new InvalidNameException(Messages.getString(
2490:                                "ldap.32", //$NON-NLS-1$
2491:                                new Object[] { name.toString() }));
2492:                    }
2493:                }
2494:
2495:                if (namingListener instanceof  UnsolicitedNotificationListener) {
2496:                    if (unls == null) {
2497:                        unls = new ArrayList<UnsolicitedNotificationListener>();
2498:                        addUnsolicitedListener();
2499:                    }
2500:
2501:                    unls.add((UnsolicitedNotificationListener) namingListener);
2502:
2503:                    if (!(namingListener instanceof  NamespaceChangeListener)
2504:                            && !(namingListener instanceof  ObjectChangeListener)) {
2505:                        return;
2506:                    }
2507:                }
2508:
2509:                // ri is silent in this case
2510:                if (scope != EventContext.OBJECT_SCOPE
2511:                        && scope != EventContext.ONELEVEL_SCOPE
2512:                        && scope != EventContext.SUBTREE_SCOPE) {
2513:                    // ldap.33=Scope should be one of 'OBJECT_SCOPE', 'ONELEVEL_SCOPE'
2514:                    // or 'SUBTREE_SCOPE'
2515:                    throw new IllegalArgumentException(Messages
2516:                            .getString("ldap.33")); //$NON-NLS-1$
2517:                }
2518:
2519:                String targetDN = getTargetDN(name, contextDn);
2520:
2521:                Filter filter = new Filter(Filter.PRESENT_FILTER);
2522:                filter.setValue("objectClass");
2523:
2524:                SearchControls controls = new SearchControls();
2525:                controls.setSearchScope(scope);
2526:
2527:                Name tempName = new LdapName(contextDn.toString());
2528:                tempName.addAll(name);
2529:                String baseDN = tempName.toString();
2530:
2531:                int messageId = doPersistentSearch(targetDN, baseDN, filter,
2532:                        controls, namingListener);
2533:
2534:                if (listeners == null) {
2535:                    listeners = new HashMap<NamingListener, List<Integer>>();
2536:                }
2537:
2538:                List<Integer> idList = listeners.get(namingListener);
2539:                if (idList == null) {
2540:                    idList = new ArrayList<Integer>();
2541:                    listeners.put(namingListener, idList);
2542:                }
2543:
2544:                idList.add(Integer.valueOf(messageId));
2545:
2546:            }
2547:
2548:            private void addUnsolicitedListener() {
2549:                client.addUnsolicitedListener(new UnsolicitedListener() {
2550:
2551:                    public void receiveNotification(
2552:                            UnsolicitedNotificationImpl un, Control[] cs) {
2553:                        EventObject event = null;
2554:                        try {
2555:                            un.setControls(narrowingControls(cs));
2556:                            event = new UnsolicitedNotificationEvent(this , un);
2557:                        } catch (NamingException e) {
2558:                            event = new NamingExceptionEvent(
2559:                                    LdapContextImpl.this , e);
2560:                        }
2561:
2562:                        for (UnsolicitedNotificationListener listener : unls) {
2563:                            notifyNamingListener(listener, event);
2564:                        }
2565:
2566:                    }
2567:
2568:                });
2569:            }
2570:
2571:            private int doPersistentSearch(String targetDN,
2572:                    final String baseDN, Filter filter,
2573:                    SearchControls controls, NamingListener namingListener)
2574:                    throws CommunicationException {
2575:
2576:                SearchOp op = new SearchOp(targetDN, controls, filter);
2577:
2578:                final NamingListener listener = namingListener;
2579:                op.setSearchResult(new PersistentSearchResult() {
2580:
2581:                    @Override
2582:                    public void receiveNotificationHook(Object obj) {
2583:                        EventObject event = null;
2584:                        // construct event
2585:                        if (obj instanceof  ECNotificationControl) {
2586:                            ECNotificationControl control = (ECNotificationControl) obj;
2587:                            event = constructNamingEvent(this , control, baseDN);
2588:                        }
2589:
2590:                        if (obj instanceof  LdapResult) {
2591:                            LdapResult ldapResult = (LdapResult) obj;
2592:                            NamingException ex = LdapUtils
2593:                                    .getExceptionFromResult(ldapResult);
2594:                            // may not happen
2595:                            if (ex == null) {
2596:                                return;
2597:                            }
2598:
2599:                            event = new NamingExceptionEvent(
2600:                                    LdapContextImpl.this , ex);
2601:                        }
2602:
2603:                        // notify listener
2604:                        notifyNamingListener(listener, event);
2605:                    }
2606:
2607:                });
2608:
2609:                try {
2610:                    return client.addPersistentSearch(op);
2611:                } catch (IOException e) {
2612:                    CommunicationException ex = new CommunicationException();
2613:                    ex.setRootCause(e);
2614:                    throw ex;
2615:                }
2616:            }
2617:
2618:            private void notifyNamingListener(final NamingListener listener,
2619:                    final EventObject event) {
2620:                /*
2621:                 * start new thread to notify listener, so user code may not affect
2622:                 * dispatcher thread
2623:                 */
2624:                Thread thread = new Thread(new Runnable() {
2625:
2626:                    public void run() {
2627:                        if (event instanceof  NamingEvent) {
2628:                            NamingEvent namingEvent = (NamingEvent) event;
2629:                            namingEvent.dispatch(listener);
2630:                        } else if (event instanceof  NamingExceptionEvent) {
2631:                            NamingExceptionEvent exceptionEvent = (NamingExceptionEvent) event;
2632:                            listener.namingExceptionThrown(exceptionEvent);
2633:                        } else if (event instanceof  UnsolicitedNotificationEvent) {
2634:                            UnsolicitedNotificationEvent namingEvent = (UnsolicitedNotificationEvent) event;
2635:                            namingEvent
2636:                                    .dispatch((UnsolicitedNotificationListener) listener);
2637:                        }
2638:
2639:                    }
2640:
2641:                });
2642:
2643:                thread.start();
2644:            }
2645:
2646:            public void addNamingListener(String s, int i,
2647:                    NamingListener namingListener) throws NamingException {
2648:                addNamingListener(convertFromStringToName(s), i, namingListener);
2649:            }
2650:
2651:            public void removeNamingListener(NamingListener namingListener)
2652:                    throws NamingException {
2653:                if (listeners == null || !listeners.containsKey(namingListener)) {
2654:                    return;
2655:                }
2656:
2657:                if (namingListener instanceof  UnsolicitedNotificationListener) {
2658:                    unls.remove(namingListener);
2659:                }
2660:
2661:                List<Integer> idList = listeners.remove(namingListener);
2662:                if (idList == null) {
2663:                    return;
2664:                }
2665:
2666:                try {
2667:                    for (Integer id : idList) {
2668:                        client.removePersistentSearch(id.intValue(),
2669:                                requestControls);
2670:                    }
2671:                } catch (IOException e) {
2672:                    CommunicationException ex = new CommunicationException();
2673:                    ex.setRootCause(e);
2674:                }
2675:            }
2676:
2677:            public boolean targetMustExist() throws NamingException {
2678:                // FIXME
2679:                return false;
2680:            }
2681:
2682:            private NamingEvent constructNamingEvent(
2683:                    PersistentSearchResult result,
2684:                    ECNotificationControl control, String baseDN) {
2685:                Binding newBinding = null;
2686:                Binding oldBinding = null;
2687:
2688:                switch (control.getChangeType()) {
2689:                case ECNotificationControl.ADD:
2690:                    String newName = convertToRelativeName(result.getDn(),
2691:                            baseDN);
2692:                    newBinding = new Binding(newName, null);
2693:                    newBinding.setNameInNamespace(result.getDn());
2694:                    break;
2695:                case ECNotificationControl.DELETE:
2696:                    String deleteName = convertToRelativeName(result.getDn(),
2697:                            baseDN);
2698:                    oldBinding = new Binding(deleteName, null);
2699:                    oldBinding.setNameInNamespace(result.getDn());
2700:                    break;
2701:                case ECNotificationControl.MODIFY_DN:
2702:                    if (result.getDn() != null) {
2703:                        newBinding = new Binding(convertToRelativeName(result
2704:                                .getDn(), baseDN), null);
2705:                        newBinding.setNameInNamespace(result.getDn());
2706:                    }
2707:
2708:                    if (control.getPreviousDN() != null) {
2709:                        oldBinding = new Binding(convertToRelativeName(control
2710:                                .getPreviousDN(), baseDN), null);
2711:                        oldBinding.setNameInNamespace(control.getPreviousDN());
2712:                    }
2713:                    break;
2714:                case ECNotificationControl.MODIFY:
2715:                    String relativeName = convertToRelativeName(result.getDn(),
2716:                            baseDN);
2717:                    newBinding = new Binding(relativeName, null);
2718:                    newBinding.setNameInNamespace(result.getDn());
2719:                    // FIXME: how to get old binding?
2720:                    oldBinding = new Binding(relativeName, null);
2721:                    oldBinding.setNameInNamespace(result.getDn());
2722:                }
2723:
2724:                NamingEvent event = new NamingEvent(this, control
2725:                        .getJNDIChangeType(), newBinding, oldBinding, Integer
2726:                        .valueOf(control.getChangeNumber()));
2727:
2728:                return event;
2729:            }
2730:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.