001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.harmony.jndi.provider.ldap;
018:
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.Hashtable;
022: import java.util.Iterator;
023: import java.util.LinkedList;
024: import java.util.List;
025: import java.util.Set;
026: import java.util.TreeSet;
027:
028: import javax.naming.Binding;
029: import javax.naming.CompositeName;
030: import javax.naming.ConfigurationException;
031: import javax.naming.Context;
032: import javax.naming.InvalidNameException;
033: import javax.naming.Name;
034: import javax.naming.NameClassPair;
035: import javax.naming.NameNotFoundException;
036: import javax.naming.NamingEnumeration;
037: import javax.naming.NamingException;
038: import javax.naming.OperationNotSupportedException;
039: import javax.naming.ReferralException;
040: import javax.naming.directory.Attribute;
041: import javax.naming.directory.Attributes;
042: import javax.naming.directory.BasicAttribute;
043: import javax.naming.directory.BasicAttributes;
044: import javax.naming.directory.DirContext;
045: import javax.naming.directory.InvalidSearchFilterException;
046: import javax.naming.directory.ModificationItem;
047: import javax.naming.directory.SchemaViolationException;
048: import javax.naming.directory.SearchControls;
049: import javax.naming.directory.SearchResult;
050:
051: import org.apache.harmony.jndi.internal.nls.Messages;
052: import org.apache.harmony.jndi.internal.parser.AttributeTypeAndValuePair;
053: import org.apache.harmony.jndi.provider.ldap.parser.FilterParser;
054: import org.apache.harmony.jndi.provider.ldap.parser.ParseException;
055:
056: public class LdapSchemaContextImpl extends LdapContextImpl {
057:
058: public static final String CLASS_DEFINITION = "classdefinition";
059:
060: public static final String ATTRIBUTE_DEFINITION = "attributedefinition";
061:
062: public static final String SYNTAX_DEFINITION = "syntaxdefinition";
063:
064: public static final String MATCHING_RULE = "matchingrule";
065:
066: public static final String OBJECT_CLASSES = "objectclasses";
067:
068: public static final String ATTRIBUTE_TYPES = "attributetypes";
069:
070: public static final String LDAP_SYNTAXES = "ldapsyntaxes";
071:
072: public static final String MATCHING_RULES = "matchingrules";
073:
074: protected String subschemasubentry = null;
075:
076: final private static Hashtable<String, String> schemaJndi2Ldap = new Hashtable<String, String>();
077: static {
078: schemaJndi2Ldap.put(CLASS_DEFINITION, OBJECT_CLASSES);
079: schemaJndi2Ldap.put(ATTRIBUTE_DEFINITION, ATTRIBUTE_TYPES);
080: schemaJndi2Ldap.put(SYNTAX_DEFINITION, LDAP_SYNTAXES);
081: schemaJndi2Ldap.put(MATCHING_RULE, MATCHING_RULES);
082: }
083:
084: final private static Hashtable<String, String> schemaLdap2Jndi = new Hashtable<String, String>();
085: static {
086: schemaLdap2Jndi.put(OBJECT_CLASSES, CLASS_DEFINITION);
087: schemaLdap2Jndi.put(ATTRIBUTE_TYPES, ATTRIBUTE_DEFINITION);
088: schemaLdap2Jndi.put(LDAP_SYNTAXES, SYNTAX_DEFINITION);
089: schemaLdap2Jndi.put(MATCHING_RULES, MATCHING_RULE);
090: }
091:
092: private LdapContextImpl parent;
093:
094: private Name rdn = null;
095:
096: public LdapSchemaContextImpl(LdapContextImpl ctx,
097: Hashtable<Object, Object> env, Name dn)
098: throws InvalidNameException {
099: super (ctx, env, dn.getPrefix(0).toString());
100: parent = ctx;
101: rdn = dn;
102: }
103:
104: public DirContext getSchema(Name name) throws NamingException {
105: throw new OperationNotSupportedException();
106: }
107:
108: public DirContext getSchema(String name) throws NamingException {
109: throw new OperationNotSupportedException();
110: }
111:
112: public DirContext getSchemaClassDefinition(Name name)
113: throws NamingException {
114: throw new OperationNotSupportedException();
115: }
116:
117: public DirContext getSchemaClassDefinition(String name)
118: throws NamingException {
119: throw new OperationNotSupportedException();
120: }
121:
122: public String getNameInNamespace() throws NamingException {
123: throw new OperationNotSupportedException();
124: }
125:
126: public DirContext createSubcontext(Name name, Attributes attributes)
127: throws NamingException {
128: checkName(name);
129:
130: Name schemaType = name.getPrefix(name.size() - 1);
131:
132: if (null == attributes || attributes.size() == 0) {
133: throw new SchemaViolationException(Messages
134: .getString("jndi.8D"));
135: }
136:
137: String schema = schemaJndi2Ldap.get(schemaType.toString()
138: .toLowerCase());
139: if (null == schema) {
140: throw new SchemaViolationException(Messages
141: .getString("jndi.8D"));
142: }
143: if (!LdapContextImpl.schemaTree.keySet().contains(schema)) {
144: throw new SchemaViolationException(Messages
145: .getString("jndi.8E"));
146: }
147: String targetDN = rdn.toString() + parent.subschemasubentry;
148: StringBuilder builder = new StringBuilder("( ");
149: NamingEnumeration<String> ids = attributes.getIDs();
150:
151: // FIXME what if attribute value has \' or \", or can Attributes be used
152: // directly
153: boolean hasNOID = false;
154: while (ids.hasMoreElements()) {
155: String id = ids.nextElement();
156: Attribute attribute = attributes.get(id);
157: if (id.equalsIgnoreCase("NUMERICOID")) {
158: builder.append(attribute);
159: builder.append(" ");
160: hasNOID = true;
161: } else {
162: builder.append(id);
163: builder.append(" ");
164: builder.append(attribute);
165: builder.append(" ");
166: }
167: }
168: builder.append(")");
169: if (!hasNOID) {
170: throw new ConfigurationException(Messages
171: .getString("jndi.8F"));
172: }
173:
174: ModifyOp op = new ModifyOp(targetDN);
175: BasicAttribute schemaEntry = new LdapAttribute(
176: new BasicAttribute(schema, builder.toString()), parent);
177: op.addModification(jndi2ldap[DirContext.ADD_ATTRIBUTE],
178: new LdapAttribute(schemaEntry, parent));
179:
180: try {
181: doBasicOperation(op);
182: } catch (ReferralException e) {
183: // TODO
184: }
185: return new LdapSchemaContextImpl(parent, parent.env, name);
186: }
187:
188: public DirContext createSubcontext(String name,
189: Attributes attributes) throws NamingException {
190: Name n = convertFromStringToName(name);
191: return createSubcontext(n, attributes);
192: }
193:
194: public Attributes getAttributes(Name name) throws NamingException {
195: Name targetDN = (rdn.size() != 0) ? name.addAll(rdn) : name;
196:
197: BasicAttributes schemaAttributes = new BasicAttributes();
198:
199: Set<String> keyset = null;
200: int size = targetDN.size();
201: switch (size) {
202: case 0:
203: break;
204: case 1:
205: String schemaType = schemaJndi2Ldap.get(name.get(0)
206: .toLowerCase());
207: if (null == schemaType) {
208: throw new NameNotFoundException(name.toString());
209: }
210: schemaAttributes.put(new BasicAttribute("objectclass", name
211: .get(0).toLowerCase()));
212: break;
213: default:
214: Hashtable<String, Object> classDef = parent
215: .findSchemaDefInfo(schemaJndi2Ldap.get(name.get(0)
216: .toLowerCase()), name.get(1));
217: if (null == classDef) {
218: throw new NameNotFoundException(name.toString());
219: }
220: schemaAttributes = new BasicAttributes();
221: keyset = classDef.keySet();
222: for (Iterator<String> i = keyset.iterator(); i.hasNext();) {
223: String id = i.next();
224: if (id.equals("orig")) {
225: continue;
226: }
227: Object value = classDef.get(id);
228: schemaAttributes.put(new BasicAttribute(id
229: .toLowerCase(), value));
230: }
231: }
232: return schemaAttributes;
233: }
234:
235: public Attributes getAttributes(Name name, String[] as)
236: throws NamingException {
237: Attributes attrs = getAttributes(name);
238: Attribute attr = null;
239: Attributes filteredAttrs = new BasicAttributes();
240: for (int i = 0; i < as.length; i++) {
241: attr = attrs.get(as[i]);
242: if (attr != null) {
243: filteredAttrs.put(attr);
244: }
245: }
246: return filteredAttrs;
247: }
248:
249: public Attributes getAttributes(String attributeName)
250: throws NamingException {
251: Name name = new CompositeName(attributeName);
252: return getAttributes(name);
253: }
254:
255: public Attributes getAttributes(String name, String[] as)
256: throws NamingException {
257: return getAttributes(new CompositeName(name), as);
258: }
259:
260: private void checkName(Name name) {
261: if (name == null) {
262: // jndi.2E=The name is null
263: throw new NullPointerException(Messages
264: .getString("jndi.2E")); //$NON-NLS-1$
265: }
266: }
267:
268: public void modifyAttributes(Name name, int i, Attributes attributes)
269: throws NamingException {
270: checkName(name);
271: if (attributes == null) {
272: // jndi.13=Non-null attribute is required for modification
273: throw new NullPointerException(Messages
274: .getString("jndi.13")); //$NON-NLS-1$
275: }
276:
277: if (i != DirContext.ADD_ATTRIBUTE
278: && i != DirContext.REMOVE_ATTRIBUTE
279: && i != DirContext.REPLACE_ATTRIBUTE) {
280: /*
281: * jndi.14=Modification code {0} must be one of
282: * DirContext.ADD_ATTRIBUTE, DirContext.REPLACE_ATTRIBUTE and
283: * DirContext.REMOVE_ATTRIBUTE
284: */
285: throw new IllegalArgumentException(Messages.getString(
286: "jndi.14", i)); //$NON-NLS-1$
287: }
288:
289: NamingEnumeration<? extends Attribute> enu = attributes
290: .getAll();
291: ModificationItem[] items = new ModificationItem[attributes
292: .size()];
293: int index = 0;
294: while (enu.hasMore()) {
295: items[index++] = new ModificationItem(i, enu.next());
296: }
297:
298: modifyAttributes(name, items);
299:
300: }
301:
302: private static final int jndi2ldap[] = { -1, 0, 2, 1, };
303:
304: public void modifyAttributes(Name name,
305: ModificationItem[] modificationItems)
306: throws NamingException {
307: checkName(name);
308:
309: Name targetDN = (rdn.size() != 0) ? name.addAll(rdn) : name;
310: int size = targetDN.size();
311: ModifyOp op = new ModifyOp(targetDN.toString());
312: String oldValue = "(objectclass)";
313: switch (size) {
314: case 0:
315: break;
316: case 1:
317: String schemaType = schemaJndi2Ldap.get(name.get(0)
318: .toLowerCase());
319: if (null == schemaType) {
320: throw new NameNotFoundException(name.toString());
321: }
322: if (modificationItems == null) {
323: throw new NullPointerException(Messages
324: .getString("ldap.27")); //$NON-NLS-1$
325: }
326: break;
327: default:
328: Hashtable<String, Object> classDef = parent
329: .findSchemaDefInfo(schemaJndi2Ldap.get(name.get(0)
330: .toLowerCase()), name.get(1));
331: if (modificationItems == null) {
332: throw new NullPointerException(Messages
333: .getString("ldap.27")); //$NON-NLS-1$
334: }
335: if (null == classDef) {
336: throw new NameNotFoundException(name.toString());
337: }
338:
339: oldValue = (String) classDef.get("orig");
340: }
341: BasicAttribute oldAttr = new LdapAttribute(new BasicAttribute(
342: OBJECT_CLASSES, oldValue), parent);
343: StringBuilder addValue = new StringBuilder();
344: for (ModificationItem item : modificationItems) {
345: Attribute attr = item.getAttribute();
346: addValue.append(attr.getID()).append(" ")
347: .append(attr.get());
348: }
349: addValue.append(" )");
350: BasicAttribute newAttr = new LdapAttribute(new BasicAttribute(
351: OBJECT_CLASSES, oldValue.replace(")", addValue
352: .toString())), this );
353: op.addModification(jndi2ldap[DirContext.REMOVE_ATTRIBUTE],
354: new LdapAttribute(oldAttr, parent));
355: op.addModification(jndi2ldap[DirContext.ADD_ATTRIBUTE],
356: new LdapAttribute(newAttr, parent));
357:
358: try {
359: doBasicOperation(op);
360: } catch (Exception e) {
361: throw new SchemaViolationException(
362: "Cannot modify schema root");
363: }
364:
365: }
366:
367: public void modifyAttributes(String s, int i, Attributes attributes)
368: throws NamingException {
369: Name name = convertFromStringToName(s);
370: modifyAttributes(name, i, attributes);
371: }
372:
373: public void modifyAttributes(String s,
374: ModificationItem[] modificationItems)
375: throws NamingException {
376: Name name = convertFromStringToName(s);
377: modifyAttributes(name, modificationItems);
378:
379: }
380:
381: public Context createSubcontext(Name name) throws NamingException {
382: DirContext subContext = createSubcontext(name, null);
383: return subContext;
384: }
385:
386: public Context createSubcontext(String name) throws NamingException {
387: Name n = convertFromStringToName(name);
388: return createSubcontext(n);
389: }
390:
391: public void destroySubcontext(Name name) throws NamingException {
392: checkName(name);
393:
394: // Name schemaType = name.getPrefix(name.size() - 1);
395: String targetDN = rdn.toString() + parent.subschemasubentry;
396: ModifyOp op = new ModifyOp(targetDN);
397: String schemaType = null;
398: try {
399: schemaType = schemaJndi2Ldap.get(name.getPrefix(
400: name.size() - 1).toString().toLowerCase());
401: } catch (IndexOutOfBoundsException e) {
402: throw new ArrayIndexOutOfBoundsException();
403: }
404:
405: Hashtable<String, Object> classDef = parent.findSchemaDefInfo(
406: schemaType, name.get(1));
407: if (null == classDef) {
408: return;
409: }
410: String oldValue = (String) classDef.get("orig");
411: LdapAttribute oldAttr = new LdapAttribute(new BasicAttribute(
412: schemaType, oldValue), parent);
413: op.addModification(jndi2ldap[DirContext.REMOVE_ATTRIBUTE],
414: oldAttr);
415:
416: try {
417: doBasicOperation(op);
418: } catch (Exception e) {
419: // TODO need to handle referal exception in the future
420: }
421: }
422:
423: public void destroySubcontext(String name) throws NamingException {
424: destroySubcontext(convertFromStringToName(name));
425: }
426:
427: public NamingEnumeration<NameClassPair> list(Name name)
428: throws NamingException {
429: Name targetDN = name.addAll(rdn);
430:
431: LdapNamingEnumeration<NameClassPair> enumeration = new LdapNamingEnumeration<NameClassPair>(
432: null, null);
433: Set<String> keyset = null;
434: int size = targetDN.size();
435: switch (size) {
436: case 0:
437: keyset = LdapContextImpl.schemaTree.keySet();
438: for (Iterator<String> i = keyset.iterator(); i.hasNext();) {
439: String schemaType = i.next();
440: NameClassPair pair = new NameClassPair(schemaLdap2Jndi
441: .get(schemaType.toLowerCase()), this .getClass()
442: .getName());
443: enumeration.add(pair);
444: }
445: break;
446: case 1:
447: String schemaType = schemaJndi2Ldap.get(name.get(0)
448: .toLowerCase());
449: if (null == schemaType) {
450: throw new NameNotFoundException(name.toString());
451: }
452: Hashtable<String, Hashtable<String, Object>> schemas = LdapContextImpl.schemaTree
453: .get(schemaType);
454: keyset = schemas.keySet();
455: for (Iterator<String> i = keyset.iterator(); i.hasNext();) {
456: schemaType = i.next();
457: NameClassPair pair = new NameClassPair(schemaType
458: .toLowerCase(), this .getClass().getName());
459: enumeration.add(pair);
460: }
461: break;
462: default:
463: schemaType = schemaJndi2Ldap.get(name.getPrefix(1)
464: .toString().toLowerCase());
465: if (null == schemaType) {
466: throw new NameNotFoundException(name.toString());
467: }
468: list(name.getSuffix(1));
469: }
470: return enumeration;
471: }
472:
473: public NamingEnumeration<NameClassPair> list(String name)
474: throws NamingException {
475: // TODO name supposed to be "" string, what about the situation when
476: // name is not ""
477: return list(convertFromStringToName(name));
478: }
479:
480: public NamingEnumeration<Binding> listBindings(Name name)
481: throws NamingException {
482: Name targetDN = name.addAll(rdn);
483:
484: LdapNamingEnumeration<Binding> enumeration = new LdapNamingEnumeration<Binding>(
485: null, null);
486: Set<String> keyset = null;
487: int size = targetDN.size();
488: switch (size) {
489: case 0:
490: keyset = LdapContextImpl.schemaTree.keySet();
491: for (Iterator<String> i = keyset.iterator(); i.hasNext();) {
492: String schemaType = i.next();
493: Binding binding = new Binding(schemaLdap2Jndi
494: .get(schemaType.toLowerCase()), this .getClass()
495: .getName(), null);
496: enumeration.add(binding);
497: }
498: break;
499: case 1:
500: String schemaType = schemaJndi2Ldap.get(name.get(0)
501: .toLowerCase());
502: if (null == schemaType) {
503: throw new NameNotFoundException(name.toString());
504: }
505: Hashtable<String, Hashtable<String, Object>> schemas = LdapContextImpl.schemaTree
506: .get(schemaType);
507: keyset = schemas.keySet();
508: for (Iterator<String> i = keyset.iterator(); i.hasNext();) {
509: schemaType = i.next();
510: Binding binding = new Binding(schemaType.toLowerCase(),
511: this .getClass().getName(), null);
512: enumeration.add(binding);
513: }
514: break;
515: default:
516: schemaType = schemaJndi2Ldap.get(name.getPrefix(1)
517: .toString().toLowerCase());
518: if (null == schemaType) {
519: throw new NameNotFoundException(name.toString());
520: }
521: list(name.getSuffix(1));
522: }
523: return enumeration;
524: }
525:
526: public NamingEnumeration<Binding> listBindings(String name)
527: throws NamingException {
528: return listBindings(convertFromStringToName(name));
529: }
530:
531: public Object lookup(Name n) throws NamingException {
532: return new LdapSchemaContextImpl(parent, env, n.addAll(rdn));
533: }
534:
535: public Object lookup(String name) throws NamingException {
536: return lookup(convertFromStringToName(name));
537: }
538:
539: public void rename(Name nOld, Name nNew) throws NamingException {
540: throw new SchemaViolationException(Messages
541: .getString("jndi.err.01"));
542: }
543:
544: public void rename(String sOld, String sNew) throws NamingException {
545: throw new SchemaViolationException(Messages
546: .getString("jndi.err.01"));
547: }
548:
549: public NamingEnumeration<SearchResult> search(Name name,
550: Attributes attributes) throws NamingException {
551: return search(name, attributes, null);
552: }
553:
554: public NamingEnumeration<SearchResult> search(Name name,
555: // Used to filter attribute value
556: Attributes attributes,
557: // Used to filter attribute name
558: String[] as) throws NamingException {
559: checkName(name);
560:
561: Name targetDN = name.addAll(rdn);
562:
563: /*
564: * Formalize attributes, change all ids to lowercase, if attributes is
565: * non-null
566: */
567:
568: boolean hasMatchingAttributes = (null != attributes && 0 != attributes
569: .size());
570: boolean hasAttributes2Return = (null != as && 0 != as.length);
571:
572: // Attribute matcher
573: BasicAttributes attrMatcher = new BasicAttributes();
574: if (hasMatchingAttributes) {
575: NamingEnumeration<? extends Attribute> attrEnum = attributes
576: .getAll();
577: while (attrEnum.hasMore()) {
578: Attribute old = attrEnum.next();
579: BasicAttribute newAttr = new BasicAttribute(old.getID()
580: .toLowerCase());
581: for (int i = 0; i < old.size(); i++) {
582: if (old.get(i) instanceof String) {
583: newAttr
584: .add(((String) old.get(i))
585: .toLowerCase());
586: } else {
587: newAttr.add(old.get(i));
588: }
589: }
590: attrMatcher.put(newAttr);
591: }
592: }
593:
594: // Attribute selector
595: TreeSet<String> attrSel = new TreeSet<String>();
596:
597: // Construct result NamingEnumeration
598: LdapNamingEnumeration<SearchResult> enumeration = new LdapNamingEnumeration<SearchResult>(
599: null, null);
600: String schemaType = null;
601:
602: LinkedList<String> attrValues = new LinkedList<String>();
603: int size = targetDN.size();
604: switch (size) {
605: case 0:
606: /*
607: * Name is a empty string, search against root, may return schema
608: * types: (classdefinition, attributedefinition, syntaxdefinition,
609: * matchingrule)
610: */
611: attrValues.addAll(LdapContextImpl.schemaTree.keySet());
612: /*
613: * Filter attribute names - whether the single attribute name
614: * 'objectclass' is chosen.
615: */
616: int objectclassIndex = -1;
617: if (hasAttributes2Return) {
618: for (int i = 0; i < as.length; i++) {
619: if (as[i].equalsIgnoreCase("objectclass")) {
620: objectclassIndex = i;
621: break;
622: }
623: }
624: }
625: attrSel.add("objectclass");
626:
627: /*
628: * Filter attribute values - choose from (classdefinition,
629: * attributedefinition, syntaxdefinition, matchingrule)
630: */
631: if (hasMatchingAttributes) {
632: Attribute attribute = attrMatcher.get("objectclass");
633: if (null == attribute) {
634: return enumeration;
635: }
636: for (int i = 0; i < attrValues.size(); i++) {
637: schemaType = schemaLdap2Jndi.get(attrValues.get(i));
638: /*
639: * RI's behavior is odd here - it only retrieves the first
640: * encountered attribute value,
641: */
642: if (attribute.contains(schemaType)) {
643: BasicAttributes basicAttributes = new BasicAttributes();
644: /*
645: * if(objectclassIndex == -1), then No name was choose,
646: * which means SearchResult will have empty
647: * BasicAttributes.
648: */
649: if (objectclassIndex != -1) {
650: basicAttributes.put("objectclass",
651: schemaType);
652: }
653: SearchResult pair = new SearchResult(
654: schemaType, null, basicAttributes);
655: enumeration.add(pair);
656: break;
657: }
658: }
659: } else {
660: for (int i = 0; i < attrValues.size(); i++) {
661: schemaType = schemaLdap2Jndi.get(attrValues.get(i));
662: BasicAttributes basicAttributes = new BasicAttributes();
663: /*
664: * if(objectclassIndex == -1), then No name was choose,
665: * which means SearchResult will have empty BasicAttributes.
666: */
667: if (objectclassIndex != -1) {
668: basicAttributes.put("objectclass", schemaType);
669: }
670: SearchResult pair = new SearchResult(schemaType,
671: null, basicAttributes);
672: enumeration.add(pair);
673: }
674: }
675: break;
676: case 1:
677: if (hasAttributes2Return) {
678: attrSel.addAll(Arrays.asList(as));
679: }
680: schemaType = schemaJndi2Ldap.get(name.get(0).toLowerCase());
681: if (null == schemaType) {
682: throw new NameNotFoundException(name.toString());
683: }
684: Hashtable<String, Hashtable<String, Object>> schemas = LdapContextImpl.schemaTree
685: .get(schemaType);
686: attrValues.addAll(schemas.keySet());
687: BasicAttributes basicAttributes = null;
688: if (hasMatchingAttributes) {
689: for (int i = 0; i < attrValues.size(); i++) {
690: NamingEnumeration<Attribute> filters = attrMatcher
691: .getAll();
692: String id = attrValues.get(i);
693: Hashtable<String, Object> schemaDef = schemas
694: .get(id);
695: boolean matched = true;
696: while (filters.hasMore()) {
697: Attribute filter = filters.next();
698: Object values = schemaDef.get(filter.getID());
699: /*
700: * Attribute definition will only be retrieved when it
701: * is designated in attrFilter
702: */
703: if (values == null || !match(filter, values)) {
704: matched = false;
705: break;
706: }
707: }
708: if (matched) {
709: basicAttributes = new BasicAttributes();
710: for (Iterator<String> iterator = schemaDef
711: .keySet().iterator(); iterator
712: .hasNext();) {
713: String key = iterator.next();
714: if (key.equals("orig")) {
715: continue;
716: }
717: if (hasAttributes2Return
718: && attrSel.contains(key)
719: || !hasAttributes2Return) {
720: basicAttributes.put(key, schemaDef
721: .get(key));
722: }
723: }
724: SearchResult pair = new SearchResult(id, null,
725: basicAttributes);
726: enumeration.add(pair);
727: }
728: }
729: } else {
730: for (int i = 0; i < attrValues.size(); i++) {
731: Hashtable<String, Object> schemaDef = schemas
732: .get(attrValues.get(i));
733: basicAttributes = new BasicAttributes();
734: for (Iterator<String> iterator = schemaDef.keySet()
735: .iterator(); iterator.hasNext();) {
736: String key = iterator.next();
737: if (key.equals("orig")) {
738: continue;
739: }
740: if (hasAttributes2Return
741: && attrSel.contains(key)
742: || !hasAttributes2Return) {
743: basicAttributes
744: .put(key, schemaDef.get(key));
745: }
746: }
747: SearchResult pair = new SearchResult(attrValues
748: .get(i), null, basicAttributes);
749: enumeration.add(pair);
750: }
751: }
752: break;
753:
754: default:
755: schemaType = schemaJndi2Ldap.get(name.getPrefix(1)
756: .toString().toLowerCase());
757: if (null == schemaType) {
758: throw new NameNotFoundException(name.toString());
759: }
760: search(name.getSuffix(1), attributes, as);
761: }
762: return enumeration;
763:
764: }
765:
766: private boolean match(Attribute filter, Object values)
767: throws NamingException {
768: NamingEnumeration<?> attrValues = filter.getAll();
769: ArrayList v = null;
770: if (values instanceof ArrayList) {
771: v = (ArrayList) values;
772: } else {
773: v = new ArrayList();
774: v.add(values);
775: }
776:
777: while (attrValues.hasMore()) {
778: Object attrValue = attrValues.next();
779: for (int i = 0; i < v.size(); i++) {
780: if (attrValue.equals("*") || attrValue.equals(v.get(i))) {
781: return true;
782: }
783: }
784: }
785: return false;
786: }
787:
788: public NamingEnumeration<SearchResult> search(Name name,
789: String filter, Object[] objs, SearchControls searchControls)
790: throws NamingException {
791:
792: checkName(name);
793:
794: if (filter == null) {
795: throw new NullPointerException(Messages
796: .getString("ldap.28")); //$NON-NLS-1$
797: }
798: if (filter.length() == 0) {
799: throw new StringIndexOutOfBoundsException();
800: }
801: if (!filter.startsWith("(")) {
802: StringBuilder filterWrapper = new StringBuilder("(");
803: filterWrapper.append(filter).append(")");
804: filter = filterWrapper.toString();
805: }
806:
807: if (null == searchControls) {
808: searchControls = new SearchControls();
809: }
810:
811: FilterParser filterParser = new FilterParser(filter);
812: filterParser.setArgs(objs);
813: Filter f = null;
814: try {
815: f = filterParser.parse();
816: } catch (ParseException e) {
817: InvalidSearchFilterException ex = new InvalidSearchFilterException(
818: Messages.getString("ldap.29")); //$NON-NLS-1$
819: ex.setRootCause(e);
820: throw ex;
821: }
822:
823: BasicAttributes matchingAttrs = new BasicAttributes();
824: extractMatchingAttributes(f, matchingAttrs);
825:
826: return search(name, matchingAttrs, searchControls
827: .getReturningAttributes());
828: }
829:
830: private void extractMatchingAttributes(Filter f,
831: BasicAttributes matchingAttrs) {
832: if (!f.isLeaf()) {
833: List<Filter> children = f.getChildren();
834: for (Iterator iter = children.iterator(); iter.hasNext();) {
835: extractMatchingAttributes((Filter) iter.next(),
836: matchingAttrs);
837: }
838: } else {
839: Object value = f.getValue();
840: if (value instanceof AttributeTypeAndValuePair) {
841: AttributeTypeAndValuePair pair = (AttributeTypeAndValuePair) value;
842: matchingAttrs.put(pair.getType(), pair.getValue());
843: } else {
844: matchingAttrs.put((String) value, "*");
845: }
846: }
847: }
848: }
|