View Javadoc
1   package ca.uhn.fhir.jpa.util;
2   
3   import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
4   import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
5   import ca.uhn.fhir.rest.api.server.RequestDetails;
6   import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
7   import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
8   import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
9   import org.hl7.fhir.instance.model.api.IBaseResource;
10  import org.hl7.fhir.r4.model.Subscription;
11  import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
12  import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
13  import org.springframework.beans.factory.annotation.Autowired;
14  import org.springframework.beans.factory.annotation.Qualifier;
15  
16  import static org.apache.commons.lang3.StringUtils.isNotBlank;
17  
18  /*
19   * #%L
20   * HAPI FHIR JPA Server
21   * %%
22   * Copyright (C) 2014 - 2018 University Health Network
23   * %%
24   * Licensed under the Apache License, Version 2.0 (the "License");
25   * you may not use this file except in compliance with the License.
26   * You may obtain a copy of the License at
27   * 
28   *      http://www.apache.org/licenses/LICENSE-2.0
29   * 
30   * Unless required by applicable law or agreed to in writing, software
31   * distributed under the License is distributed on an "AS IS" BASIS,
32   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33   * See the License for the specific language governing permissions and
34   * limitations under the License.
35   * #L%
36   */
37  
38  /**
39   * Interceptor which requires newly created {@link Subscription subscriptions} to be in
40   * {@link SubscriptionStatus#REQUESTED} state and prevents clients from changing the status.
41   */
42  public class SubscriptionsRequireManualActivationInterceptorR4 extends ServerOperationInterceptorAdapter {
43  
44  	@Autowired
45  	@Qualifier("mySubscriptionDaoR4")
46  	private IFhirResourceDao<Subscription> myDao;
47  
48  	@Override
49  	public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
50  		if (myDao.getContext().getResourceDefinition(theResource).getName().equals("Subscription")) {
51  			verifyStatusOk(RestOperationTypeEnum.CREATE, null, theResource);
52  		}
53  	}
54  
55  	@Override
56  	public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
57  		if (myDao.getContext().getResourceDefinition(theNewResource).getName().equals("Subscription")) {
58  			verifyStatusOk(RestOperationTypeEnum.UPDATE, theOldResource, theNewResource);
59  		}
60  	}
61  
62  
63  	public void setDao(IFhirResourceDao<Subscription> theDao) {
64  		myDao = theDao;
65  	}
66  
67  	private void verifyStatusOk(RestOperationTypeEnum theOperation, IBaseResource theOldResourceOrNull, IBaseResource theResource) {
68  		Subscription subscription = (Subscription) theResource;
69  		SubscriptionStatus newStatus = subscription.getStatusElement().getValue();
70  
71  		if (newStatus == SubscriptionStatus.REQUESTED || newStatus == SubscriptionStatus.OFF) {
72  			return;
73  		}
74  
75  		if (newStatus == null) {
76  			String actualCode = subscription.getStatusElement().getValueAsString();
77  			throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated on this server" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
78  		}
79  
80  		if (theOldResourceOrNull != null) {
81  			try {
82  				Subscription existing = (Subscription) theOldResourceOrNull;
83  				SubscriptionStatus existingStatus = existing.getStatusElement().getValue();
84  				if (existingStatus != newStatus) {
85  					verifyActiveStatus(theOperation, subscription, newStatus, existingStatus);
86  				}
87  			} catch (ResourceNotFoundException e) {
88  				verifyActiveStatus(theOperation, subscription, newStatus, null);
89  			}
90  		} else {
91  			verifyActiveStatus(theOperation, subscription, newStatus, null);
92  		}
93  	}
94  
95  	private void verifyActiveStatus(RestOperationTypeEnum theOperation, Subscription theSubscription, SubscriptionStatus newStatus, SubscriptionStatus theExistingStatus) {
96  		SubscriptionChannelType channelType = theSubscription.getChannel().getTypeElement().getValue();
97  
98  		if (channelType == null) {
99  			throw new UnprocessableEntityException("Subscription.channel.type must be populated");
100 		}
101 
102 		if (channelType == SubscriptionChannelType.WEBSOCKET) {
103 			return;
104 		}
105 
106 		if (theExistingStatus != null) {
107 			throw new UnprocessableEntityException("Subscription.status can not be changed from " + describeStatus(theExistingStatus) + " to " + describeStatus(newStatus));
108 		}
109 
110 		if (theSubscription.getStatus() == null) {
111 			throw new UnprocessableEntityException("Can not " + theOperation.getCode().toLowerCase() + " resource: Subscription.status must be populated on this server");
112 		}
113 
114 		throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatus.OFF.toCode() + "' or '" + SubscriptionStatus.REQUESTED.toCode() + "' on a newly created subscription");
115 	}
116 
117 	private String describeStatus(SubscriptionStatus existingStatus) {
118 		String existingStatusString;
119 		if (existingStatus != null) {
120 			existingStatusString = '\'' + existingStatus.toCode() + '\'';
121 		} else {
122 			existingStatusString = "null";
123 		}
124 		return existingStatusString;
125 	}
126 
127 }