1 package com.atlassian.user.impl.ldap.search.page;
2
3 import com.atlassian.user.EntityException;
4 import com.atlassian.user.impl.ldap.repository.LdapContextFactory;
5 import com.atlassian.user.impl.ldap.search.LDAPPagerInfo;
6 import com.atlassian.user.impl.ldap.properties.LdapSearchProperties;
7 import com.atlassian.user.search.page.AbstractPrefetchingPager;
8 import com.atlassian.user.util.EnumerationAdaptor;
9 import com.atlassian.user.util.LDAPUtils;
10 import com.atlassian.util.profiling.UtilTimerStack;
11 import net.sf.ldaptemplate.support.filter.Filter;
12 import org.apache.log4j.Logger;
13
14 import javax.naming.NamingEnumeration;
15 import javax.naming.NamingException;
16 import javax.naming.directory.DirContext;
17 import javax.naming.directory.SearchControls;
18 import javax.naming.directory.SearchResult;
19 import java.util.Iterator;
20 import java.util.List;
21
22 public abstract class AbstractLDAPPager<T> extends AbstractPrefetchingPager<T> implements Iterator<T>
23 {
24 protected final Logger log = Logger.getLogger(this.getClass());
25 protected NamingEnumeration<SearchResult> enume;
26 protected Filter originalQuery;
27 protected LdapSearchProperties searchProperties;
28 protected LdapContextFactory repository;
29 protected String originalBaseSearchContext;
30 protected boolean searchAllDepths;
31 protected String[] returningAttributes;
32 private int timeLimitMillis;
33 public boolean closed;
34
35 protected AbstractLDAPPager(LdapSearchProperties searchProperties, LdapContextFactory repository, LDAPPagerInfo info)
36 {
37 this.searchProperties = searchProperties;
38 this.repository = repository;
39 this.enume = info.getNamingEnumeration();
40 this.originalQuery = info.getLDAPQuery();
41 this.originalBaseSearchContext = info.getBaseSearchContext();
42 this.searchAllDepths = info.isSearchAllDepths();
43 this.returningAttributes = info.getReturningAttributes();
44 this.timeLimitMillis = info.getTimeToLive();
45 }
46
47 public AbstractLDAPPager()
48 {
49
50 }
51
52
53
54
55
56
57 protected abstract List<T> preloadSearchResult(SearchResult result, List<T> prefetched) throws EntityException;
58
59 public void remove()
60 {
61 throw new UnsupportedOperationException("This iterator does not support removal.");
62 }
63
64
65
66
67 protected void preload()
68 {
69 indexOfFirstItemInCurrentPage = idx;
70
71 if (UtilTimerStack.isActive())
72 {
73 UtilTimerStack.push(this.getClass().getName() + "_preload__(originalQuery= " + originalQuery + ")");
74 }
75
76 DirContext ctx = null;
77
78 try
79 {
80 if (closed)
81 {
82 ctx = repository.getLDAPContext();
83 SearchControls ctls = LDAPUtils.createSearchControls(returningAttributes, searchAllDepths,
84 timeLimitMillis);
85 if (log.isDebugEnabled())
86 {
87 log.debug("AbstractLDAPPager.preload:" + originalQuery.encode());
88 }
89 enume = ctx.search(originalBaseSearchContext, originalQuery.encode(), ctls);
90 }
91
92 super.preload(new EnumerationAdaptor<SearchResult>(enume));
93 }
94 catch (Exception e)
95 {
96 log.error("Error while paging through results", e);
97 throw new RuntimeException("Unexpected error paging through LDAP results: " + e.getMessage(), e);
98 }
99 finally
100 {
101 if (enume != null)
102 {
103 try { enume.close(); } catch (NamingException e) { log.error("Error closing enumeration.", e); }
104 }
105
106 if (ctx != null)
107 {
108 try { ctx.close(); } catch (NamingException e) { log.error("Error closing context.", e); }
109 }
110
111 closed = true;
112 }
113
114 if (UtilTimerStack.isActive())
115 {
116 UtilTimerStack.pop(this.getClass().getName() + "_preload__(originalQuery= " + originalQuery + ")");
117 }
118 }
119
120 protected List<T> fetch(Object element, List<T> prefetched) throws EntityException
121 {
122 return preloadSearchResult((SearchResult) element, prefetched);
123 }
124
125 }