| 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 | } | |
|
||||||||||