View Javadoc
1   /*
2    * Copyright 2001-2008 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  
18  package org.apache.juddi.api.impl;
19  
20  import java.util.ArrayList;
21  import java.util.Date;
22  import java.util.GregorianCalendar;
23  import java.util.List;
24  import java.util.UUID;
25  
26  import javax.jws.WebService;
27  import javax.persistence.EntityManager;
28  import javax.persistence.EntityTransaction;
29  import javax.xml.bind.JAXBException;
30  import javax.xml.datatype.DatatypeConfigurationException;
31  import javax.xml.datatype.DatatypeFactory;
32  import javax.xml.ws.Holder;
33  
34  import org.apache.commons.configuration.ConfigurationException;
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.juddi.api.util.QueryStatus;
38  import org.apache.juddi.api.util.SubscriptionQuery;
39  import org.apache.juddi.config.AppConfig;
40  import org.apache.juddi.config.PersistenceManager;
41  import org.apache.juddi.config.Property;
42  import org.apache.juddi.jaxb.JAXBMarshaller;
43  import org.apache.juddi.mapping.MappingApiToModel;
44  import org.apache.juddi.mapping.MappingModelToApi;
45  import org.apache.juddi.model.SubscriptionChunkToken;
46  import org.apache.juddi.model.SubscriptionMatch;
47  import org.apache.juddi.model.UddiEntityPublisher;
48  import org.apache.juddi.query.FindBusinessByPublisherQuery;
49  import org.apache.juddi.query.FindSubscriptionByPublisherQuery;
50  import org.apache.juddi.v3.error.ErrorMessage;
51  import org.apache.juddi.v3.error.FatalErrorException;
52  import org.apache.juddi.v3.error.InvalidValueException;
53  import org.apache.juddi.validation.ValidateSubscription;
54  import org.uddi.api_v3.AssertionStatusReport;
55  import org.uddi.api_v3.BindingDetail;
56  import org.uddi.api_v3.BusinessDetail;
57  import org.uddi.api_v3.BusinessList;
58  import org.uddi.api_v3.FindBinding;
59  import org.uddi.api_v3.FindBusiness;
60  import org.uddi.api_v3.FindRelatedBusinesses;
61  import org.uddi.api_v3.FindService;
62  import org.uddi.api_v3.FindTModel;
63  import org.uddi.api_v3.GetAssertionStatusReport;
64  import org.uddi.api_v3.GetBindingDetail;
65  import org.uddi.api_v3.GetBusinessDetail;
66  import org.uddi.api_v3.GetServiceDetail;
67  import org.uddi.api_v3.GetTModelDetail;
68  import org.uddi.api_v3.RelatedBusinessesList;
69  import org.uddi.api_v3.ServiceDetail;
70  import org.uddi.api_v3.ServiceList;
71  import org.uddi.api_v3.TModelDetail;
72  import org.uddi.api_v3.TModelList;
73  import org.uddi.sub_v3.DeleteSubscription;
74  import org.uddi.sub_v3.GetSubscriptionResults;
75  import org.uddi.sub_v3.KeyBag;
76  import org.uddi.sub_v3.Subscription;
77  import org.uddi.sub_v3.SubscriptionFilter;
78  import org.uddi.sub_v3.SubscriptionResultsList;
79  import org.uddi.v3_service.DispositionReportFaultMessage;
80  import org.uddi.v3_service.UDDISubscriptionPortType;
81  
82  /**
83   * This is jUDDI's implementation of the UDDIv3 Subscription API
84   */
85  @WebService(serviceName="UDDISubscriptionService", 
86  			endpointInterface="org.uddi.v3_service.UDDISubscriptionPortType",
87  			targetNamespace = "urn:uddi-org:api_v3_portType")
88  public class UDDISubscriptionImpl extends AuthenticatedService implements UDDISubscriptionPortType {
89  
90  	private static Log logger = LogFactory.getLog(UDDISubscriptionImpl.class);
91  
92  	public static final int DEFAULT_SUBSCRIPTIONEXPIRATION_DAYS = 30;
93  	public static final int DEFAULT_CHUNKEXPIRATION_MINUTES = 5;
94  
95  	public static final String CHUNK_TOKEN_PREFIX = "chunktoken:";
96  
97          private UDDIServiceCounter serviceCounter;
98  
99          public UDDISubscriptionImpl() {
100             super();
101             serviceCounter = ServiceCounterLifecycleResource.getServiceCounter(this.getClass());
102         }
103 	
104 	public void deleteSubscription(DeleteSubscription body)
105 			throws DispositionReportFaultMessage {
106 	        long startTime = System.currentTimeMillis();
107 
108 		EntityManager em = PersistenceManager.getEntityManager();
109 		EntityTransaction tx = em.getTransaction();
110 		try {
111 			tx.begin();
112 	
113 			UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());
114 			new ValidateSubscription(publisher).validateDeleteSubscription(em, body);
115 			
116 	        List<String> subscriptionKeyList = body.getSubscriptionKey();
117 	        for (String subscriptionKey : subscriptionKeyList) {
118 	                Object obj = em.find(org.apache.juddi.model.Subscription.class, subscriptionKey);
119 	                em.remove(obj);
120 	        }
121 	
122 	        tx.commit();
123                 long procTime = System.currentTimeMillis() - startTime;
124                 serviceCounter.update(SubscriptionQuery.DELETE_SUBSCRIPTION, 
125                         QueryStatus.SUCCESS, procTime);
126                 } catch (DispositionReportFaultMessage drfm) {
127                     long procTime = System.currentTimeMillis() - startTime;
128                     serviceCounter.update(SubscriptionQuery.DELETE_SUBSCRIPTION, 
129                             QueryStatus.FAILED, procTime);                      
130                     throw drfm;                                                                                                 
131 		} finally {
132 			if (tx.isActive()) {
133 				tx.rollback();
134 			}
135 			em.close();
136 		}
137 	}
138    
139     public SubscriptionResultsList getSubscriptionResults(GetSubscriptionResults body) throws DispositionReportFaultMessage {
140     	return getSubscriptionResults(body, null);
141     }
142 	/* (non-Javadoc)
143 	 * @see org.uddi.v3_service.UDDISubscriptionPortType#getSubscriptionResults(org.uddi.sub_v3.GetSubscriptionResults)
144 	 * 
145 	 * Notes: Does it make sense to refresh the subscription matches on a call to this method?  I don't think so, the user theoretically had
146 	 * a set of entities in mind when the subscription was saved and the snapshot should remain just that - a snapshot of the entities at the
147 	 * time of the subscription save.  The result of this policy is that if an entity is deleted, that deleted result will appear in the keyBag
148 	 * on every call to this method.  To resolve this, the user can renew the subscription at which time the "match" snapshot will be refreshed.
149 	 * 
150 	 * The WS needs to be authenticated (null publisher), however the notificationSubscriber is calling this method also. The
151 	 * notificationSubscriber will pass in the publisher and this method will work in unauthenticated mode.
152 	 */
153 	@SuppressWarnings("unchecked")
154 	public SubscriptionResultsList getSubscriptionResults(GetSubscriptionResults body, UddiEntityPublisher publisher) throws DispositionReportFaultMessage {
155                 long startTime = System.currentTimeMillis();
156             
157 		EntityManager em = PersistenceManager.getEntityManager();
158 		EntityTransaction tx = em.getTransaction();
159                 try {
160 	        tx.begin();
161 	        
162 			if (publisher==null) {
163 				publisher = this.getEntityPublisher(em, body.getAuthInfo());
164 				new ValidateSubscription(publisher).validateGetSubscriptionResults(em, body);
165 			}
166 			
167 			org.apache.juddi.model.Subscription modelSubscription = em.find(org.apache.juddi.model.Subscription.class, body.getSubscriptionKey());
168 			SubscriptionFilter subscriptionFilter = null;
169 			try {
170 				subscriptionFilter = (SubscriptionFilter)JAXBMarshaller.unmarshallFromString(modelSubscription.getSubscriptionFilter(), JAXBMarshaller.PACKAGE_SUBSCRIPTION);
171 			} 
172 			catch (JAXBException e) {
173 				logger.error("JAXB Exception while unmarshalling subscription filter", e);
174 				throw new FatalErrorException(new ErrorMessage("errors.Unspecified"));
175 			}
176 			if (logger.isDebugEnabled()) logger.debug("filter=" + modelSubscription.getSubscriptionFilter());
177 			
178 			SubscriptionResultsList result = new SubscriptionResultsList();
179                         result.setChunkToken("0");
180                         //chunkToken:  Optional element used to retrieve subsequent groups of data when the first invocation of this API indicates more data is available.  This occurs when a chunkToken is returned whose value is not "0" in the validValuesList structure described in the next section.  To retrieve the next chunk of data, the chunkToken returned should be used as an argument to the next invocation of this API.
181 			result.setCoveragePeriod(body.getCoveragePeriod());
182 	
183 			// The subscription structure is required output for the results
184 			org.uddi.sub_v3.Subscription apiSubscription = new org.uddi.sub_v3.Subscription();
185 			MappingModelToApi.mapSubscription(modelSubscription, apiSubscription);
186 			result.setSubscription(apiSubscription);
187 			
188 			Date startPointDate = new Date(body.getCoveragePeriod().getStartPoint().toGregorianCalendar().getTimeInMillis());
189 			Date endPointDate = new Date(body.getCoveragePeriod().getEndPoint().toGregorianCalendar().getTimeInMillis());
190 	
191 			Integer chunkData = null;
192 			if (body.getChunkToken() != null && body.getChunkToken().length() > 0) {
193 				SubscriptionChunkToken chunkToken = em.find(SubscriptionChunkToken.class, body.getChunkToken());
194 				
195 				if (chunkToken == null)
196 					throw new InvalidValueException(new ErrorMessage("errors.getsubscriptionresult.InvalidChunkToken", body.getChunkToken()));
197 				if (!chunkToken.getSubscriptionKey().equals(body.getSubscriptionKey()))
198 					throw new InvalidValueException(new ErrorMessage("errors.getsubscriptionresult.NonMatchingChunkToken", body.getChunkToken()));
199 				if (chunkToken.getStartPoint() != null && chunkToken.getStartPoint().getTime() != startPointDate.getTime())
200 					throw new InvalidValueException(new ErrorMessage("errors.getsubscriptionresult.NonMatchingChunkToken", body.getChunkToken()));
201 				if (chunkToken.getEndPoint() != null && chunkToken.getEndPoint().getTime() != endPointDate.getTime())
202 					throw new InvalidValueException(new ErrorMessage("errors.getsubscriptionresult.NonMatchingChunkToken", body.getChunkToken()));
203 				if (chunkToken.getExpiresAfter().before(new Date()))
204 					throw new InvalidValueException(new ErrorMessage("errors.getsubscriptionresult.ExpiredChunkToken", body.getChunkToken()));
205 				
206 				chunkData = chunkToken.getData();
207 				// We've got the data from the chunk token, now it is no longer needed (once it's called, it's used up)
208 				em.remove(chunkToken);
209 			}
210 	
211 			
212 			if (subscriptionFilter.getFindBinding() != null) {
213 				//Get the current matching keys
214 				List<?> currentMatchingKeys = getSubscriptionMatches(subscriptionFilter, em);
215 				// See if there's any missing keys by comparing against the previous matches.  If so, they missing keys are added to the KeyBag and
216 				// then added to the result
217 				List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
218 				if (missingKeys != null && missingKeys.size() > 0) {
219 					KeyBag missingKeyBag = new KeyBag();
220 					missingKeyBag.setDeleted(true);
221 					for (String key : missingKeys)
222 						missingKeyBag.getBindingKey().add(key);
223 					
224 					result.getKeyBag().add(missingKeyBag);
225 				}
226 				
227 				// Re-setting the subscription matches to the new matching key collection
228 				//modelSubscription.getSubscriptionMatches().clear();
229 				//for (Object key : currentMatchingKeys) {
230 				//	SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);
231 				//	modelSubscription.getSubscriptionMatches().add(subMatch);
232 				//}
233 				
234 				// Now, finding the necessary entities, within the coverage period limits
235 				if (modelSubscription.isBrief()) {
236 					KeyBag resultsKeyBag = new KeyBag();
237 					for (String key : (List<String>)currentMatchingKeys)
238 						resultsKeyBag.getBindingKey().add(key);
239 					
240 					result.getKeyBag().add(resultsKeyBag);
241 				}
242 				else {
243 					FindBinding fb = subscriptionFilter.getFindBinding();
244 					org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
245 					findQualifiers.mapApiFindQualifiers(fb.getFindQualifiers());
246 					
247 					// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default.  User settings for
248 					// these values don't make sense with the "chunking" feature.
249 					fb.setListHead(null);
250 					fb.setMaxRows(null);
251 					// Setting the start index to the chunkData
252 					Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
253 					
254 					BindingDetail bindingDetail = InquiryHelper.getBindingDetailFromKeys(fb, findQualifiers, em, currentMatchingKeys,              
255 						startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
256 							
257 					// Upon exiting above function, if more results are to be had, the subscriptionStartIndex will contain the latest value (or null
258 					// if no more results)
259 					chunkData = subscriptionStartIndex.value;
260 					
261 					result.setBindingDetail(bindingDetail);
262 				}
263 			}
264 			if (subscriptionFilter.getFindBusiness() != null) {
265 				//Get the current matching keys
266 				List<?> currentMatchingKeys = getSubscriptionMatches(subscriptionFilter, em);
267 	
268 				List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
269 				if (missingKeys != null && missingKeys.size() > 0) {
270 					KeyBag missingKeyBag = new KeyBag();
271 					missingKeyBag.setDeleted(true);
272 					for (String key : missingKeys)
273 						missingKeyBag.getBusinessKey().add(key);
274 	
275 					result.getKeyBag().add(missingKeyBag);
276 				}
277 				
278 				// Re-setting the subscription matches to the new matching key collection
279 				//modelSubscription.getSubscriptionMatches().clear();
280 				//for (Object key : currentMatchingKeys) {
281 				//	SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);
282 				//	modelSubscription.getSubscriptionMatches().add(subMatch);
283 				//}
284 				
285 				// Now, finding the necessary entities, within the coverage period limits
286 				if (modelSubscription.isBrief()) {
287 					KeyBag resultsKeyBag = new KeyBag();
288 					for (String key : (List<String>)currentMatchingKeys)
289 						resultsKeyBag.getBusinessKey().add(key);
290 					
291 					result.getKeyBag().add(resultsKeyBag);
292 				}
293 				else {
294 					FindBusiness fb = subscriptionFilter.getFindBusiness();
295 					org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
296 					findQualifiers.mapApiFindQualifiers(fb.getFindQualifiers());
297 					
298 					// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default.  User settings for
299 					// these values don't make sense with the "chunking" feature.
300 					fb.setListHead(null);
301 					fb.setMaxRows(null);
302 					// Setting the start index to the chunkData
303 					Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
304 					
305 					BusinessList businessList = InquiryHelper.getBusinessListFromKeys(fb, findQualifiers, em, currentMatchingKeys,
306 																					  startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
307 					
308 					// Upon exiting above function, if more results are to be had, the subscriptionStartIndex will contain the latest value (or null
309 					// if no more results)
310 					chunkData = subscriptionStartIndex.value;
311 					
312 					result.setBusinessList(businessList);
313 				}
314 			}
315 			if (subscriptionFilter.getFindService() != null) {
316 				//Get the current matching keys
317 				List<?> currentMatchingKeys = getSubscriptionMatches(subscriptionFilter, em);
318 				if (logger.isDebugEnabled()) logger.debug("current matching keys=" + currentMatchingKeys);
319 				List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
320 				if (missingKeys != null && missingKeys.size() > 0) {
321 					KeyBag missingKeyBag = new KeyBag();
322 					missingKeyBag.setDeleted(true);
323 					for (String key : missingKeys)
324 						missingKeyBag.getServiceKey().add(key);
325 	
326 					result.getKeyBag().add(missingKeyBag);
327 				}
328 				
329 				// Re-setting the subscription matches to the new matching key collection
330 				//modelSubscription.getSubscriptionMatches().clear();
331 				//for (Object key : currentMatchingKeys) {
332 				//	SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);
333 				//	modelSubscription.getSubscriptionMatches().add(subMatch);
334 				//}
335 				
336 				// Now, finding the necessary entities, within the coverage period limits
337 				if (modelSubscription.isBrief()) {
338 					KeyBag resultsKeyBag = new KeyBag();
339 					for (String key : (List<String>)currentMatchingKeys)
340 						resultsKeyBag.getServiceKey().add(key);
341 					
342 					result.getKeyBag().add(resultsKeyBag);
343 				}
344 				else {
345 					FindService fs = subscriptionFilter.getFindService();
346 					org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
347 					findQualifiers.mapApiFindQualifiers(fs.getFindQualifiers());
348 					
349 					// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default.  User settings for
350 					// these values don't make sense with the "chunking" feature.
351 					fs.setListHead(null);
352 					fs.setMaxRows(null);
353 					// Setting the start index to the chunkData
354 					Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
355 	
356 					ServiceList serviceList = InquiryHelper.getServiceListFromKeys(fs, findQualifiers, em, currentMatchingKeys,
357 																				   startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
358 					if (serviceList.getServiceInfos()==null || serviceList.getServiceInfos().getServiceInfo().size()==0) {
359 						serviceList=null;
360 					}
361 					// Upon exiting above function, if more results are to be had, the subscriptionStartIndex will contain the latest value (or null
362 					// if no more results)
363 					chunkData = subscriptionStartIndex.value;
364 					
365 					result.setServiceList(serviceList);
366 				}
367 			}
368 			if (subscriptionFilter.getFindTModel() != null) {
369 				//Get the current matching keys
370 				List<?> currentMatchingKeys = getSubscriptionMatches(subscriptionFilter, em);
371 	
372 				List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
373 				if (missingKeys != null && missingKeys.size() > 0) {
374 					KeyBag missingKeyBag = new KeyBag();
375 					missingKeyBag.setDeleted(true);
376 					for (String key : missingKeys)
377 						missingKeyBag.getTModelKey().add(key);
378 	
379 					result.getKeyBag().add(missingKeyBag);
380 				}
381 				
382 				// Re-setting the subscription matches to the new matching key collection
383 				//modelSubscription.getSubscriptionMatches().clear();
384 				//for (Object key : currentMatchingKeys) {
385 				//	SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);
386 				//	modelSubscription.getSubscriptionMatches().add(subMatch);
387 				//}
388 				
389 				// Now, finding the necessary entities, within the coverage period limits
390 				if (modelSubscription.isBrief()) {
391 					KeyBag resultsKeyBag = new KeyBag();
392 					for (String key : (List<String>)currentMatchingKeys)
393 						resultsKeyBag.getTModelKey().add(key);
394 					
395 					result.getKeyBag().add(resultsKeyBag);
396 				}
397 				else {
398 					FindTModel ft = subscriptionFilter.getFindTModel();
399 					org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
400 					findQualifiers.mapApiFindQualifiers(ft.getFindQualifiers());
401 	
402 					// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default.  User settings for
403 					// these values don't make sense with the "chunking" feature.
404 					ft.setListHead(null);
405 					ft.setMaxRows(null);
406 					// Setting the start index to the chunkData
407 					Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
408 					
409 					// If more results are to be had, chunkData will come out with a value and a new token will be generated below.  Otherwise, it will
410 					// be null and no token will be generated.
411 					TModelList tmodelList = InquiryHelper.getTModelListFromKeys(ft, findQualifiers, em, currentMatchingKeys, 
412 																				startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
413 	
414 					// Upon exiting above function, if more results are to be had, the subscriptionStartIndex will contain the latest value (or null
415 					// if no more results)
416 					chunkData = subscriptionStartIndex.value;
417 					
418 					result.setTModelList(tmodelList);
419 				}
420 				
421 			}
422 			if (subscriptionFilter.getFindRelatedBusinesses() != null) {
423 				FindRelatedBusinesses findRelatedBusiness = subscriptionFilter.getFindRelatedBusinesses();
424 				RelatedBusinessesList  relatedBusinessList = InquiryHelper.getRelatedBusinessesList(findRelatedBusiness, em, startPointDate, endPointDate);
425 				result.setRelatedBusinessesList(relatedBusinessList);
426 			}
427 			if (subscriptionFilter.getGetBindingDetail() != null) {
428 				GetBindingDetail getDetail = subscriptionFilter.getGetBindingDetail();
429 				
430 				// Running through the key list here to determine the deleted keys and store the existing entities.
431 				KeyBag missingKeyBag = new KeyBag();
432 				missingKeyBag.setDeleted(true);
433 				List<org.apache.juddi.model.BindingTemplate> existingList = new ArrayList<org.apache.juddi.model.BindingTemplate>(0);
434 				for (String key : getDetail.getBindingKey()) {
435 					org.apache.juddi.model.BindingTemplate modelBindingTemplate = em.find(org.apache.juddi.model.BindingTemplate.class, key);
436 					if (modelBindingTemplate != null)
437 						existingList.add(modelBindingTemplate);
438 					else
439 						missingKeyBag.getBindingKey().add(key);
440 				}
441 				// Store deleted keys in the results
442 				if (missingKeyBag.getBindingKey() != null && missingKeyBag.getBindingKey().size() > 0)
443 					result.getKeyBag().add(missingKeyBag);
444 				
445 				KeyBag resultsKeyBag = new KeyBag();
446 				BindingDetail bindingDetail = new BindingDetail();
447 	
448 				// Set the currentIndex to 0 or the value of the chunkData
449 				int currentIndex = 0;
450 				if (chunkData != null)
451 					currentIndex = chunkData;
452 	
453 				int returnedRowCount = 0;
454 				while(currentIndex < existingList.size()) {
455 	
456 					org.apache.juddi.model.BindingTemplate modelBindingTemplate = existingList.get(currentIndex);
457 						
458 					if (startPointDate.after(modelBindingTemplate.getModifiedIncludingChildren())) {
459 						currentIndex++;
460 						continue;
461 					}
462 					
463 					if (endPointDate.before(modelBindingTemplate.getModifiedIncludingChildren())) {
464 						currentIndex++;
465 						continue;
466 					}
467 					
468 					if (modelSubscription.isBrief()) {
469 						resultsKeyBag.getBindingKey().add(modelBindingTemplate.getEntityKey());
470 					}
471 					else {
472 						org.uddi.api_v3.BindingTemplate apiBindingTemplate = new org.uddi.api_v3.BindingTemplate();
473 						MappingModelToApi.mapBindingTemplate(modelBindingTemplate, apiBindingTemplate);
474 						bindingDetail.getBindingTemplate().add(apiBindingTemplate);
475 						
476 						returnedRowCount++;
477 					}
478 	
479 					// If the returned rows equals the max allowed, we can end the loop.
480 					if (modelSubscription.getMaxEntities() != null) {
481 						if (returnedRowCount == modelSubscription.getMaxEntities())
482 							break;
483 					}
484 	
485 					currentIndex++;
486 				}
487 				
488 				// If the loop was broken prematurely (max row count hit) we set the chunk data to the next index to start with.
489 				// A non-null value of chunk data will cause a chunk token to be generated. 
490 				if (currentIndex < (existingList.size() - 1))
491 					chunkData = currentIndex + 1;
492 				else
493 					chunkData = null;
494 				
495 				if (modelSubscription.isBrief())
496 					result.getKeyBag().add(resultsKeyBag);
497 				else
498 					result.setBindingDetail(bindingDetail);
499 				
500 				
501 			}
502 			if (subscriptionFilter.getGetBusinessDetail() != null) {
503 				GetBusinessDetail getDetail = subscriptionFilter.getGetBusinessDetail();
504 	
505 				// Running through the key list here to determine the deleted keys and store the existing entities.
506 				KeyBag missingKeyBag = new KeyBag();
507 				missingKeyBag.setDeleted(true);
508 				List<org.apache.juddi.model.BusinessEntity> existingList = new ArrayList<org.apache.juddi.model.BusinessEntity>(0);
509 				for (String key : getDetail.getBusinessKey()) {
510 					org.apache.juddi.model.BusinessEntity modelBusinessEntity = em.find(org.apache.juddi.model.BusinessEntity.class, key);
511 					if (modelBusinessEntity != null)
512 						existingList.add(modelBusinessEntity);
513 					else
514 						missingKeyBag.getBusinessKey().add(key);
515 				}
516 				// Store deleted keys in the results
517 				if (missingKeyBag.getBusinessKey() != null && missingKeyBag.getBusinessKey().size() > 0)
518 					result.getKeyBag().add(missingKeyBag);
519 				
520 				KeyBag resultsKeyBag = new KeyBag();
521 				BusinessDetail businessDetail = new BusinessDetail();
522 	
523 				// Set the currentIndex to 0 or the value of the chunkData
524 				int currentIndex = 0;
525 				if (chunkData != null)
526 					currentIndex = chunkData;
527 				
528 				int returnedRowCount = 0;
529 				while(currentIndex < existingList.size()) {
530 	
531 					org.apache.juddi.model.BusinessEntity modelBusinessEntity = existingList.get(currentIndex);
532 	
533 					if (startPointDate.after(modelBusinessEntity.getModifiedIncludingChildren())) {
534 						currentIndex++;
535 						continue;
536 					}
537 					
538 					if (endPointDate.before(modelBusinessEntity.getModifiedIncludingChildren())) {
539 						currentIndex++;
540 						continue;
541 					}
542 					
543 					if (modelSubscription.isBrief()) {
544 						resultsKeyBag.getBusinessKey().add(modelBusinessEntity.getEntityKey());
545 					}
546 					else {
547 						org.uddi.api_v3.BusinessEntity apiBusinessEntity = new org.uddi.api_v3.BusinessEntity();
548 						MappingModelToApi.mapBusinessEntity(modelBusinessEntity, apiBusinessEntity);
549 						businessDetail.getBusinessEntity().add(apiBusinessEntity);
550 						
551 						returnedRowCount++;
552 					}
553 	
554 					// If the returned rows equals the max allowed, we can end the loop.
555 					if (modelSubscription.getMaxEntities() != null) {
556 						if (returnedRowCount == modelSubscription.getMaxEntities())
557 							break;
558 					}
559 	
560 					currentIndex++;
561 				}
562 				
563 				// If the loop was broken prematurely (max row count hit) we set the chunk data to the next index to start with.
564 				// A non-null value of chunk data will cause a chunk token to be generated. 
565 				if (currentIndex < (existingList.size() - 1))
566 					chunkData = currentIndex + 1;
567 				else
568 					chunkData = null;
569 				
570 				if (modelSubscription.isBrief())
571 					result.getKeyBag().add(resultsKeyBag);
572 				else
573 					result.setBusinessDetail(businessDetail);
574 				
575 			}
576 			if (subscriptionFilter.getGetServiceDetail() != null) {
577 				GetServiceDetail getDetail = subscriptionFilter.getGetServiceDetail();
578 	
579 				// Running through the key list here to determine the deleted keys and store the existing entities.
580 				KeyBag missingKeyBag = new KeyBag();
581 				missingKeyBag.setDeleted(true);
582 				List<org.apache.juddi.model.BusinessService> existingList = new ArrayList<org.apache.juddi.model.BusinessService>(0);
583 				for (String key : getDetail.getServiceKey()) {
584 					org.apache.juddi.model.BusinessService modelBusinessService = em.find(org.apache.juddi.model.BusinessService.class, key);
585 					if (modelBusinessService != null)
586 						existingList.add(modelBusinessService);
587 					else
588 						missingKeyBag.getBusinessKey().add(key);
589 				}
590 				// Store deleted keys in the results
591 				if (missingKeyBag.getServiceKey() != null && missingKeyBag.getServiceKey().size() > 0)
592 					result.getKeyBag().add(missingKeyBag);
593 	
594 				KeyBag resultsKeyBag = new KeyBag();
595 				ServiceDetail serviceDetail = new ServiceDetail();
596 				
597 				// Set the currentIndex to 0 or the value of the chunkData
598 				int currentIndex = 0;
599 				if (chunkData != null)
600 					currentIndex = chunkData;
601 				
602 				int returnedRowCount = 0;
603 				while(currentIndex < existingList.size()) {
604 					
605 					org.apache.juddi.model.BusinessService modelBusinessService = existingList.get(currentIndex);
606 						
607 					if (startPointDate.after(modelBusinessService.getModifiedIncludingChildren())) {
608 						currentIndex++;
609 						continue;
610 					}
611 					
612 					if (endPointDate.before(modelBusinessService.getModifiedIncludingChildren())) {
613 						currentIndex++;
614 						continue;
615 					}
616 					
617 					if (modelSubscription.isBrief()) {
618 						resultsKeyBag.getServiceKey().add(modelBusinessService.getEntityKey());
619 					}
620 					else {
621 						org.uddi.api_v3.BusinessService apiBusinessService = new org.uddi.api_v3.BusinessService();
622 						MappingModelToApi.mapBusinessService(modelBusinessService, apiBusinessService);
623 						serviceDetail.getBusinessService().add(apiBusinessService);
624 						
625 						returnedRowCount++;
626 					}
627 	
628 					// If the returned rows equals the max allowed, we can end the loop.
629 					if (modelSubscription.getMaxEntities() != null) {
630 						if (returnedRowCount == modelSubscription.getMaxEntities())
631 							break;
632 					}
633 	
634 					currentIndex++;
635 				}
636 				
637 				// If the loop was broken prematurely (max row count hit) we set the chunk data to the next index to start with.
638 				// A non-null value of chunk data will cause a chunk token to be generated. 
639 				if (currentIndex < (existingList.size() - 1))
640 					chunkData = currentIndex + 1;
641 				else
642 					chunkData = null;
643 				
644 				if (modelSubscription.isBrief())
645 					result.getKeyBag().add(resultsKeyBag);
646 				else
647 					result.setServiceDetail(serviceDetail);
648 				
649 			}
650 			if (subscriptionFilter.getGetTModelDetail() != null) {
651 				GetTModelDetail getDetail = subscriptionFilter.getGetTModelDetail();
652 	
653 				// Running through the key list here to determine the deleted keys and store the existing entities.
654 				KeyBag missingKeyBag = new KeyBag();
655 				missingKeyBag.setDeleted(true);
656 				List<org.apache.juddi.model.Tmodel> existingList = new ArrayList<org.apache.juddi.model.Tmodel>(0);
657 				for (String key : getDetail.getTModelKey()) {
658 					org.apache.juddi.model.Tmodel modelTModel = em.find(org.apache.juddi.model.Tmodel.class, key);
659 					if (modelTModel != null)
660 						existingList.add(modelTModel);
661 					else
662 						missingKeyBag.getTModelKey().add(key);
663 				}
664 				// Store deleted keys in the results
665 				if (missingKeyBag.getTModelKey() != null && missingKeyBag.getTModelKey().size() > 0)
666 					result.getKeyBag().add(missingKeyBag);
667 				
668 				KeyBag resultsKeyBag = new KeyBag();
669 				TModelDetail tmodelDetail = new TModelDetail();
670 	
671 				// Set the currentIndex to 0 or the value of the chunkData
672 				int currentIndex = 0;
673 				if (chunkData != null)
674 					currentIndex = chunkData;
675 				
676 				int returnedRowCount = 0;
677 				while(currentIndex < existingList.size()) {
678 	
679 					org.apache.juddi.model.Tmodel modelTModel = existingList.get(currentIndex);
680 						
681 					if (startPointDate.after(modelTModel.getModifiedIncludingChildren())) {
682 						currentIndex++;
683 						continue;
684 					}
685 					
686 					if (endPointDate.before(modelTModel.getModifiedIncludingChildren())) {
687 						currentIndex++;
688 						continue;
689 					}
690 					
691 					if (modelSubscription.isBrief()) {
692 						resultsKeyBag.getTModelKey().add(modelTModel.getEntityKey());
693 					}
694 					else {
695 						org.uddi.api_v3.TModel apiTModel = new org.uddi.api_v3.TModel();
696 						MappingModelToApi.mapTModel(modelTModel, apiTModel);
697 						tmodelDetail.getTModel().add(apiTModel);
698 						
699 						returnedRowCount++;
700 					}
701 	
702 					// If the returned rows equals the max allowed, we can end the loop.
703 					if (modelSubscription.getMaxEntities() != null) {
704 						if (returnedRowCount == modelSubscription.getMaxEntities())
705 							break;
706 					}
707 	
708 					currentIndex++;
709 				}
710 				
711 				// If the loop was broken prematurely (max row count hit) we set the chunk data to the next index to start with.
712 				// A non-null value of chunk data will cause a chunk token to be generated. 
713 				if (currentIndex < (existingList.size() - 1))
714 					chunkData = currentIndex + 1;
715 				else
716 					chunkData = null;
717 				
718 				if (modelSubscription.isBrief())
719 					result.getKeyBag().add(resultsKeyBag);
720 				else
721 					result.setTModelDetail(tmodelDetail);
722 				
723 			}
724 			if (subscriptionFilter.getGetAssertionStatusReport() != null) {
725 				// The coverage period doesn't apply here (basically because publisher assertions don't keep operational info).
726 				// TODO, JUDDI-873 edit they do now, rewrite this query
727 				GetAssertionStatusReport getAssertionStatusReport = subscriptionFilter.getGetAssertionStatusReport();
728                                 List<?> businessKeysFound = null;
729                                 businessKeysFound = FindBusinessByPublisherQuery.select(em, null, publisher, businessKeysFound);
730 		
731                                 AssertionStatusReport assertionStatusReport  = new AssertionStatusReport();
732                                 
733 				List<org.apache.juddi.model.PublisherAssertion> pubAssertionList = org.apache.juddi.query.FindPublisherAssertionByBusinessQuery.select(em, businessKeysFound, getAssertionStatusReport.getCompletionStatus());
734                                 //if (pubAssertionList==null)
735                                 //    return result;
736                                 for (org.apache.juddi.model.PublisherAssertion modelPubAssertion : pubAssertionList) {
737 
738                                         if (startPointDate.after(modelPubAssertion.getModified())) {
739                                                 continue;
740                                         }
741 
742                                         if (endPointDate.before(modelPubAssertion.getModified())) {
743                                                 continue;
744                                         }
745                                         org.uddi.api_v3.AssertionStatusItem apiAssertionStatusItem = new org.uddi.api_v3.AssertionStatusItem();
746 
747                                         MappingModelToApi.mapAssertionStatusItem(modelPubAssertion, apiAssertionStatusItem, businessKeysFound);
748 
749                                         assertionStatusReport.getAssertionStatusItem().add(apiAssertionStatusItem);
750                                 }
751 
752 				
753 				result.setAssertionStatusReport(assertionStatusReport);
754 			}
755 			
756 			// If chunkData contains non-null data, a new token must be created and the token returned in the results
757 			if (chunkData != null) {
758 				String chunkToken = CHUNK_TOKEN_PREFIX + UUID.randomUUID();
759 				SubscriptionChunkToken newChunkToken = new SubscriptionChunkToken(chunkToken);
760 				newChunkToken.setSubscriptionKey(body.getSubscriptionKey());
761 				newChunkToken.setStartPoint(startPointDate);
762 				newChunkToken.setEndPoint(endPointDate);
763 				newChunkToken.setData(chunkData);
764 	
765 				int chunkExpirationMinutes = DEFAULT_CHUNKEXPIRATION_MINUTES;
766 				try { 
767 					chunkExpirationMinutes = AppConfig.getConfiguration().getInt(Property.JUDDI_SUBSCRIPTION_CHUNKEXPIRATION_MINUTES); 
768 				}
769 				catch(ConfigurationException ce) { 
770 					throw new FatalErrorException(new ErrorMessage("errors.configuration.Retrieval"));
771 				}
772 				newChunkToken.setExpiresAfter(new Date(System.currentTimeMillis() + ((long)chunkExpirationMinutes * 60L * 1000L)));
773 				
774 				em.persist(newChunkToken);
775 				
776 				result.setChunkToken(chunkToken);
777 			}
778 			
779 	        tx.commit();
780                 long procTime = System.currentTimeMillis() - startTime;
781                 serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONRESULTS, 
782                         QueryStatus.SUCCESS, procTime);
783 
784 	        return result;
785         } catch (DispositionReportFaultMessage drfm) {
786             long procTime = System.currentTimeMillis() - startTime;
787             serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONRESULTS, 
788                     QueryStatus.FAILED, procTime);                      
789             throw drfm;                                                                                                 
790         } finally {
791 			if (tx.isActive()) {
792 				tx.rollback();
793 			}
794 			em.close();
795 		}
796 	}
797 
798 	@SuppressWarnings("unchecked")
799 	public List<Subscription> getSubscriptions(String authInfo)
800 			throws DispositionReportFaultMessage {
801 	        long startTime = System.currentTimeMillis();
802 		EntityManager em = PersistenceManager.getEntityManager();
803 		EntityTransaction tx = em.getTransaction();
804                 try {
805                         tx.begin();
806 	
807 			UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);
808 			
809 			List<Subscription> result = new ArrayList<Subscription>(0);
810 			
811 			List<org.apache.juddi.model.Subscription> modelSubscriptionList = (List<org.apache.juddi.model.Subscription>)FindSubscriptionByPublisherQuery.select(em, publisher.getAuthorizedName());
812 			if (modelSubscriptionList != null && modelSubscriptionList.size() > 0) {
813 				for (org.apache.juddi.model.Subscription modelSubscription : modelSubscriptionList) {
814 					
815 					Subscription apiSubscription = new Subscription();
816 					
817 					MappingModelToApi.mapSubscription(modelSubscription, apiSubscription);
818 					
819 					result.add(apiSubscription);
820 				}
821 			}
822 	        
823 	        tx.commit();
824                 long procTime = System.currentTimeMillis() - startTime;
825                 serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONS, 
826                         QueryStatus.SUCCESS, procTime);
827 
828 		return result;
829         } catch (DispositionReportFaultMessage drfm) {
830                     long procTime = System.currentTimeMillis() - startTime;
831                     serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONS, 
832                             QueryStatus.FAILED, procTime);                      
833                     throw drfm;                                                                                                 		
834         } finally {
835 			if (tx.isActive()) {
836 				tx.rollback();
837 			}
838 			em.close();
839 		}
840 	}
841 
842 
843 	/* 
844 	 * @see org.uddi.v3_service.UDDISubscriptionPortType#saveSubscription(java.lang.String, javax.xml.ws.Holder)
845 	 * 
846 	 * Notes: The matching keys are saved on a new subscription (or renewed subscription) for the find_* filters only.  With the other filter 
847 	 * types, taking a snapshot of the matches doesn't make sense.
848 	 * 
849 	 */
850 	public void saveSubscription(String authInfo,
851 			Holder<List<Subscription>> subscription)
852 			throws DispositionReportFaultMessage {
853 	        long startTime = System.currentTimeMillis();
854 
855 		EntityManager em = PersistenceManager.getEntityManager();
856 		EntityTransaction tx = em.getTransaction();
857 		try {
858 			tx.begin();
859 	
860 			UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);
861 			publisher.populateKeyGeneratorKeys(em);
862 			new ValidateSubscription(publisher).validateSubscriptions(em, subscription.value, publisher);
863 			
864 			List<org.uddi.sub_v3.Subscription> apiSubscriptionList = subscription.value;
865 			for (org.uddi.sub_v3.Subscription apiSubscription : apiSubscriptionList) {
866 				
867 				org.apache.juddi.model.Subscription modelSubscription = new org.apache.juddi.model.Subscription();
868 				
869 				Object existing = em.find(org.apache.juddi.model.Subscription.class, apiSubscription.getSubscriptionKey());
870 				if (existing != null) {
871 					org.apache.juddi.model.Subscription existingEntity = (org.apache.juddi.model.Subscription) existing;
872 					doRenewal(existingEntity, apiSubscription);
873 					//carrying over the created and last notified dates if this is a renewal.
874 					modelSubscription.setCreateDate(existingEntity.getCreateDate());
875 					modelSubscription.setLastNotified(existingEntity.getLastNotified());
876 					em.remove(existing);
877 				} else {
878 					modelSubscription.setCreateDate(new Date());
879 				}
880                               
881 				doSubscriptionExpirationDate(apiSubscription);
882 				
883 				MappingApiToModel.mapSubscription(apiSubscription, modelSubscription);
884 				
885 				modelSubscription.setAuthorizedName(publisher.getAuthorizedName());
886 				
887 				// Add the matching keys to the match collection
888 				List<?> keys = getSubscriptionMatches(apiSubscription.getSubscriptionFilter(), em);
889 				if (keys != null && keys.size() > 0) {
890 					for (Object key : keys) {
891 						SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);
892 						modelSubscription.getSubscriptionMatches().add(subMatch);
893 					}
894 				}
895 				
896 				em.persist(modelSubscription);
897 			}
898 	
899 			tx.commit();
900 	                long procTime = System.currentTimeMillis() - startTime;
901 	                serviceCounter.update(SubscriptionQuery.SAVE_SUBSCRIPTION, 
902 	                        QueryStatus.SUCCESS, procTime);
903 	        } catch (DispositionReportFaultMessage drfm) {
904                     long procTime = System.currentTimeMillis() - startTime;
905                     serviceCounter.update(SubscriptionQuery.SAVE_SUBSCRIPTION, 
906                             QueryStatus.FAILED, procTime);                      
907                     throw drfm;                                                                                                                 
908 		} finally {
909 			if (tx.isActive()) {
910 				tx.rollback();
911 			}
912 			em.close();
913 		}
914 	}
915 
916 	/**
917 	 * Will perform the necessary logic for when a subscription is renewed (evidenced by a subscription with the same key in existence).  
918 	 * In general, the appropriate data is copied from the stored subscription to the renewal subscription request.
919 	 * 
920 	 * @param existingSubscription - existing stored subscription
921 	 * @param apiSubscription - renewal subscription request
922 	 * @throws DispositionReportFaultMessage 
923 	 */
924 	protected void doRenewal(org.apache.juddi.model.Subscription existingSubscription, org.uddi.sub_v3.Subscription apiSubscription) throws DispositionReportFaultMessage {
925 		if (apiSubscription.getSubscriptionFilter() == null) {
926 			String rawFilter = existingSubscription.getSubscriptionFilter();
927 			try {
928 				SubscriptionFilter existingFilter = (SubscriptionFilter)JAXBMarshaller.unmarshallFromString(rawFilter, "org.uddi.sub_v3");
929 				apiSubscription.setSubscriptionFilter(existingFilter);
930 			} 
931 			catch (JAXBException e) {
932 				logger.error("JAXB Exception while marshalling subscription filter", e);
933 				throw new FatalErrorException(new ErrorMessage("errors.Unspecified"));
934 			} 
935 		}
936 		
937 	}
938 	
939 	/**
940 	 * Will add the expiration date to the provided subscription request.  Date is earlier of user provided date and the system default
941 	 * 
942 	 * @param apiSubscription
943 	 * @throws DispositionReportFaultMessage
944 	 */
945 	protected void doSubscriptionExpirationDate(org.uddi.sub_v3.Subscription apiSubscription) throws DispositionReportFaultMessage {
946 
947 		int subscriptionExpirationDays = DEFAULT_SUBSCRIPTIONEXPIRATION_DAYS;
948 		try { 
949 			subscriptionExpirationDays = AppConfig.getConfiguration().getInt(Property.JUDDI_SUBSCRIPTION_EXPIRATION_DAYS); 
950 		}
951 		catch(ConfigurationException ce) { 
952 			throw new FatalErrorException(new ErrorMessage("errors.configuration.Retrieval"));
953 		}
954 
955 		GregorianCalendar expirationDate = new GregorianCalendar();
956 		expirationDate.add(GregorianCalendar.DAY_OF_MONTH, subscriptionExpirationDays);
957 		
958 		// The expiration date is the earlier of the provided date and that specified by the parameter.
959 		if (apiSubscription.getExpiresAfter() != null) {
960 			GregorianCalendar userExpiration = apiSubscription.getExpiresAfter().toGregorianCalendar();
961 			if (userExpiration.getTimeInMillis() < expirationDate.getTimeInMillis())
962 				expirationDate.setTimeInMillis(userExpiration.getTimeInMillis());
963 		}
964 
965 		try { 
966 			DatatypeFactory df = DatatypeFactory.newInstance();
967 			apiSubscription.setExpiresAfter(df.newXMLGregorianCalendar(expirationDate));
968 		}
969 		catch(DatatypeConfigurationException ce) { 
970 			throw new FatalErrorException(new ErrorMessage("errors.Unspecified"));
971 		}
972 		
973 	}
974 
975 	/**
976 	 * Will take a snapshot of the keys that match the subscription filter return them.  Currently, keys are only returned for the find_*
977 	 * filters.  It seems redundant to return the keys in the get_*Detail filters.
978 	 * 
979 	 * @param subscriptionFilter
980 	 * @param em
981 	 * @return a list of subscription matches
982 	 * @throws DispositionReportFaultMessage
983 	 */
984 	protected List<?> getSubscriptionMatches(SubscriptionFilter subscriptionFilter, EntityManager em) 
985 			 throws DispositionReportFaultMessage {
986 		
987 		
988 		List<?> keys = null;
989 		if (subscriptionFilter.getFindBinding() != null) {
990 			org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
991 			findQualifiers.mapApiFindQualifiers(subscriptionFilter.getFindBinding().getFindQualifiers());
992 			keys = InquiryHelper.findBinding(subscriptionFilter.getFindBinding(), findQualifiers, em);
993 		}
994 		if (subscriptionFilter.getFindBusiness() != null) {
995 			org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
996 			findQualifiers.mapApiFindQualifiers(subscriptionFilter.getFindBusiness().getFindQualifiers());
997 			keys = InquiryHelper.findBusiness(subscriptionFilter.getFindBusiness(), findQualifiers, em);
998 		}
999 		if (subscriptionFilter.getFindService() != null) {
1000 			org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
1001 			findQualifiers.mapApiFindQualifiers(subscriptionFilter.getFindService().getFindQualifiers());
1002 			keys = InquiryHelper.findService(subscriptionFilter.getFindService(), findQualifiers, em);
1003 		}
1004 		if (subscriptionFilter.getFindTModel() != null) {
1005 			org.apache.juddi.query.util.FindQualifiers findQualifiers = new org.apache.juddi.query.util.FindQualifiers();
1006 			findQualifiers.mapApiFindQualifiers(subscriptionFilter.getFindTModel().getFindQualifiers());
1007 			keys = InquiryHelper.findTModel(subscriptionFilter.getFindTModel(), findQualifiers, em);
1008 		}
1009 		if (subscriptionFilter.getFindRelatedBusinesses() != null) {
1010 			// TODO: should we bother taking a snapshot of these?
1011 		}
1012 		if (subscriptionFilter.getGetBindingDetail() != null) {
1013 			//keys = subscriptionFilter.getGetBindingDetail().getBindingKey();
1014 			// Nothing needs to be done
1015 		}
1016 		if (subscriptionFilter.getGetBusinessDetail() != null) {
1017 			//keys = subscriptionFilter.getGetBusinessDetail().getBusinessKey();
1018 			// Nothing needs to be done
1019 		}
1020 		if (subscriptionFilter.getGetServiceDetail() != null) {
1021 			//keys = subscriptionFilter.getGetServiceDetail().getServiceKey();
1022 			// Nothing needs to be done
1023 		}
1024 		if (subscriptionFilter.getGetTModelDetail() != null) {
1025 			//keys = subscriptionFilter.getGetTModelDetail().getTModelKey();
1026 			// Nothing needs to be done
1027 		}
1028 		if (subscriptionFilter.getGetAssertionStatusReport() != null) {
1029 			// Nothing needs to be done
1030 		}
1031 		return keys;
1032 		
1033 	}
1034 	
1035 	private List<String> getMissingKeys(List<?> currentMatchingKeys, List<SubscriptionMatch> subscriptionMatches) {
1036 
1037 		List<String> result = new ArrayList<String>(subscriptionMatches.size());
1038 		for (SubscriptionMatch subMatch : subscriptionMatches)
1039 			result.add(subMatch.getEntityKey());
1040 		
1041 		result.removeAll(currentMatchingKeys);
1042 		
1043 		return result;
1044 	}
1045 	
1046 }