Source code: com/fetish/directory/Search.java
1 package com.fetish.directory;
2
3 import java.util.Vector;
4 import net.jini.core.lookup.ServiceMatches;
5 import net.jini.core.lookup.ServiceItem;
6 import net.jini.core.lookup.ServiceID;
7
8 /**
9 * Class with information about a search process. <br>
10 * It holds the responses from all asked FADA nodes.
11 */
12 public class Search {
13
14 private Object lock;
15 private Object lockpending;
16 private long maxWaitTime;
17 private Vector pendingThreads;
18 private long expiryDate;
19
20 public static final long MAX_WAIT_TIME = 10000;
21
22 /** This search identifier */
23 SearchID searchID;
24
25 /** Number of pending searches */
26 long pending = 0;
27
28 /** Vector of ServiceItem elements with services found for this search */
29 private Vector results;
30
31 /** Maximum number of responses */
32 int maxResponses = Integer.MAX_VALUE;
33
34 /**
35 * Constructs a new Search object with the specified SearchID and default maximum wait time.
36 */
37 public Search( SearchID id, int maxResponses ) {
38 this.lock = new Object();
39 this.lockpending = new Object();
40 this.pending = 0;
41 this.searchID = id;
42 this.results = new Vector( 0, 1 );
43 this.pendingThreads = new Vector( 0, 1 );
44 this.maxWaitTime = MAX_WAIT_TIME;
45 this.maxResponses = maxResponses;
46 this.expiryDate = System.currentTimeMillis();
47 }
48
49 /**
50 * Constructs a new Search object with the specified SearchID and maximum wait time.
51 */
52 public Search( SearchID id, long maxWaitTime, int maxResponses ) {
53 this.lock = new Object();
54 this.lockpending = new Object();
55 this.pending = 0;
56 this.searchID = id;
57 this.results = new Vector( 0, 1 );
58 this.pendingThreads = new Vector( 0, 1 );
59 this.maxWaitTime = maxWaitTime;
60 this.maxResponses = maxResponses;
61 this.expiryDate = System.currentTimeMillis();
62 }
63
64 // Do we need this one?
65 //public Search( SearchID id, long numSearches ) {
66 //this.lock = new Object();
67 //this.pending = numSearches;
68 //this.searchID = id;
69 //this.results = new Vector( 0, 1 );
70 //}
71 /**
72 * Adds <code>started</code> to the amount of started searches to wait
73 * results from.<br>
74 */
75 public void startedSearches( int started ) {
76 synchronized( this.lockpending ) {
77 this.pending += started;
78 }
79 }
80
81 /**
82 * Adds one to the amount of started searches for the FADA node identified
83 * by <code>sid</code> ServiceID.<br>
84 */
85 public void startedSearches( ServiceID sid ) {
86 if( !this.pendingThreads.contains( sid ) ) {
87 this.pendingThreads.add( sid );
88 }
89 }
90
91 /**
92 * Obtains the SearchID for this Search object
93 */
94 public SearchID getSearchID() {
95 return this.searchID;
96 }
97
98 /**
99 * Obtains the expiry date for this Search object
100 */
101 public long getExpiryDate() {
102 return this.expiryDate;
103 }
104
105 /**
106 * Sets the expiry date for this Search object
107 */
108 public void setExpiryDate( long date ) {
109 this.expiryDate = date;
110 }
111
112 /**
113 * Puts obtained results in this Search object.<br>
114 * This method decreases the count of started searches to allow
115 * early return of the <code>getResults</code> method.
116 */
117 public synchronized void addResult (ServiceMatches sm) {
118
119 // extract the serviceItems from the serviceMatches
120 if (sm != null) {
121 for (int i=0; i<sm.totalMatches; i++) {
122 results.addElement(sm.items[i]);
123 }
124 } else
125 synchronized( this.lockpending ) {
126 pending--;
127 if ( /*( pending <= 0 ) ||*/ ( this.maxResponses <= results.size() ) ) {
128 synchronized( this.lock ) {
129 this.lock.notify();
130 }
131 } else {
132 }
133 }
134 }
135
136 /**
137 * Puts obtained results in this Search object for the FADA node
138 * identified by <code>sid</code> ServiceID.
139 * This method decreases the count of started searches to allow
140 * early return of the <code>getResults</code> method.
141 */
142 public synchronized void addResult ( ServiceID sid, ServiceMatches sm ) {
143 // Add results on Search object
144 if( this.pendingThreads.contains( sid ) ) {
145 this.pendingThreads.remove( sid );
146 synchronized( this.lockpending ) {
147 pending--;
148 if ( /*( pending <= 0 ) ||*/ ( this.maxResponses <= results.size() ) ) {
149 synchronized( this.lock ) {
150 this.lock.notify();
151 }
152 }
153 }
154 }
155 }
156
157 /**
158 * Announces that a search process for this Search has finished.
159 * This method decreases the count of started searches for this
160 * Search object.
161 */
162 public void finishedSearch() {
163 synchronized( this.lockpending ) {
164 pending--;
165 //if( pending <= 0 ) {
166 // No more pending threads on this search id
167 //synchronized( this.lock ) {
168 //this.lock.notify();
169 //}
170 //}
171 }
172 }
173
174 /**
175 * Obtains the results of the search process.
176 * This method blocks the calling thread until the search process has
177 * finished, which happens when:<p>
178 * <ul>
179 * <li>The amount of responses reaches <i>maxResponses OR</i></li>
180 * <li>maxWaitTime milliseconds have passed since call to this
181 * method <i>OR</i></li>
182 * <li>All started search threads have finished</li>
183 * </ul>
184 * @return The ServiceMatches class for the results of the search.
185 */
186 public ServiceMatches getResults() {
187
188 try {
189 synchronized( this.lock ) {
190 this.lock.wait( this.maxWaitTime );
191 }
192 } catch( InterruptedException e ) {
193 }
194
195 // construct a serviceMatches from the serviceItem elements
196
197 // In order to maintain Jini semantics, a null array must be the
198 // items array if no result is found ( Vector.toArray() constructs
199 // a 0 elements array when Vector has no elements
200
201 ServiceItem[] items = null;
202 if ( results.size() > 0 ) {
203 items = ( ServiceItem[] )results.toArray(
204 new ServiceItem[ results.size() ]
205 );
206 }
207
208 return new ServiceMatches( items, results.size() );
209 }
210 /*
211 public boolean equals(Object o) {
212 if ( o instanceof Search ) {
213 return ((Search)o).equals(this.id);
214 }
215 return false;
216 }
217 */
218 }