View Javadoc
1   package ca.uhn.fhir.jpa.dao.dstu3;
2   
3   /*
4    * #%L
5    * HAPI FHIR JPA Server
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   * http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import static org.apache.commons.lang3.StringUtils.isNotBlank;
24  
25  import java.util.*;
26  
27  import org.hl7.fhir.dstu3.model.IdType;
28  import org.hl7.fhir.dstu3.model.OperationOutcome;
29  import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
30  import org.hl7.fhir.dstu3.model.OperationOutcome.OperationOutcomeIssueComponent;
31  import org.hl7.fhir.exceptions.FHIRException;
32  import org.hl7.fhir.instance.model.api.*;
33  import org.springframework.beans.factory.annotation.Autowired;
34  import org.springframework.beans.factory.annotation.Qualifier;
35  
36  import ca.uhn.fhir.context.RuntimeResourceDefinition;
37  import ca.uhn.fhir.context.RuntimeSearchParam;
38  import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
39  import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
40  import ca.uhn.fhir.jpa.entity.ResourceTable;
41  import ca.uhn.fhir.jpa.util.DeleteConflict;
42  import ca.uhn.fhir.model.api.Include;
43  import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
44  import ca.uhn.fhir.rest.api.*;
45  import ca.uhn.fhir.rest.api.server.RequestDetails;
46  import ca.uhn.fhir.rest.server.exceptions.*;
47  import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
48  import ca.uhn.fhir.util.FhirTerser;
49  import ca.uhn.fhir.validation.*;
50  
51  public class FhirResourceDaoDstu3<T extends IAnyResource> extends BaseHapiFhirResourceDao<T> {
52  
53  	private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3.class);
54  
55  	@Autowired()
56  	@Qualifier("myInstanceValidatorDstu3")
57  	private IValidatorModule myInstanceValidator;
58  
59  	@Override
60  	protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode) {
61  		OperationOutcome oo = new OperationOutcome();
62  		OperationOutcomeIssueComponent issue = oo.addIssue();
63  		issue.getSeverityElement().setValueAsString(theSeverity);
64  		issue.setDiagnostics(theMessage);
65  		try {
66  			issue.setCode(org.hl7.fhir.dstu3.model.OperationOutcome.IssueType.fromCode(theCode));
67  		} catch (FHIRException e) {
68  			ourLog.error("Unknown code: {}", theCode);
69  		}
70  		return oo;
71  	}
72  
73  
74  	@Override
75  	public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequestDetails) {
76  		ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theResource, null, theId);
77  		notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
78  
79  		if (theMode == ValidationModeEnum.DELETE) {
80  			if (theId == null || theId.hasIdPart() == false) {
81  				throw new InvalidRequestException("No ID supplied. ID is required when validating with mode=DELETE");
82  			}
83  			final ResourceTable entity = readEntityLatestVersion(theId);
84  
85  			// Validate that there are no resources pointing to the candidate that
86  			// would prevent deletion
87  			List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
88  			if (myDaoConfig.isEnforceReferentialIntegrityOnDelete()) {
89  				validateOkToDelete(deleteConflicts, entity, true);
90  			}
91  			validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
92  
93  			OperationOutcome oo = new OperationOutcome();
94  			oo.addIssue().setSeverity(IssueSeverity.INFORMATION).setDiagnostics("Ok to delete");
95  			return new MethodOutcome(new IdType(theId.getValue()), oo);
96  		}
97  
98  		FhirValidator validator = getContext().newValidator();
99  
100 		validator.registerValidatorModule(myInstanceValidator);
101 
102 		validator.registerValidatorModule(new IdChecker(theMode));
103 
104 		IBaseResource resourceToValidateById = null;
105 		if (theId != null && theId.hasResourceType() && theId.hasIdPart()) {
106 			Class<? extends IBaseResource> type = getContext().getResourceDefinition(theId.getResourceType()).getImplementingClass();
107 			IFhirResourceDao<? extends IBaseResource> dao = getDao(type);
108 			resourceToValidateById = dao.read(theId, theRequestDetails);
109 		}
110 
111 		ValidationResult result;
112 		if (theResource == null) {
113 			if (resourceToValidateById != null) {
114 				result = validator.validateWithResult(resourceToValidateById);
115 			} else {
116 				String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "cantValidateWithNoResource");
117 				throw new InvalidRequestException(msg);
118 			}
119 		} else if (isNotBlank(theRawResource)) {
120 			result = validator.validateWithResult(theRawResource);
121 		} else {
122 			result = validator.validateWithResult(theResource);
123 		}
124 
125 		if (result.isSuccessful()) {
126 			MethodOutcome retVal = new MethodOutcome();
127 			retVal.setOperationOutcome(result.toOperationOutcome());
128 			return retVal;
129 		} else {
130 			throw new PreconditionFailedException("Validation failed", result.toOperationOutcome());
131 		}
132 
133 	}
134 
135 	private class IdChecker implements IValidatorModule {
136 
137 		private ValidationModeEnum myMode;
138 
139 		public IdChecker(ValidationModeEnum theMode) {
140 			myMode = theMode;
141 		}
142 
143 		@Override
144 		public void validateResource(IValidationContext<IBaseResource> theCtx) {
145 			boolean hasId = theCtx.getResource().getIdElement().hasIdPart();
146 			if (myMode == ValidationModeEnum.CREATE) {
147 				if (hasId) {
148 					throw new UnprocessableEntityException("Resource has an ID - ID must not be populated for a FHIR create");
149 				}
150 			} else if (myMode == ValidationModeEnum.UPDATE) {
151 				if (hasId == false) {
152 					throw new UnprocessableEntityException("Resource has no ID - ID must be populated for a FHIR update");
153 				}
154 			}
155 
156 		}
157 
158 	}
159 
160 }