MultiRepository | Line # 107 | 41 | 10 | 87.3% |
0.87323946
|
MultiThreadSearch | Line # 336 | 82 | 22 | 91.2% |
0.91150445
|
(1) | |||
Result | |||
0.73913044
|
issrg.test.ds.TestDS.testIssuing issrg.test.ds.TestDS.testIssuing | 1 PASS | |
1 | /* | |
2 | * Copyright (c) 2000-2005, University of Salford | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions are met: | |
7 | * | |
8 | * Redistributions of source code must retain the above copyright notice, this | |
9 | * list of conditions and the following disclaimer. | |
10 | * | |
11 | * Redistributions in binary form must reproduce the above copyright notice, | |
12 | * this list of conditions and the following disclaimer in the documentation | |
13 | * and/or other materials provided with the distribution. | |
14 | * | |
15 | * Neither the name of the University of Salford nor the names of its | |
16 | * contributors may be used to endorse or promote products derived from this | |
17 | * software without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | |
31 | /* | |
32 | * Copyright (c) 2006, University of Kent | |
33 | * All rights reserved. | |
34 | * | |
35 | * Redistribution and use in source and binary forms, with or without | |
36 | * modification, are permitted provided that the following conditions are met: | |
37 | * | |
38 | * Redistributions of source code must retain the above copyright notice, this | |
39 | * list of conditions and the following disclaimer. | |
40 | * | |
41 | * Redistributions in binary form must reproduce the above copyright notice, | |
42 | * this list of conditions and the following disclaimer in the documentation | |
43 | * and/or other materials provided with the distribution. | |
44 | * | |
45 | * 1. Neither the name of the University of Kent nor the names of its | |
46 | * contributors may be used to endorse or promote products derived from this | |
47 | * software without specific prior written permission. | |
48 | * | |
49 | * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
50 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
51 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
52 | * PURPOSE ARE DISCLAIMED. | |
53 | * | |
54 | * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
55 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
56 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
57 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
58 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
59 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
60 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
61 | * POSSIBILITY OF SUCH DAMAGE. | |
62 | * | |
63 | * 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE | |
64 | * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS | |
65 | * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS | |
66 | * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH | |
67 | * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH | |
68 | * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY | |
69 | * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE | |
70 | * SERIOUS FAULTS, IN THIS SOFTWARE. | |
71 | * | |
72 | * 5. This license is governed, except to the extent that local laws | |
73 | * necessarily apply, by the laws of England and Wales. | |
74 | */ | |
75 | ||
76 | package issrg.utils.repository; | |
77 | ||
78 | import javax.naming.directory.DirContext; | |
79 | import javax.naming.CompositeName; | |
80 | import javax.naming.directory.Attribute; | |
81 | import javax.naming.directory.Attributes; | |
82 | import javax.naming.directory.BasicAttribute; | |
83 | import java.util.Vector; | |
84 | import java.security.Principal; | |
85 | ||
86 | import org.apache.log4j.*;// added for logging | |
87 | /** | |
88 | * This class is the implementation of the Attribute Repository for | |
89 | * multithreaded access to a cluster of repositories. | |
90 | * It can be built out of an array of Repositories. Each of these repositories | |
91 | * constitutes a root for searches. | |
92 | * | |
93 | * <p>The object can be used for retrieving similar information from multiple | |
94 | * directories simultaneously. For example, it is useful when retrieving X.509 | |
95 | * Attribute Certificates for PMI entities that possess ACs issued by different | |
96 | * issuers (therefore, stored in different repositories available to them). | |
97 | * | |
98 | * <p>The object creates multiple threads (one per repository) when attributes | |
99 | * are requested and performs the searches simultaneously. This improves | |
100 | * efficiency, since most of the time the repositories | |
101 | * are waiting for a reply. The object waits till all of the contexts return | |
102 | * anything or report an error, so the result is always complete. | |
103 | * | |
104 | * @author A Otenko | |
105 | * @version 0.2 | |
106 | */ | |
107 | public class MultiRepository extends DefaultRepository { | |
108 | private AttributeRepository [] initialRepositories; | |
109 | private MultiThreadSearch mts = new MultiThreadSearch(); | |
110 | private static Logger logger = Logger.getLogger(MultiRepository.class); | |
111 | ||
112 | 0 | protected MultiRepository(){} |
113 | ||
114 | /** | |
115 | * This constructor builds the MultiRepository with a number of roots. | |
116 | * | |
117 | * @param repositories An array of AttributeRepositories to be used as the | |
118 | * search roots | |
119 | */ | |
120 | 713 | public MultiRepository(AttributeRepository [] repositories) { |
121 | 713 | AttributeRepository [] r=new AttributeRepository[repositories.length]; |
122 | 713 | System.arraycopy(repositories, 0, r, 0, r.length); |
123 | ||
124 | ||
125 | // now prune the null pointers | |
126 | ||
127 | 713 | int j=0; // the first null entry in the array - the number of non-null repositories |
128 | 1448 | for (int i=0; i<r.length; i++){ |
129 | 735 | if (r[j]==null && r[i]!=null){ |
130 | 0 | r[j]=r[i]; // move non-null repositories to the front |
131 | 0 | r[i]=null; |
132 | } | |
133 | ||
134 | 735 | if (r[j]!=null) j++; |
135 | } | |
136 | // now j is the number of non-null repositories, and they all are at the beginning of the array | |
137 | ||
138 | 713 | initialRepositories=new AttributeRepository[j]; |
139 | 713 | System.arraycopy(r, 0, initialRepositories, 0, initialRepositories.length); |
140 | } | |
141 | ||
142 | /** | |
143 | * This creates a MultiRepository with a single root repository | |
144 | * | |
145 | * @param repository A AttributeRepository | |
146 | */ | |
147 | 682 | public MultiRepository(AttributeRepository repository) { |
148 | 682 | this(new AttributeRepository[]{repository}); |
149 | } | |
150 | ||
151 | /** | |
152 | * This method searches for the given attributes in the repositories provided | |
153 | * at construction time. | |
154 | * | |
155 | * @param DN - the Principal naming the entry in the repositories | |
156 | * @param AttributeNames - the names of the attributes to be retrieved; if | |
157 | * null, all available attributes will be returned | |
158 | * | |
159 | * @return the requested Attributes | |
160 | */ | |
161 | 3221 | public Attributes getAttributes(java.security.Principal DN, String [] AttributeNames) throws RepositoryException{ |
162 | // construct a synchronous list of entry names for each repository - | |
163 | // use the same entry name for all repositories | |
164 | 3221 | java.security.Principal dns[] = new java.security.Principal[initialRepositories.length]; |
165 | 6479 | for (int i=0; i<dns.length; i++){ |
166 | 3258 | dns[i]=DN; |
167 | } | |
168 | 3221 | return getAttributes(dns, initialRepositories, AttributeNames); |
169 | } | |
170 | ||
171 | /** | |
172 | * This method will collect attributes from all the entries identified by | |
173 | * the TokenLocator. Each TokenLocator in the chain points to a location in | |
174 | * a repository; if the repository in it is null, all the repositories | |
175 | * provided at construction time | |
176 | * MultiRepository will be searched; otherwise only the repository stated in | |
177 | * the TokenLocator | |
178 | * will be searched. | |
179 | * | |
180 | * @param locator - the locator of the entries with the attributes | |
181 | * @param AttributeNames - the names of the attributes | |
182 | * | |
183 | * @return Attributes that are located in all the locations pointed to by the | |
184 | * TokenLocator | |
185 | */ | |
186 | 3233 | public Attributes getAttributes(TokenLocator locator, String [] AttributeNames) throws RepositoryException { |
187 | 3233 | Vector dns = new Vector(); |
188 | 3233 | Vector reps = new Vector(); |
189 | 6466 | while(locator!=null){ |
190 | 3233 | dns.add(locator.getLocator()); |
191 | 3233 | AttributeRepository r = locator.getRepository(); |
192 | 3233 | reps.add(r==null? this: r); // use this MultiRepository, if no specific repository was specified |
193 | 3233 | locator=locator.getAlternativeLocator(); |
194 | } | |
195 | 3233 | return getAttributes((Principal [])dns.toArray(new Principal[0]), |
196 | (AttributeRepository [])reps.toArray(new AttributeRepository [0]), | |
197 | AttributeNames); | |
198 | } | |
199 | ||
200 | /** | |
201 | * This is method searches for a single attribute. This is a shortcut for | |
202 | * getAttributes(locator, new String[]{AttributeName}).get(AttributeName); | |
203 | * | |
204 | * @param locator - the TokenLocator identifying multiple locations of the | |
205 | * attribute | |
206 | * @param AttributeName - the name of the attribute to retrieve | |
207 | * | |
208 | * @return the requested Attribute | |
209 | */ | |
210 | 3233 | public Attribute getAttribute(TokenLocator locator, String AttributeName) throws RepositoryException{ |
211 | 3233 | String [] AttributeNames= new String[]{AttributeName}; |
212 | 3233 | Attributes attrs = getAttributes(locator, AttributeNames); |
213 | ||
214 | 3233 | return (attrs==null)?null:(attrs.get(AttributeName)); |
215 | } | |
216 | ||
217 | /** | |
218 | * This is the root method called by any other getAttributes that gets the | |
219 | * set of named attributes from the entries with the DNs. | |
220 | * It searches all provided repositories simultaneously. If the DN and named | |
221 | * attribute | |
222 | * exist in more than one of the named contexts, then multiple attribute | |
223 | * values will be returned. | |
224 | * | |
225 | * <p>The list of entry names DN is synchronised with the list of | |
226 | * repositories so that each entry name is used only for the corresponding | |
227 | * repository, but the whole list of attributes is requested from each | |
228 | * repository. When other getAttributes methods use this method, they simply | |
229 | * construct such synchronous lists of entry names and repositories. These | |
230 | * methods do | |
231 | * not update the status or diagnosis set by this method, and they propagate | |
232 | * the exceptions thrown by this method. | |
233 | * | |
234 | * <p>Effectively, this method constructs a new MultiThreadSearch and invokes | |
235 | * a getAttributes method on it. Because this may cause recursive invocation | |
236 | * of this method from different threads, this method is NOT synchronized. | |
237 | * For example, | |
238 | * a search for attributes in two chained TokenLocators with no repository | |
239 | * specified constructs one MultiThreadSearch, which spawns two threads, each | |
240 | * attempting to invoke getAttributes | |
241 | * method on this very MultiRepository object; this should be allowed (no | |
242 | * mutex on the method), and in its turn creates two other MultiThreadSearches, | |
243 | * each spawning one thread for each initial repository passed to | |
244 | * the MultiRepository at construction time. The side effect of this is that | |
245 | * during the call to getAttributes the status and diagnosis values are | |
246 | * undetermined, since the calls to multiple MultiThreadSearch will | |
247 | * temporarily set | |
248 | * the status and diagnosis of this MultiRepository, until the recursion | |
249 | * unwinds back, and the MultiThreadSearch at the root of this recursion will | |
250 | * set the ultimate diagnosis and status of invocation of getAttributes | |
251 | * method. Note also that if the getAttributes method on the corresponding | |
252 | * repositories is synchronized, this will only slow down the multithreaded | |
253 | * search, but will not block the process (unless by some bad design they | |
254 | * use the same MultiRepository that invoked them). | |
255 | * | |
256 | * <p>After calling the method the repository will be set into one of the | |
257 | * states: FAILURE_STATUS, SUCCESS_STATUS or PARTIAL_SUCCESS_STATUS. Failure | |
258 | * means there were no roots that succeeded. Success means that all of the | |
259 | * roots succeeded (the entries were found and some or no attributes were | |
260 | * retrieved). Partial success means that some of the roots failed, but some | |
261 | * have succeeded, which may be in case some of the roots do not contain | |
262 | * the required entry. The caller must find out himself what the cause is, and | |
263 | * decide if the results are sufficiently successful. | |
264 | * | |
265 | * @param DN The distinguished names of the entry from which the attributes | |
266 | * are requested | |
267 | * @param repositories The repositories to be searched; must have the same number | |
268 | * of elements, as DN; each DN must have a non-null repository corresponding | |
269 | * @param AttributeNames The array of LDAP names for the attributes; can be | |
270 | * null, if all available attributes and their values are to be retrieved | |
271 | * | |
272 | * @return the requested attributes; the Repository status reflects the status | |
273 | * of retrieval, the diagnosis contains exceptions the underlying objects | |
274 | * threw, if they failed | |
275 | * | |
276 | * @throws RepositoryException, if all of the repositories failed, in which case the | |
277 | * embedded exception will be the Throwable returned by <code>getDiagnosis</code> | |
278 | * method; FAILURE_STATUS will also be set | |
279 | * | |
280 | * @see MultiThreadSearch#getAttributes | |
281 | */ | |
282 | 6454 | protected Attributes getAttributes(java.security.Principal[] DN, AttributeRepository [] repositories, String [] AttributeNames) throws RepositoryException{ |
283 | 6454 | MultiThreadSearch ms = new MultiThreadSearch(); |
284 | 6454 | try{ |
285 | 6454 | logger.debug("get attributes based on "); |
286 | 12945 | for (int i=0; i<DN.length; i++) logger.debug("dn = "+DN[i].getName()); |
287 | 12945 | for (int i=0; i<repositories.length; i++) logger.debug("repository = "+repositories[i].getClass().getName()); |
288 | 12908 | for (int i=0; i<AttributeNames.length; i++) logger.debug("attribute name = "+AttributeNames[i]); |
289 | 6454 | return ms.getAttributes(DN, repositories, AttributeNames); |
290 | }finally{ | |
291 | 6454 | mts=ms; |
292 | } | |
293 | } | |
294 | ||
295 | /** | |
296 | * This method returns the status of the repository. It is set when returning | |
297 | * attributes. | |
298 | * | |
299 | * @return the integer value corresponding to the status | |
300 | * | |
301 | * @see getAttributes(java.security.Principal,String[]) | |
302 | */ | |
303 | 0 | public int getStatus(){ |
304 | 0 | return mts.status; |
305 | } | |
306 | ||
307 | /** | |
308 | * This method returns the Throwable, representing the error, or null, if no | |
309 | * error has been encountered (only if the repository is in SUCCESS_STATUS). | |
310 | * The Throwable contains an error message and the stack trace of the error. | |
311 | * | |
312 | * @return Throwable object, representing the error, or null, if no error occured | |
313 | */ | |
314 | 3215 | public Throwable getDiagnosis(){ |
315 | 3215 | return mts.diagnosis; |
316 | } | |
317 | ||
318 | /** | |
319 | * This method returns the array of repositories used by the MultiRepository | |
320 | * by default (when TokenLocators do not refer to a specific repository). | |
321 | * | |
322 | * @return the array of AttributeRespositories used by MultiRepository by | |
323 | * default; is never null, does not contain null entries, but may be empty | |
324 | * (zero length) | |
325 | */ | |
326 | 0 | public AttributeRepository [] getRepositories() { |
327 | 0 | return initialRepositories; |
328 | } | |
329 | } | |
330 | ||
331 | /** | |
332 | * This is a utility class that does the actual search in multiple repositories | |
333 | * using multiple threads. The logic of invocation must guarantee that it is | |
334 | * used from a single Thread. | |
335 | */ | |
336 | class MultiThreadSearch implements Runnable { | |
337 | protected int status; // status of the Repository | |
338 | protected Throwable diagnosis; // the ultimate status: the stack frame in it, the error message to deliver, etc | |
339 | private static Logger logger = Logger.getLogger(MultiThreadSearch.class); | |
340 | private AttributeRepository [] reps; | |
341 | private Throwable [] statuses; // the latest Exceptions thrown by run() methods; null for OK | |
342 | private Attributes [] results; // the latest results returned by run() methods | |
343 | ||
344 | /** | |
345 | * Variables used by run() method | |
346 | */ | |
347 | private java.security.Principal searchDN[]; // this is the DN that the run() method uses | |
348 | private String [] attrIDs; // this is the IDs of attributes the run() method uses | |
349 | private int launched=0; // counter of launched threads | |
350 | private int [] finished={0}; // counter of terminated threads | |
351 | // it is an array, because I want it to be secure when calling getAttributes twice in a row for any unobvious reason - I can do wait() on arrays | |
352 | 7167 | protected MultiThreadSearch(){} |
353 | ||
354 | /** | |
355 | * This method sets up a number of threads, each retrieving the whole set of | |
356 | * attributes from one repository using the corresponding entry name. The | |
357 | * list of entry names must be synchronous with the list of repositories. | |
358 | * | |
359 | * <p>As the result of calling this method, the diagnosis and status will be | |
360 | * set. | |
361 | * | |
362 | * @param DN - the entry names; one for each repository | |
363 | * @param repositories - the repositories; one for each entry in the DN array | |
364 | * @param AttributeNames - the names of the attributes to be retrieved from | |
365 | * all repositories; if null, all available attributes will be retrieved | |
366 | * | |
367 | * @return the requested Attributes | |
368 | */ | |
369 | 6454 | protected Attributes getAttributes(java.security.Principal[] DN, AttributeRepository [] repositories, String [] AttributeNames) throws RepositoryException{ |
370 | 6454 | status = AttributeRepository.SUCCESS_STATUS; |
371 | 6454 | diagnosis = null; // nothing has been thrown so far |
372 | 6454 | launched=0; |
373 | 6454 | finished=new int[]{0}; // thus, stray threads will use their own copy |
374 | 6454 | searchDN=DN; |
375 | 6454 | reps=repositories; |
376 | 6454 | attrIDs = AttributeNames; |
377 | 6454 | statuses = new Throwable[reps.length]; |
378 | 6454 | results = new Attributes[reps.length]; |
379 | ||
380 | 6454 | try{ |
381 | 6454 | try{ |
382 | 12945 | while (launched<reps.length){ // launched is updated by run() method, called by Thread().start() |
383 | 6491 | synchronized(this){ |
384 | 6491 | new Thread(this).start(); // searches in different LDAPs will be mainly independent, and lots of waiting; so let them be different threads |
385 | 6491 | this.wait(); // wait till the run() passes by updating the launched counter |
386 | } | |
387 | } | |
388 | 6454 | synchronized(this.finished){ |
389 | 6454 | if (finished[0]<reps.length){ // yet not everyone has finished. |
390 | 6305 | this.finished.wait(); // so hold me, until it sleeps.. ;-) |
391 | // until it wakes, actually :-))))) | |
392 | } | |
393 | } | |
394 | ||
395 | // now we are alright; collect the wrecks :-) | |
396 | // or whatever the world has brought to us | |
397 | ||
398 | // we are synchronized, and noone else is supposed to replace statuses and results array values | |
399 | 6454 | Exception pe = null; |
400 | ||
401 | 12945 | for (int i=0; i<statuses.length; i++){ |
402 | 6491 | if (statuses[i]!=null){ |
403 | // something has happened in thread i while accessing reps[i] | |
404 | ||
405 | // at this point we should verify how crucial the error was | |
406 | 3 | pe = new issrg.utils.ExceptionPairException(pe, statuses[i]); // now we can output the thing |
407 | } | |
408 | 6491 | if (statuses[i]==null || results[i]!=null) status = AttributeRepository.PARTIAL_SUCCESS_STATUS; |
409 | } | |
410 | ||
411 | 6454 | if (pe!=null && status==AttributeRepository.SUCCESS_STATUS){ |
412 | // this means that the branch status=PARTIAL_SUCCESS_STATUS has never been | |
413 | // executed; meaning that all of the statuses were not null; meaning | |
414 | // it is a complete failure. | |
415 | 0 | throw new RepositoryException(null, pe); |
416 | } | |
417 | ||
418 | 6454 | if (pe==null){ |
419 | // this means that all the iterations of the loop went through | |
420 | // status=PARTIAL_SUCCESS_STATUS branch, so in fact it is a complete success | |
421 | 6451 | status=AttributeRepository.SUCCESS_STATUS; |
422 | } | |
423 | ||
424 | 6454 | diagnosis = pe; |
425 | ||
426 | // here it is safe to collect results | |
427 | // do not amend the status variable | |
428 | ||
429 | 6454 | Attributes result = new javax.naming.directory.BasicAttributes(); |
430 | ||
431 | 12945 | for (int i=0; i<results.length; i++){ |
432 | 6491 | Attributes a = results[i]; |
433 | 6491 | if (a==null) continue; |
434 | ||
435 | 11862 | for(javax.naming.NamingEnumeration ne = a.getIDs(); ne.hasMoreElements();){ |
436 | 5734 | String id = (String)ne.nextElement(); |
437 | 5734 | javax.naming.directory.Attribute attr = a.get(id), collection_attr=result.get(id); |
438 | 5734 | if (attr!=null){ |
439 | 5734 | if (collection_attr==null){ |
440 | 5730 | result.put(attr); |
441 | }else{ | |
442 | 8 | for(javax.naming.NamingEnumeration ne1 = attr.getAll(); ne1.hasMoreElements(); ){ |
443 | 4 | collection_attr.add(ne1.nextElement()); // do I check for the return value?.. |
444 | } | |
445 | ||
446 | // since we have updated the object by reference, this should be sufficient | |
447 | // unless they return us a clone... | |
448 | } | |
449 | } | |
450 | } | |
451 | } | |
452 | ||
453 | // now result contains all Attributes and all values for each of them | |
454 | ||
455 | 6454 | return result; |
456 | }catch (InterruptedException ie){ | |
457 | // this and the following catches are put here for the reason | |
458 | // we might want to change the error code or the exception thrown | |
459 | // (e.g. throw a descendant of the PbaException, not the PbaException itself) | |
460 | 0 | throw new RepositoryException("The thread was interrupted while waiting", ie); |
461 | }catch (javax.naming.NamingException ne){ | |
462 | 0 | throw new RepositoryException("Naming violation", ne); |
463 | }catch(Throwable th){ | |
464 | 0 | throw new RepositoryException("Unknown error", th); |
465 | } | |
466 | }catch(RepositoryException pe){ // really, this try{}catch block is needed purely to set this status | |
467 | // note, that nothing else is thrown withing that block(!) | |
468 | // so the method is error-free; i mean, all the reports can be | |
469 | // reported to the caller in a valid manner | |
470 | 0 | status = AttributeRepository.FAILURE_STATUS; |
471 | 0 | diagnosis=pe; |
472 | 0 | throw pe; |
473 | } | |
474 | ||
475 | } | |
476 | ||
477 | /** | |
478 | * This method is needed for efficient Attribute retrieval. You should not | |
479 | * call it directly, as this is part of Runnable interface. | |
480 | */ | |
481 | 6491 | public void run(){ |
482 | 6491 | int idx; |
483 | // lets have a local copy of everything, so if the getAttribtues screws up, | |
484 | // we won't screw up a consequent call. | |
485 | 6491 | AttributeRepository rep; |
486 | 6491 | int [] fin; |
487 | 6491 | int when_notify; |
488 | 6491 | Attributes [] ress; |
489 | 6491 | Throwable [] stats; |
490 | ||
491 | 6491 | java.security.Principal searchDN; |
492 | 6491 | String [] attrIDs = this.attrIDs; |
493 | ||
494 | ||
495 | 6491 | synchronized(this){ |
496 | 6491 | when_notify = reps.length; |
497 | 6491 | idx=launched; |
498 | 6491 | ress=results; |
499 | 6491 | stats=statuses; |
500 | 6491 | searchDN = this.searchDN[idx]; |
501 | 6491 | fin = finished; // save the pointer, so even if anything happens to the caller thread, we won't spoil the subsequent calls to the run() |
502 | 6491 | results[idx]=null; |
503 | 6491 | rep=reps[idx]; |
504 | ||
505 | // unlock the waiter - let us launch search in another repository | |
506 | 6491 | launched++; |
507 | 6491 | this.notifyAll(); |
508 | } | |
509 | ||
510 | // now i believe all entries about the idx index are locked for my sole use | |
511 | ||
512 | 6491 | Attributes result=null; |
513 | 6491 | Throwable status=null; |
514 | 6491 | try{ |
515 | // do some real retrieval here :-) | |
516 | ||
517 | // calling the implementation's method - it will go look for the attributes | |
518 | 6491 | logger.debug("start to get "+searchDN.getName()+" from "+rep.getClass().getName()); |
519 | 6491 | result = rep.getAttributes(searchDN, attrIDs); |
520 | 6491 | logger.debug("successful"); |
521 | 6491 | status = rep.getDiagnosis(); // this is not thread-safe; If multiple threads use the same repository it may happen some diagnosis is lost, but the advantage is that multiple threads may invoke search on the same repository |
522 | }catch(Throwable th){ | |
523 | 0 | status=th; |
524 | }finally{ | |
525 | 6491 | ress[idx]=result; |
526 | 6491 | stats[idx]=status; |
527 | ||
528 | 6491 | synchronized(fin){ |
529 | 6491 | fin[0]++; |
530 | 6491 | if (when_notify<=fin[0]){ // release the wait of the getAttributes() |
531 | 6454 | fin.notifyAll(); |
532 | } | |
533 | } | |
534 | } | |
535 | } | |
536 | } |
|