1/*
2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/**
27  * Given an enumeration of candidates, check whether each
28  * item in enumeration satifies the given filter.
29  * Each item is a Binding and the following is used to get its
30  * attributes for used by the filter:
31  *
32  *   ((DirContext)item.getObject()).getAttributes("").
33  * If item.getObject() is not an DirContext, the item is skipped
34  *
35  * The items in the enumeration are obtained one at a time as
36  * items from the search enumeration are requested.
37  *
38  * @author Rosanna Lee
39  */
40
41package com.sun.jndi.toolkit.dir;
42
43import javax.naming.*;
44import javax.naming.directory.*;
45import javax.naming.spi.DirectoryManager;
46
47import java.util.NoSuchElementException;
48import java.util.Hashtable;
49
50final public class LazySearchEnumerationImpl
51        implements NamingEnumeration<SearchResult> {
52    private NamingEnumeration<Binding> candidates;
53    private SearchResult nextMatch = null;
54    private SearchControls cons;
55    private AttrFilter filter;
56    private Context context;
57    private Hashtable<String, Object> env;
58    private boolean useFactory = true;
59
60    public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
61        AttrFilter filter, SearchControls cons) throws NamingException {
62            this.candidates = candidates;
63            this.filter = filter;
64
65            if(cons == null) {
66                this.cons = new SearchControls();
67            } else {
68                this.cons = cons;
69            }
70    }
71
72    @SuppressWarnings("unchecked")      // For Hashtable clone: env.clone()
73    public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
74        AttrFilter filter, SearchControls cons,
75        Context ctx, Hashtable<String, Object> env, boolean useFactory)
76        throws NamingException {
77
78            this.candidates = candidates;
79            this.filter = filter;
80            this.env = (Hashtable<String, Object>)
81                    ((env == null) ? null : env.clone());
82            this.context = ctx;
83            this.useFactory = useFactory;
84
85            if(cons == null) {
86                this.cons = new SearchControls();
87            } else {
88                this.cons = cons;
89            }
90    }
91
92
93    public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
94        AttrFilter filter, SearchControls cons,
95        Context ctx, Hashtable<String, Object> env) throws NamingException {
96            this(candidates, filter, cons, ctx, env, true);
97    }
98
99    public boolean hasMore() throws NamingException {
100        // find and do not remove from list
101        return findNextMatch(false) != null;
102    }
103
104    public boolean hasMoreElements() {
105        try {
106            return hasMore();
107        } catch (NamingException e) {
108            return false;
109        }
110    }
111
112    public SearchResult nextElement() {
113        try {
114            return findNextMatch(true);
115        } catch (NamingException e) {
116            throw new NoSuchElementException(e.toString());
117        }
118    }
119
120    public SearchResult next() throws NamingException {
121        // find and remove from list
122        return (findNextMatch(true));
123    }
124
125    public void close() throws NamingException {
126        if (candidates != null) {
127            candidates.close();
128        }
129    }
130
131    private SearchResult findNextMatch(boolean remove) throws NamingException {
132        SearchResult answer;
133        if (nextMatch != null) {
134            answer = nextMatch;
135            if (remove) {
136                nextMatch = null;
137            }
138            return answer;
139        } else {
140            // need to find next match
141            Binding next;
142            Object obj;
143            Attributes targetAttrs;
144            while (candidates.hasMore()) {
145                next = candidates.next();
146                obj = next.getObject();
147                if (obj instanceof DirContext) {
148                    targetAttrs = ((DirContext)(obj)).getAttributes("");
149                    if (filter.check(targetAttrs)) {
150                        if (!cons.getReturningObjFlag()) {
151                            obj = null;
152                        } else if (useFactory) {
153                            try {
154                                // Give name only if context non-null,
155                                // otherwise, name will be interpreted relative
156                                // to initial context (not what we want)
157                                Name nm = (context != null ?
158                                    new CompositeName(next.getName()) : null);
159                                obj = DirectoryManager.getObjectInstance(obj,
160                                    nm, context, env, targetAttrs);
161                            } catch (NamingException e) {
162                                throw e;
163                            } catch (Exception e) {
164                                NamingException e2 = new NamingException(
165                                    "problem generating object using object factory");
166                                e2.setRootCause(e);
167                                throw e2;
168                            }
169                        }
170                        answer = new SearchResult(next.getName(),
171                            next.getClassName(), obj,
172                            SearchFilter.selectAttributes(targetAttrs,
173                                cons.getReturningAttributes()),
174                            true);
175                        if (!remove)
176                            nextMatch = answer;
177                        return answer;
178                    }
179                }
180            }
181            return null;
182        }
183    }
184}
185