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 at7 * 8 * http://www.apache.org/licenses/LICENSE-2.09 * 10 * Unless required by applicable law or agreed to in writing, software11 * 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 and14 * limitations under the License.15 *16 */1718package org.apache.juddi.api.impl;
1920import java.util.ArrayList;
21import java.util.Date;
22import java.util.GregorianCalendar;
23import java.util.List;
24import java.util.UUID;
2526import javax.jws.WebService;
27import javax.persistence.EntityManager;
28import javax.persistence.EntityTransaction;
29import javax.xml.bind.JAXBException;
30import javax.xml.datatype.DatatypeConfigurationException;
31import javax.xml.datatype.DatatypeFactory;
32import javax.xml.ws.Holder;
3334import org.apache.commons.configuration.ConfigurationException;
35import org.apache.commons.logging.Log;
36import org.apache.commons.logging.LogFactory;
37import org.apache.juddi.api.util.QueryStatus;
38import org.apache.juddi.api.util.SubscriptionQuery;
39import org.apache.juddi.config.AppConfig;
40import org.apache.juddi.config.PersistenceManager;
41import org.apache.juddi.config.Property;
42import org.apache.juddi.jaxb.JAXBMarshaller;
43import org.apache.juddi.mapping.MappingApiToModel;
44import org.apache.juddi.mapping.MappingModelToApi;
45import org.apache.juddi.model.SubscriptionChunkToken;
46import org.apache.juddi.model.SubscriptionMatch;
47import org.apache.juddi.model.UddiEntityPublisher;
48import org.apache.juddi.query.FindBusinessByPublisherQuery;
49import org.apache.juddi.query.FindSubscriptionByPublisherQuery;
50import org.apache.juddi.v3.error.ErrorMessage;
51import org.apache.juddi.v3.error.FatalErrorException;
52import org.apache.juddi.v3.error.InvalidValueException;
53import org.apache.juddi.validation.ValidateSubscription;
54import org.uddi.api_v3.AssertionStatusReport;
55import org.uddi.api_v3.BindingDetail;
56import org.uddi.api_v3.BusinessDetail;
57import org.uddi.api_v3.BusinessList;
58import org.uddi.api_v3.FindBinding;
59import org.uddi.api_v3.FindBusiness;
60import org.uddi.api_v3.FindRelatedBusinesses;
61import org.uddi.api_v3.FindService;
62import org.uddi.api_v3.FindTModel;
63import org.uddi.api_v3.GetAssertionStatusReport;
64import org.uddi.api_v3.GetBindingDetail;
65import org.uddi.api_v3.GetBusinessDetail;
66import org.uddi.api_v3.GetServiceDetail;
67import org.uddi.api_v3.GetTModelDetail;
68import org.uddi.api_v3.RelatedBusinessesList;
69import org.uddi.api_v3.ServiceDetail;
70import org.uddi.api_v3.ServiceList;
71import org.uddi.api_v3.TModelDetail;
72import org.uddi.api_v3.TModelList;
73import org.uddi.sub_v3.DeleteSubscription;
74import org.uddi.sub_v3.GetSubscriptionResults;
75import org.uddi.sub_v3.KeyBag;
76import org.uddi.sub_v3.Subscription;
77import org.uddi.sub_v3.SubscriptionFilter;
78import org.uddi.sub_v3.SubscriptionResultsList;
79import org.uddi.v3_service.DispositionReportFaultMessage;
80import org.uddi.v3_service.UDDISubscriptionPortType;
8182/**83 * This is jUDDI's implementation of the UDDIv3 Subscription API84 */85 @WebService(serviceName="UDDISubscriptionService",
86 endpointInterface="org.uddi.v3_service.UDDISubscriptionPortType",
87 targetNamespace = "urn:uddi-org:api_v3_portType")
88publicclassUDDISubscriptionImplextendsAuthenticatedServiceimplements UDDISubscriptionPortType {
8990privatestatic Log logger = LogFactory.getLog(UDDISubscriptionImpl.class);
9192publicstaticfinalint DEFAULT_SUBSCRIPTIONEXPIRATION_DAYS = 30;
93publicstaticfinalint DEFAULT_CHUNKEXPIRATION_MINUTES = 5;
9495publicstaticfinal String CHUNK_TOKEN_PREFIX = "chunktoken:";
9697privateUDDIServiceCounter serviceCounter;
9899publicUDDISubscriptionImpl() {
100super();
101 serviceCounter = ServiceCounterLifecycleResource.getServiceCounter(this.getClass());
102 }
103104publicvoid deleteSubscription(DeleteSubscription body)
105throws DispositionReportFaultMessage {
106long startTime = System.currentTimeMillis();
107108 EntityManager em = PersistenceManager.getEntityManager();
109 EntityTransaction tx = em.getTransaction();
110try {
111 tx.begin();
112113 UddiEntityPublisher publisher = this.getEntityPublisher(em, body.getAuthInfo());
114newValidateSubscription(publisher).validateDeleteSubscription(em, body);
115116 List<String> subscriptionKeyList = body.getSubscriptionKey();
117for (String subscriptionKey : subscriptionKeyList) {
118 Object obj = em.find(org.apache.juddi.model.Subscription.class, subscriptionKey);
119 em.remove(obj);
120 }
121122 tx.commit();
123long procTime = System.currentTimeMillis() - startTime;
124 serviceCounter.update(SubscriptionQuery.DELETE_SUBSCRIPTION,
125 QueryStatus.SUCCESS, procTime);
126 } catch (DispositionReportFaultMessage drfm) {
127long procTime = System.currentTimeMillis() - startTime;
128 serviceCounter.update(SubscriptionQuery.DELETE_SUBSCRIPTION,
129 QueryStatus.FAILED, procTime);
130throw drfm;
131 } finally {
132if (tx.isActive()) {
133 tx.rollback();
134 }
135 em.close();
136 }
137 }
138139public SubscriptionResultsList getSubscriptionResults(GetSubscriptionResults body) throws DispositionReportFaultMessage {
140return 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 had146 * a set of entities in mind when the subscription was saved and the snapshot should remain just that - a snapshot of the entities at the147 * time of the subscription save. The result of this policy is that if an entity is deleted, that deleted result will appear in the keyBag148 * 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. The151 * notificationSubscriber will pass in the publisher and this method will work in unauthenticated mode.152 */153 @SuppressWarnings("unchecked")
154public SubscriptionResultsList getSubscriptionResults(GetSubscriptionResults body, UddiEntityPublisher publisher) throws DispositionReportFaultMessage {
155long startTime = System.currentTimeMillis();
156157 EntityManager em = PersistenceManager.getEntityManager();
158 EntityTransaction tx = em.getTransaction();
159try {
160 tx.begin();
161162if (publisher==null) {
163 publisher = this.getEntityPublisher(em, body.getAuthInfo());
164newValidateSubscription(publisher).validateGetSubscriptionResults(em, body);
165 }
166167 org.apache.juddi.model.Subscription modelSubscription = em.find(org.apache.juddi.model.Subscription.class, body.getSubscriptionKey());
168 SubscriptionFilter subscriptionFilter = null;
169try {
170 subscriptionFilter = (SubscriptionFilter)JAXBMarshaller.unmarshallFromString(modelSubscription.getSubscriptionFilter(), JAXBMarshaller.PACKAGE_SUBSCRIPTION);
171 }
172catch (JAXBException e) {
173 logger.error("JAXB Exception while unmarshalling subscription filter", e);
174thrownewFatalErrorException(newErrorMessage("errors.Unspecified"));
175 }
176if (logger.isDebugEnabled()) logger.debug("filter=" + modelSubscription.getSubscriptionFilter());
177178 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());
182183// The subscription structure is required output for the results184 org.uddi.sub_v3.Subscription apiSubscription = new org.uddi.sub_v3.Subscription();
185 MappingModelToApi.mapSubscription(modelSubscription, apiSubscription);
186 result.setSubscription(apiSubscription);
187188 Date startPointDate = new Date(body.getCoveragePeriod().getStartPoint().toGregorianCalendar().getTimeInMillis());
189 Date endPointDate = new Date(body.getCoveragePeriod().getEndPoint().toGregorianCalendar().getTimeInMillis());
190191 Integer chunkData = null;
192if (body.getChunkToken() != null && body.getChunkToken().length() > 0) {
193 SubscriptionChunkToken chunkToken = em.find(SubscriptionChunkToken.class, body.getChunkToken());
194195if (chunkToken == null)
196thrownewInvalidValueException(newErrorMessage("errors.getsubscriptionresult.InvalidChunkToken", body.getChunkToken()));
197if (!chunkToken.getSubscriptionKey().equals(body.getSubscriptionKey()))
198thrownewInvalidValueException(newErrorMessage("errors.getsubscriptionresult.NonMatchingChunkToken", body.getChunkToken()));
199if (chunkToken.getStartPoint() != null && chunkToken.getStartPoint().getTime() != startPointDate.getTime())
200thrownewInvalidValueException(newErrorMessage("errors.getsubscriptionresult.NonMatchingChunkToken", body.getChunkToken()));
201if (chunkToken.getEndPoint() != null && chunkToken.getEndPoint().getTime() != endPointDate.getTime())
202thrownewInvalidValueException(newErrorMessage("errors.getsubscriptionresult.NonMatchingChunkToken", body.getChunkToken()));
203if (chunkToken.getExpiresAfter().before(new Date()))
204thrownewInvalidValueException(newErrorMessage("errors.getsubscriptionresult.ExpiredChunkToken", body.getChunkToken()));
205206 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 }
210211212if (subscriptionFilter.getFindBinding() != null) {
213//Get the current matching keys214 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 and216// then added to the result217 List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
218if (missingKeys != null && missingKeys.size() > 0) {
219 KeyBag missingKeyBag = new KeyBag();
220 missingKeyBag.setDeleted(true);
221for (String key : missingKeys)
222 missingKeyBag.getBindingKey().add(key);
223224 result.getKeyBag().add(missingKeyBag);
225 }
226227// Re-setting the subscription matches to the new matching key collection228//modelSubscription.getSubscriptionMatches().clear();229//for (Object key : currentMatchingKeys) {230// SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);231// modelSubscription.getSubscriptionMatches().add(subMatch);232//}233234// Now, finding the necessary entities, within the coverage period limits235if (modelSubscription.isBrief()) {
236 KeyBag resultsKeyBag = new KeyBag();
237for (String key : (List<String>)currentMatchingKeys)
238 resultsKeyBag.getBindingKey().add(key);
239240 result.getKeyBag().add(resultsKeyBag);
241 }
242else {
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());
246247// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default. User settings for248// 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 chunkData252 Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
253254 BindingDetail bindingDetail = InquiryHelper.getBindingDetailFromKeys(fb, findQualifiers, em, currentMatchingKeys,
255 startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
256257// Upon exiting above function, if more results are to be had, the subscriptionStartIndex will contain the latest value (or null258// if no more results)259 chunkData = subscriptionStartIndex.value;
260261 result.setBindingDetail(bindingDetail);
262 }
263 }
264if (subscriptionFilter.getFindBusiness() != null) {
265//Get the current matching keys266 List<?> currentMatchingKeys = getSubscriptionMatches(subscriptionFilter, em);
267268 List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
269if (missingKeys != null && missingKeys.size() > 0) {
270 KeyBag missingKeyBag = new KeyBag();
271 missingKeyBag.setDeleted(true);
272for (String key : missingKeys)
273 missingKeyBag.getBusinessKey().add(key);
274275 result.getKeyBag().add(missingKeyBag);
276 }
277278// Re-setting the subscription matches to the new matching key collection279//modelSubscription.getSubscriptionMatches().clear();280//for (Object key : currentMatchingKeys) {281// SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);282// modelSubscription.getSubscriptionMatches().add(subMatch);283//}284285// Now, finding the necessary entities, within the coverage period limits286if (modelSubscription.isBrief()) {
287 KeyBag resultsKeyBag = new KeyBag();
288for (String key : (List<String>)currentMatchingKeys)
289 resultsKeyBag.getBusinessKey().add(key);
290291 result.getKeyBag().add(resultsKeyBag);
292 }
293else {
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());
297298// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default. User settings for299// 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 chunkData303 Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
304305 BusinessList businessList = InquiryHelper.getBusinessListFromKeys(fb, findQualifiers, em, currentMatchingKeys,
306 startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
307308// Upon exiting above function, if more results are to be had, the subscriptionStartIndex will contain the latest value (or null309// if no more results)310 chunkData = subscriptionStartIndex.value;
311312 result.setBusinessList(businessList);
313 }
314 }
315if (subscriptionFilter.getFindService() != null) {
316//Get the current matching keys317 List<?> currentMatchingKeys = getSubscriptionMatches(subscriptionFilter, em);
318if (logger.isDebugEnabled()) logger.debug("current matching keys=" + currentMatchingKeys);
319 List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
320if (missingKeys != null && missingKeys.size() > 0) {
321 KeyBag missingKeyBag = new KeyBag();
322 missingKeyBag.setDeleted(true);
323for (String key : missingKeys)
324 missingKeyBag.getServiceKey().add(key);
325326 result.getKeyBag().add(missingKeyBag);
327 }
328329// Re-setting the subscription matches to the new matching key collection330//modelSubscription.getSubscriptionMatches().clear();331//for (Object key : currentMatchingKeys) {332// SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);333// modelSubscription.getSubscriptionMatches().add(subMatch);334//}335336// Now, finding the necessary entities, within the coverage period limits337if (modelSubscription.isBrief()) {
338 KeyBag resultsKeyBag = new KeyBag();
339for (String key : (List<String>)currentMatchingKeys)
340 resultsKeyBag.getServiceKey().add(key);
341342 result.getKeyBag().add(resultsKeyBag);
343 }
344else {
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());
348349// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default. User settings for350// 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 chunkData354 Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
355356 ServiceList serviceList = InquiryHelper.getServiceListFromKeys(fs, findQualifiers, em, currentMatchingKeys,
357 startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
358if (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 null362// if no more results)363 chunkData = subscriptionStartIndex.value;
364365 result.setServiceList(serviceList);
366 }
367 }
368if (subscriptionFilter.getFindTModel() != null) {
369//Get the current matching keys370 List<?> currentMatchingKeys = getSubscriptionMatches(subscriptionFilter, em);
371372 List<String> missingKeys = getMissingKeys(currentMatchingKeys, modelSubscription.getSubscriptionMatches());
373if (missingKeys != null && missingKeys.size() > 0) {
374 KeyBag missingKeyBag = new KeyBag();
375 missingKeyBag.setDeleted(true);
376for (String key : missingKeys)
377 missingKeyBag.getTModelKey().add(key);
378379 result.getKeyBag().add(missingKeyBag);
380 }
381382// Re-setting the subscription matches to the new matching key collection383//modelSubscription.getSubscriptionMatches().clear();384//for (Object key : currentMatchingKeys) {385// SubscriptionMatch subMatch = new SubscriptionMatch(modelSubscription, (String)key);386// modelSubscription.getSubscriptionMatches().add(subMatch);387//}388389// Now, finding the necessary entities, within the coverage period limits390if (modelSubscription.isBrief()) {
391 KeyBag resultsKeyBag = new KeyBag();
392for (String key : (List<String>)currentMatchingKeys)
393 resultsKeyBag.getTModelKey().add(key);
394395 result.getKeyBag().add(resultsKeyBag);
396 }
397else {
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());
401402// To do subscription "chunking", the listHead and maxRows are nulled which will set them to system default. User settings for403// 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 chunkData407 Holder<Integer> subscriptionStartIndex = new Holder<Integer>(chunkData);
408409// If more results are to be had, chunkData will come out with a value and a new token will be generated below. Otherwise, it will410// be null and no token will be generated.411 TModelList tmodelList = InquiryHelper.getTModelListFromKeys(ft, findQualifiers, em, currentMatchingKeys,
412 startPointDate, endPointDate, subscriptionStartIndex, modelSubscription.getMaxEntities());
413414// Upon exiting above function, if more results are to be had, the subscriptionStartIndex will contain the latest value (or null415// if no more results)416 chunkData = subscriptionStartIndex.value;
417418 result.setTModelList(tmodelList);
419 }
420421 }
422if (subscriptionFilter.getFindRelatedBusinesses() != null) {
423 FindRelatedBusinesses findRelatedBusiness = subscriptionFilter.getFindRelatedBusinesses();
424 RelatedBusinessesList relatedBusinessList = InquiryHelper.getRelatedBusinessesList(findRelatedBusiness, em, startPointDate, endPointDate);
425 result.setRelatedBusinessesList(relatedBusinessList);
426 }
427if (subscriptionFilter.getGetBindingDetail() != null) {
428 GetBindingDetail getDetail = subscriptionFilter.getGetBindingDetail();
429430// 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);
434for (String key : getDetail.getBindingKey()) {
435 org.apache.juddi.model.BindingTemplate modelBindingTemplate = em.find(org.apache.juddi.model.BindingTemplate.class, key);
436if (modelBindingTemplate != null)
437 existingList.add(modelBindingTemplate);
438else439 missingKeyBag.getBindingKey().add(key);
440 }
441// Store deleted keys in the results442if (missingKeyBag.getBindingKey() != null && missingKeyBag.getBindingKey().size() > 0)
443 result.getKeyBag().add(missingKeyBag);
444445 KeyBag resultsKeyBag = new KeyBag();
446 BindingDetail bindingDetail = new BindingDetail();
447448// Set the currentIndex to 0 or the value of the chunkData449int currentIndex = 0;
450if (chunkData != null)
451 currentIndex = chunkData;
452453int returnedRowCount = 0;
454while(currentIndex < existingList.size()) {
455456 org.apache.juddi.model.BindingTemplate modelBindingTemplate = existingList.get(currentIndex);
457458if (startPointDate.after(modelBindingTemplate.getModifiedIncludingChildren())) {
459 currentIndex++;
460continue;
461 }
462463if (endPointDate.before(modelBindingTemplate.getModifiedIncludingChildren())) {
464 currentIndex++;
465continue;
466 }
467468if (modelSubscription.isBrief()) {
469 resultsKeyBag.getBindingKey().add(modelBindingTemplate.getEntityKey());
470 }
471else {
472 org.uddi.api_v3.BindingTemplate apiBindingTemplate = new org.uddi.api_v3.BindingTemplate();
473 MappingModelToApi.mapBindingTemplate(modelBindingTemplate, apiBindingTemplate);
474 bindingDetail.getBindingTemplate().add(apiBindingTemplate);
475476 returnedRowCount++;
477 }
478479// If the returned rows equals the max allowed, we can end the loop.480if (modelSubscription.getMaxEntities() != null) {
481if (returnedRowCount == modelSubscription.getMaxEntities())
482break;
483 }
484485 currentIndex++;
486 }
487488// 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. 490if (currentIndex < (existingList.size() - 1))
491 chunkData = currentIndex + 1;
492else493 chunkData = null;
494495if (modelSubscription.isBrief())
496 result.getKeyBag().add(resultsKeyBag);
497else498 result.setBindingDetail(bindingDetail);
499500501 }
502if (subscriptionFilter.getGetBusinessDetail() != null) {
503 GetBusinessDetail getDetail = subscriptionFilter.getGetBusinessDetail();
504505// 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);
509for (String key : getDetail.getBusinessKey()) {
510 org.apache.juddi.model.BusinessEntity modelBusinessEntity = em.find(org.apache.juddi.model.BusinessEntity.class, key);
511if (modelBusinessEntity != null)
512 existingList.add(modelBusinessEntity);
513else514 missingKeyBag.getBusinessKey().add(key);
515 }
516// Store deleted keys in the results517if (missingKeyBag.getBusinessKey() != null && missingKeyBag.getBusinessKey().size() > 0)
518 result.getKeyBag().add(missingKeyBag);
519520 KeyBag resultsKeyBag = new KeyBag();
521 BusinessDetail businessDetail = new BusinessDetail();
522523// Set the currentIndex to 0 or the value of the chunkData524int currentIndex = 0;
525if (chunkData != null)
526 currentIndex = chunkData;
527528int returnedRowCount = 0;
529while(currentIndex < existingList.size()) {
530531 org.apache.juddi.model.BusinessEntity modelBusinessEntity = existingList.get(currentIndex);
532533if (startPointDate.after(modelBusinessEntity.getModifiedIncludingChildren())) {
534 currentIndex++;
535continue;
536 }
537538if (endPointDate.before(modelBusinessEntity.getModifiedIncludingChildren())) {
539 currentIndex++;
540continue;
541 }
542543if (modelSubscription.isBrief()) {
544 resultsKeyBag.getBusinessKey().add(modelBusinessEntity.getEntityKey());
545 }
546else {
547 org.uddi.api_v3.BusinessEntity apiBusinessEntity = new org.uddi.api_v3.BusinessEntity();
548 MappingModelToApi.mapBusinessEntity(modelBusinessEntity, apiBusinessEntity);
549 businessDetail.getBusinessEntity().add(apiBusinessEntity);
550551 returnedRowCount++;
552 }
553554// If the returned rows equals the max allowed, we can end the loop.555if (modelSubscription.getMaxEntities() != null) {
556if (returnedRowCount == modelSubscription.getMaxEntities())
557break;
558 }
559560 currentIndex++;
561 }
562563// 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. 565if (currentIndex < (existingList.size() - 1))
566 chunkData = currentIndex + 1;
567else568 chunkData = null;
569570if (modelSubscription.isBrief())
571 result.getKeyBag().add(resultsKeyBag);
572else573 result.setBusinessDetail(businessDetail);
574575 }
576if (subscriptionFilter.getGetServiceDetail() != null) {
577 GetServiceDetail getDetail = subscriptionFilter.getGetServiceDetail();
578579// 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);
583for (String key : getDetail.getServiceKey()) {
584 org.apache.juddi.model.BusinessService modelBusinessService = em.find(org.apache.juddi.model.BusinessService.class, key);
585if (modelBusinessService != null)
586 existingList.add(modelBusinessService);
587else588 missingKeyBag.getBusinessKey().add(key);
589 }
590// Store deleted keys in the results591if (missingKeyBag.getServiceKey() != null && missingKeyBag.getServiceKey().size() > 0)
592 result.getKeyBag().add(missingKeyBag);
593594 KeyBag resultsKeyBag = new KeyBag();
595 ServiceDetail serviceDetail = new ServiceDetail();
596597// Set the currentIndex to 0 or the value of the chunkData598int currentIndex = 0;
599if (chunkData != null)
600 currentIndex = chunkData;
601602int returnedRowCount = 0;
603while(currentIndex < existingList.size()) {
604605 org.apache.juddi.model.BusinessService modelBusinessService = existingList.get(currentIndex);
606607if (startPointDate.after(modelBusinessService.getModifiedIncludingChildren())) {
608 currentIndex++;
609continue;
610 }
611612if (endPointDate.before(modelBusinessService.getModifiedIncludingChildren())) {
613 currentIndex++;
614continue;
615 }
616617if (modelSubscription.isBrief()) {
618 resultsKeyBag.getServiceKey().add(modelBusinessService.getEntityKey());
619 }
620else {
621 org.uddi.api_v3.BusinessService apiBusinessService = new org.uddi.api_v3.BusinessService();
622 MappingModelToApi.mapBusinessService(modelBusinessService, apiBusinessService);
623 serviceDetail.getBusinessService().add(apiBusinessService);
624625 returnedRowCount++;
626 }
627628// If the returned rows equals the max allowed, we can end the loop.629if (modelSubscription.getMaxEntities() != null) {
630if (returnedRowCount == modelSubscription.getMaxEntities())
631break;
632 }
633634 currentIndex++;
635 }
636637// 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. 639if (currentIndex < (existingList.size() - 1))
640 chunkData = currentIndex + 1;
641else642 chunkData = null;
643644if (modelSubscription.isBrief())
645 result.getKeyBag().add(resultsKeyBag);
646else647 result.setServiceDetail(serviceDetail);
648649 }
650if (subscriptionFilter.getGetTModelDetail() != null) {
651 GetTModelDetail getDetail = subscriptionFilter.getGetTModelDetail();
652653// 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);
657for (String key : getDetail.getTModelKey()) {
658 org.apache.juddi.model.Tmodel modelTModel = em.find(org.apache.juddi.model.Tmodel.class, key);
659if (modelTModel != null)
660 existingList.add(modelTModel);
661else662 missingKeyBag.getTModelKey().add(key);
663 }
664// Store deleted keys in the results665if (missingKeyBag.getTModelKey() != null && missingKeyBag.getTModelKey().size() > 0)
666 result.getKeyBag().add(missingKeyBag);
667668 KeyBag resultsKeyBag = new KeyBag();
669 TModelDetail tmodelDetail = new TModelDetail();
670671// Set the currentIndex to 0 or the value of the chunkData672int currentIndex = 0;
673if (chunkData != null)
674 currentIndex = chunkData;
675676int returnedRowCount = 0;
677while(currentIndex < existingList.size()) {
678679 org.apache.juddi.model.Tmodel modelTModel = existingList.get(currentIndex);
680681if (startPointDate.after(modelTModel.getModifiedIncludingChildren())) {
682 currentIndex++;
683continue;
684 }
685686if (endPointDate.before(modelTModel.getModifiedIncludingChildren())) {
687 currentIndex++;
688continue;
689 }
690691if (modelSubscription.isBrief()) {
692 resultsKeyBag.getTModelKey().add(modelTModel.getEntityKey());
693 }
694else {
695 org.uddi.api_v3.TModel apiTModel = new org.uddi.api_v3.TModel();
696 MappingModelToApi.mapTModel(modelTModel, apiTModel);
697 tmodelDetail.getTModel().add(apiTModel);
698699 returnedRowCount++;
700 }
701702// If the returned rows equals the max allowed, we can end the loop.703if (modelSubscription.getMaxEntities() != null) {
704if (returnedRowCount == modelSubscription.getMaxEntities())
705break;
706 }
707708 currentIndex++;
709 }
710711// 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. 713if (currentIndex < (existingList.size() - 1))
714 chunkData = currentIndex + 1;
715else716 chunkData = null;
717718if (modelSubscription.isBrief())
719 result.getKeyBag().add(resultsKeyBag);
720else721 result.setTModelDetail(tmodelDetail);
722723 }
724if (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 query727 GetAssertionStatusReport getAssertionStatusReport = subscriptionFilter.getGetAssertionStatusReport();
728 List<?> businessKeysFound = null;
729 businessKeysFound = FindBusinessByPublisherQuery.select(em, null, publisher, businessKeysFound);
730731 AssertionStatusReport assertionStatusReport = new AssertionStatusReport();
732733 List<org.apache.juddi.model.PublisherAssertion> pubAssertionList = org.apache.juddi.query.FindPublisherAssertionByBusinessQuery.select(em, businessKeysFound, getAssertionStatusReport.getCompletionStatus());
734//if (pubAssertionList==null)735// return result;736for (org.apache.juddi.model.PublisherAssertion modelPubAssertion : pubAssertionList) {
737738if (startPointDate.after(modelPubAssertion.getModified())) {
739continue;
740 }
741742if (endPointDate.before(modelPubAssertion.getModified())) {
743continue;
744 }
745 org.uddi.api_v3.AssertionStatusItem apiAssertionStatusItem = new org.uddi.api_v3.AssertionStatusItem();
746747 MappingModelToApi.mapAssertionStatusItem(modelPubAssertion, apiAssertionStatusItem, businessKeysFound);
748749 assertionStatusReport.getAssertionStatusItem().add(apiAssertionStatusItem);
750 }
751752753 result.setAssertionStatusReport(assertionStatusReport);
754 }
755756// If chunkData contains non-null data, a new token must be created and the token returned in the results757if (chunkData != null) {
758 String chunkToken = CHUNK_TOKEN_PREFIX + UUID.randomUUID();
759 SubscriptionChunkToken newChunkToken = newSubscriptionChunkToken(chunkToken);
760 newChunkToken.setSubscriptionKey(body.getSubscriptionKey());
761 newChunkToken.setStartPoint(startPointDate);
762 newChunkToken.setEndPoint(endPointDate);
763 newChunkToken.setData(chunkData);
764765int chunkExpirationMinutes = DEFAULT_CHUNKEXPIRATION_MINUTES;
766try {
767 chunkExpirationMinutes = AppConfig.getConfiguration().getInt(Property.JUDDI_SUBSCRIPTION_CHUNKEXPIRATION_MINUTES);
768 }
769catch(ConfigurationException ce) {
770thrownewFatalErrorException(newErrorMessage("errors.configuration.Retrieval"));
771 }
772 newChunkToken.setExpiresAfter(new Date(System.currentTimeMillis() + ((long)chunkExpirationMinutes * 60L * 1000L)));
773774 em.persist(newChunkToken);
775776 result.setChunkToken(chunkToken);
777 }
778779 tx.commit();
780long procTime = System.currentTimeMillis() - startTime;
781 serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONRESULTS,
782 QueryStatus.SUCCESS, procTime);
783784return result;
785 } catch (DispositionReportFaultMessage drfm) {
786long procTime = System.currentTimeMillis() - startTime;
787 serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONRESULTS,
788 QueryStatus.FAILED, procTime);
789throw drfm;
790 } finally {
791if (tx.isActive()) {
792 tx.rollback();
793 }
794 em.close();
795 }
796 }
797798 @SuppressWarnings("unchecked")
799public List<Subscription> getSubscriptions(String authInfo)
800throws DispositionReportFaultMessage {
801long startTime = System.currentTimeMillis();
802 EntityManager em = PersistenceManager.getEntityManager();
803 EntityTransaction tx = em.getTransaction();
804try {
805 tx.begin();
806807 UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);
808809 List<Subscription> result = new ArrayList<Subscription>(0);
810811 List<org.apache.juddi.model.Subscription> modelSubscriptionList = (List<org.apache.juddi.model.Subscription>)FindSubscriptionByPublisherQuery.select(em, publisher.getAuthorizedName());
812if (modelSubscriptionList != null && modelSubscriptionList.size() > 0) {
813for (org.apache.juddi.model.Subscription modelSubscription : modelSubscriptionList) {
814815 Subscription apiSubscription = newSubscription();
816817 MappingModelToApi.mapSubscription(modelSubscription, apiSubscription);
818819 result.add(apiSubscription);
820 }
821 }
822823 tx.commit();
824long procTime = System.currentTimeMillis() - startTime;
825 serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONS,
826 QueryStatus.SUCCESS, procTime);
827828return result;
829 } catch (DispositionReportFaultMessage drfm) {
830long procTime = System.currentTimeMillis() - startTime;
831 serviceCounter.update(SubscriptionQuery.GET_SUBSCRIPTIONS,
832 QueryStatus.FAILED, procTime);
833throw drfm;
834 } finally {
835if (tx.isActive()) {
836 tx.rollback();
837 }
838 em.close();
839 }
840 }
841842843/* 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 */850publicvoid saveSubscription(String authInfo,
851 Holder<List<Subscription>> subscription)
852throws DispositionReportFaultMessage {
853long startTime = System.currentTimeMillis();
854855 EntityManager em = PersistenceManager.getEntityManager();
856 EntityTransaction tx = em.getTransaction();
857try {
858 tx.begin();
859860 UddiEntityPublisher publisher = this.getEntityPublisher(em, authInfo);
861 publisher.populateKeyGeneratorKeys(em);
862newValidateSubscription(publisher).validateSubscriptions(em, subscription.value, publisher);
863864 List<org.uddi.sub_v3.Subscription> apiSubscriptionList = subscription.value;
865for (org.uddi.sub_v3.Subscription apiSubscription : apiSubscriptionList) {
866867 org.apache.juddi.model.Subscription modelSubscription = new org.apache.juddi.model.Subscription();
868869 Object existing = em.find(org.apache.juddi.model.Subscription.class, apiSubscription.getSubscriptionKey());
870if (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 }
880881 doSubscriptionExpirationDate(apiSubscription);
882883 MappingApiToModel.mapSubscription(apiSubscription, modelSubscription);
884885 modelSubscription.setAuthorizedName(publisher.getAuthorizedName());
886887// Add the matching keys to the match collection888 List<?> keys = getSubscriptionMatches(apiSubscription.getSubscriptionFilter(), em);
889if (keys != null && keys.size() > 0) {
890for (Object key : keys) {
891 SubscriptionMatch subMatch = newSubscriptionMatch(modelSubscription, (String)key);
892 modelSubscription.getSubscriptionMatches().add(subMatch);
893 }
894 }
895896 em.persist(modelSubscription);
897 }
898899 tx.commit();
900long procTime = System.currentTimeMillis() - startTime;
901 serviceCounter.update(SubscriptionQuery.SAVE_SUBSCRIPTION,
902 QueryStatus.SUCCESS, procTime);
903 } catch (DispositionReportFaultMessage drfm) {
904long procTime = System.currentTimeMillis() - startTime;
905 serviceCounter.update(SubscriptionQuery.SAVE_SUBSCRIPTION,
906 QueryStatus.FAILED, procTime);
907throw drfm;
908 } finally {
909if (tx.isActive()) {
910 tx.rollback();
911 }
912 em.close();
913 }
914 }
915916/**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 subscription921 * @param apiSubscription - renewal subscription request922 * @throws DispositionReportFaultMessage 923 */924protectedvoid doRenewal(org.apache.juddi.model.Subscription existingSubscription, org.uddi.sub_v3.Subscription apiSubscription) throws DispositionReportFaultMessage {
925if (apiSubscription.getSubscriptionFilter() == null) {
926 String rawFilter = existingSubscription.getSubscriptionFilter();
927try {
928 SubscriptionFilter existingFilter = (SubscriptionFilter)JAXBMarshaller.unmarshallFromString(rawFilter, "org.uddi.sub_v3");
929 apiSubscription.setSubscriptionFilter(existingFilter);
930 }
931catch (JAXBException e) {
932 logger.error("JAXB Exception while marshalling subscription filter", e);
933thrownewFatalErrorException(newErrorMessage("errors.Unspecified"));
934 }
935 }
936937 }
938939/**940 * Will add the expiration date to the provided subscription request. Date is earlier of user provided date and the system default941 * 942 * @param apiSubscription943 * @throws DispositionReportFaultMessage944 */945protectedvoid doSubscriptionExpirationDate(org.uddi.sub_v3.Subscription apiSubscription) throws DispositionReportFaultMessage {
946947int subscriptionExpirationDays = DEFAULT_SUBSCRIPTIONEXPIRATION_DAYS;
948try {
949 subscriptionExpirationDays = AppConfig.getConfiguration().getInt(Property.JUDDI_SUBSCRIPTION_EXPIRATION_DAYS);
950 }
951catch(ConfigurationException ce) {
952thrownewFatalErrorException(newErrorMessage("errors.configuration.Retrieval"));
953 }
954955 GregorianCalendar expirationDate = new GregorianCalendar();
956 expirationDate.add(GregorianCalendar.DAY_OF_MONTH, subscriptionExpirationDays);
957958// The expiration date is the earlier of the provided date and that specified by the parameter.959if (apiSubscription.getExpiresAfter() != null) {
960 GregorianCalendar userExpiration = apiSubscription.getExpiresAfter().toGregorianCalendar();
961if (userExpiration.getTimeInMillis() < expirationDate.getTimeInMillis())
962 expirationDate.setTimeInMillis(userExpiration.getTimeInMillis());
963 }
964965try {
966 DatatypeFactory df = DatatypeFactory.newInstance();
967 apiSubscription.setExpiresAfter(df.newXMLGregorianCalendar(expirationDate));
968 }
969catch(DatatypeConfigurationException ce) {
970thrownewFatalErrorException(newErrorMessage("errors.Unspecified"));
971 }
972973 }
974975/**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 subscriptionFilter980 * @param em981 * @return a list of subscription matches982 * @throws DispositionReportFaultMessage983 */984protected List<?> getSubscriptionMatches(SubscriptionFilter subscriptionFilter, EntityManager em)
985throws DispositionReportFaultMessage {
986987988 List<?> keys = null;
989if (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 }
994if (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 }
999if (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 }
1004if (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 }
1009if (subscriptionFilter.getFindRelatedBusinesses() != null) {
1010// TODO: should we bother taking a snapshot of these?1011 }
1012if (subscriptionFilter.getGetBindingDetail() != null) {
1013//keys = subscriptionFilter.getGetBindingDetail().getBindingKey();1014// Nothing needs to be done1015 }
1016if (subscriptionFilter.getGetBusinessDetail() != null) {
1017//keys = subscriptionFilter.getGetBusinessDetail().getBusinessKey();1018// Nothing needs to be done1019 }
1020if (subscriptionFilter.getGetServiceDetail() != null) {
1021//keys = subscriptionFilter.getGetServiceDetail().getServiceKey();1022// Nothing needs to be done1023 }
1024if (subscriptionFilter.getGetTModelDetail() != null) {
1025//keys = subscriptionFilter.getGetTModelDetail().getTModelKey();1026// Nothing needs to be done1027 }
1028if (subscriptionFilter.getGetAssertionStatusReport() != null) {
1029// Nothing needs to be done1030 }
1031return keys;
10321033 }
10341035private List<String> getMissingKeys(List<?> currentMatchingKeys, List<SubscriptionMatch> subscriptionMatches) {
10361037 List<String> result = new ArrayList<String>(subscriptionMatches.size());
1038for (SubscriptionMatch subMatch : subscriptionMatches)
1039 result.add(subMatch.getEntityKey());
10401041 result.removeAll(currentMatchingKeys);
10421043return result;
1044 }
10451046 }