📄 multirepository.java
字号:
* of elements, as DN; each DN must have a non-null repository corresponding
* @param AttributeNames The array of LDAP names for the attributes; can be
* null, if all available attributes and their values are to be retrieved
*
* @return the requested attributes; the Repository status reflects the status
* of retrieval, the diagnosis contains exceptions the underlying objects
* threw, if they failed
*
* @throws RepositoryException, if all of the repositories failed, in which case the
* embedded exception will be the Throwable returned by <code>getDiagnosis</code>
* method; FAILURE_STATUS will also be set
*
* @see MultiThreadSearch#getAttributes
*/
protected Attributes getAttributes(java.security.Principal[] DN, AttributeRepository [] repositories, String [] AttributeNames) throws RepositoryException{
MultiThreadSearch ms = new MultiThreadSearch();
try{
return ms.getAttributes(DN, repositories, AttributeNames);
}finally{
mts=ms;
}
}
/**
* This method returns the status of the repository. It is set when returning
* attributes.
*
* @return the integer value corresponding to the status
*
* @see getAttributes(java.security.Principal,String[])
*/
public int getStatus(){
return mts.status;
}
/**
* This method returns the Throwable, representing the error, or null, if no
* error has been encountered (only if the repository is in SUCCESS_STATUS).
* The Throwable contains an error message and the stack trace of the error.
*
* @return Throwable object, representing the error, or null, if no error occured
*/
public Throwable getDiagnosis(){
return mts.diagnosis;
}
/**
* This method returns the array of repositories used by the MultiRepository
* by default (when TokenLocators do not refer to a specific repository).
*
* @return the array of AttributeRespositories used by MultiRepository by
* default; is never null, does not contain null entries, but may be empty
* (zero length)
*/
public AttributeRepository [] getRepositories() {
return initialRepositories;
}
}
/**
* This is a utility class that does the actual search in multiple repositories
* using multiple threads. The logic of invocation must guarantee that it is
* used from a single Thread.
*/
class MultiThreadSearch implements Runnable {
protected int status; // status of the Repository
protected Throwable diagnosis; // the ultimate status: the stack frame in it, the error message to deliver, etc
private AttributeRepository [] reps;
private Throwable [] statuses; // the latest Exceptions thrown by run() methods; null for OK
private Attributes [] results; // the latest results returned by run() methods
/**
* Variables used by run() method
*/
private java.security.Principal searchDN[]; // this is the DN that the run() method uses
private String [] attrIDs; // this is the IDs of attributes the run() method uses
private int launched=0; // counter of launched threads
private int [] finished={0}; // counter of terminated threads
// 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
protected MultiThreadSearch(){}
/**
* This method sets up a number of threads, each retrieving the whole set of
* attributes from one repository using the corresponding entry name. The
* list of entry names must be synchronous with the list of repositories.
*
* <p>As the result of calling this method, the diagnosis and status will be
* set.
*
* @param DN - the entry names; one for each repository
* @param repositories - the repositories; one for each entry in the DN array
* @param AttributeNames - the names of the attributes to be retrieved from
* all repositories; if null, all available attributes will be retrieved
*
* @return the requested Attributes
*/
protected Attributes getAttributes(java.security.Principal[] DN, AttributeRepository [] repositories, String [] AttributeNames) throws RepositoryException{
status = AttributeRepository.SUCCESS_STATUS;
diagnosis = null; // nothing has been thrown so far
launched=0;
finished=new int[]{0}; // thus, stray threads will use their own copy
searchDN=DN;
reps=repositories;
attrIDs = AttributeNames;
statuses = new Throwable[reps.length];
results = new Attributes[reps.length];
try{
try{
while (launched<reps.length){ // launched is updated by run() method, called by Thread().start()
synchronized(this){
new Thread(this).start(); // searches in different LDAPs will be mainly independent, and lots of waiting; so let them be different threads
this.wait(); // wait till the run() passes by updating the launched counter
}
}
synchronized(this.finished){
if (finished[0]<reps.length){ // yet not everyone has finished.
this.finished.wait(); // so hold me, until it sleeps.. ;-)
// until it wakes, actually :-)))))
}
}
// now we are alright; collect the wrecks :-)
// or whatever the world has brought to us
// we are synchronized, and noone else is supposed to replace statuses and results array values
Exception pe = null;
for (int i=0; i<statuses.length; i++){
if (statuses[i]!=null){
// something has happened in thread i while accessing reps[i]
// at this point we should verify how crucial the error was
pe = new issrg.utils.ExceptionPairException(pe, statuses[i]); // now we can output the thing
}
if (statuses[i]==null || results[i]!=null) status = AttributeRepository.PARTIAL_SUCCESS_STATUS;
}
if (pe!=null && status==AttributeRepository.SUCCESS_STATUS){
// this means that the branch status=PARTIAL_SUCCESS_STATUS has never been
// executed; meaning that all of the statuses were not null; meaning
// it is a complete failure.
throw new RepositoryException(null, pe);
}
if (pe==null){
// this means that all the iterations of the loop went through
// status=PARTIAL_SUCCESS_STATUS branch, so in fact it is a complete success
status=AttributeRepository.SUCCESS_STATUS;
}
diagnosis = pe;
// here it is safe to collect results
// do not amend the status variable
Attributes result = new javax.naming.directory.BasicAttributes();
for (int i=0; i<results.length; i++){
Attributes a = results[i];
if (a==null) continue;
for(javax.naming.NamingEnumeration ne = a.getIDs(); ne.hasMoreElements();){
String id = (String)ne.nextElement();
javax.naming.directory.Attribute attr = a.get(id), collection_attr=result.get(id);
if (attr!=null){
if (collection_attr==null){
result.put(attr);
}else{
for(javax.naming.NamingEnumeration ne1 = attr.getAll(); ne1.hasMoreElements(); ){
collection_attr.add(ne1.nextElement()); // do I check for the return value?..
}
// since we have updated the object by reference, this should be sufficient
// unless they return us a clone...
}
}
}
}
// now result contains all Attributes and all values for each of them
return result;
}catch (InterruptedException ie){
// this and the following catches are put here for the reason
// we might want to change the error code or the exception thrown
// (e.g. throw a descendant of the PbaException, not the PbaException itself)
throw new RepositoryException("The thread was interrupted while waiting", ie);
}catch (javax.naming.NamingException ne){
throw new RepositoryException("Naming violation", ne);
}catch(Throwable th){
throw new RepositoryException("Unknown error", th);
}
}catch(RepositoryException pe){ // really, this try{}catch block is needed purely to set this status
// note, that nothing else is thrown withing that block(!)
// so the method is error-free; i mean, all the reports can be
// reported to the caller in a valid manner
status = AttributeRepository.FAILURE_STATUS;
diagnosis=pe;
throw pe;
}
}
/**
* This method is needed for efficient Attribute retrieval. You should not
* call it directly, as this is part of Runnable interface.
*/
public void run(){
int idx;
// lets have a local copy of everything, so if the getAttribtues screws up,
// we won't screw up a consequent call.
AttributeRepository rep;
int [] fin;
int when_notify;
Attributes [] ress;
Throwable [] stats;
java.security.Principal searchDN;
String [] attrIDs = this.attrIDs;
synchronized(this){
when_notify = reps.length;
idx=launched;
ress=results;
stats=statuses;
searchDN = this.searchDN[idx];
fin = finished; // save the pointer, so even if anything happens to the caller thread, we won't spoil the subsequent calls to the run()
results[idx]=null;
rep=reps[idx];
// unlock the waiter - let us launch search in another repository
launched++;
this.notifyAll();
}
// now i believe all entries about the idx index are locked for my sole use
Attributes result=null;
Throwable status=null;
try{
// do some real retrieval here :-)
// calling the implementation's method - it will go look for the attributes
result = rep.getAttributes(searchDN, attrIDs);
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
}catch(Throwable th){
status=th;
}finally{
ress[idx]=result;
stats[idx]=status;
synchronized(fin){
fin[0]++;
if (when_notify<=fin[0]){ // release the wait of the getAttributes()
fin.notifyAll();
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -