1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.api.sp;
21
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Set;
26
27 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
28 import org.apache.directory.api.ldap.model.cursor.Cursor;
29 import org.apache.directory.api.ldap.model.entry.Attribute;
30 import org.apache.directory.api.ldap.model.entry.Entry;
31 import org.apache.directory.api.ldap.model.entry.Value;
32 import org.apache.directory.api.ldap.model.exception.LdapException;
33 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
34 import org.apache.directory.api.ldap.model.filter.AndNode;
35 import org.apache.directory.api.ldap.model.filter.BranchNode;
36 import org.apache.directory.api.ldap.model.filter.EqualityNode;
37 import org.apache.directory.api.ldap.model.message.AliasDerefMode;
38 import org.apache.directory.api.ldap.model.message.SearchScope;
39 import org.apache.directory.api.ldap.model.name.Dn;
40 import org.apache.directory.api.ldap.model.schema.AttributeType;
41 import org.apache.directory.server.constants.ApacheSchemaConstants;
42 import org.apache.directory.server.core.api.DirectoryService;
43 import org.apache.directory.server.i18n.I18n;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class LdapClassLoader extends ClassLoader
62 {
63 private static final Logger LOG = LoggerFactory.getLogger( LdapClassLoader.class );
64 public static final String DEFAULT_SEARCH_CONTEXTS_CONFIG = "cn=classLoaderDefaultSearchContext,ou=configuration,ou=system";
65
66 private Dn defaultSearchDn;
67 private DirectoryService directoryService;
68
69
70 private AttributeType objectClassAT;
71
72
73 public LdapClassLoader( DirectoryService directoryService ) throws LdapException
74 {
75 super( LdapClassLoader.class.getClassLoader() );
76 this.directoryService = directoryService;
77 defaultSearchDn = directoryService.getDnFactory().create( DEFAULT_SEARCH_CONTEXTS_CONFIG );
78
79 objectClassAT = directoryService.getSchemaManager().getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
80 }
81
82
83 private byte[] findClassInDIT( List<Dn> searchContexts, String name ) throws ClassNotFoundException, LdapInvalidAttributeValueException
84 {
85
86 BranchNode filter = new AndNode();
87 AttributeType fqjcnAt = directoryService.getSchemaManager().getAttributeType( "fullyQualifiedJavaClassName" );
88 filter.addNode( new EqualityNode<String>( fqjcnAt, new Value( fqjcnAt, name ) ) );
89 filter.addNode( new EqualityNode<String>( objectClassAT,
90 new Value( objectClassAT, ApacheSchemaConstants.JAVA_CLASS_OC ) ) );
91
92 try
93 {
94 for ( Dn base : searchContexts )
95 {
96 Cursor<Entry> cursor = null;
97 try
98 {
99 cursor = directoryService.getAdminSession()
100 .search( base, SearchScope.SUBTREE, filter, AliasDerefMode.DEREF_ALWAYS );
101
102 cursor.beforeFirst();
103 if ( cursor.next() )
104 {
105 LOG.debug( "Class {} found under {} search context.", name, base );
106 Entry classEntry = cursor.get();
107
108 if ( cursor.next() )
109 {
110 Entry other = cursor.get();
111 LOG.warn( "More than one class found on classpath at locations: {} \n\tand {}",
112 classEntry, other );
113 }
114
115 return classEntry.get( "javaClassByteCode" ).getBytes();
116 }
117 }
118 finally
119 {
120 if ( cursor != null )
121 {
122 cursor.close();
123 }
124 }
125 }
126 }
127 catch ( Exception e )
128 {
129 LOG.error( I18n.err( I18n.ERR_69, name ), e );
130 }
131
132 throw new ClassNotFoundException();
133 }
134
135
136
137
138
139 @Override
140 public Class<?> findClass( String name ) throws ClassNotFoundException
141 {
142 byte[] classBytes = null;
143
144 try
145 {
146
147
148
149
150
151 Entry configEntry = null;
152
153 try
154 {
155 configEntry = directoryService.getAdminSession().lookup( defaultSearchDn );
156 }
157 catch ( LdapException e )
158 {
159 LOG.debug( "No configuration data found for class loader default search contexts." );
160 }
161
162 if ( configEntry != null )
163 {
164 List<Dn> searchContexts = new ArrayList<>();
165 Attribute attr = configEntry.get( "classLoaderDefaultSearchContext" );
166
167 for ( Value val : attr )
168 {
169 Dn dn = directoryService.getDnFactory().create( val.getString() );
170 searchContexts.add( dn );
171 }
172
173 try
174 {
175 classBytes = findClassInDIT( searchContexts, name );
176
177 if ( LOG.isDebugEnabled() )
178 {
179 LOG.debug( "Class {} found under default search contexts.", name );
180 }
181 }
182 catch ( ClassNotFoundException e )
183 {
184 if ( LOG.isDebugEnabled() )
185 {
186 LOG.debug( "Class {} could not be found under default search contexts.", name );
187 }
188 }
189 }
190
191 if ( classBytes == null )
192 {
193 List<Dn> namingContexts = new ArrayList<>();
194
195 Set<String> suffixes = directoryService.getPartitionNexus().listSuffixes();
196
197 for ( String suffix : suffixes )
198 {
199 Dn suffixDn = directoryService.getDnFactory().create( suffix );
200 namingContexts.add( suffixDn );
201 }
202
203 classBytes = findClassInDIT( namingContexts, name );
204 }
205 }
206 catch ( ClassNotFoundException e )
207 {
208 String msg = I18n.err( I18n.ERR_293, name );
209 LOG.debug( msg );
210 throw new ClassNotFoundException( msg );
211 }
212 catch ( Exception e )
213 {
214 String msg = I18n.err( I18n.ERR_70, name );
215 LOG.error( msg, e );
216 throw new ClassNotFoundException( msg );
217 }
218
219 return defineClass( name, classBytes, 0, classBytes.length );
220 }
221 }