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  		if (theRequestDetails != null) {
77  			ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theResource, null, theId);
78  			notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
79  		}
80  
81  		if (theMode == ValidationModeEnum.DELETE) {
82  			if (theId == null || theId.hasIdPart() == false) {
83  				throw new InvalidRequestException("No ID supplied. ID is required when validating with mode=DELETE");
84  			}
85  			final ResourceTable entity = readEntityLatestVersion(theId);
86  
87  			// Validate that there are no resources pointing to the candidate that
88  			// would prevent deletion
89  			List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
90  			if (myDaoConfig.isEnforceReferentialIntegrityOnDelete()) {
91  				validateOkToDelete(deleteConflicts, entity, true);
92  			}
93  			validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
94  
95  			OperationOutcome oo = new OperationOutcome();
96  			oo.addIssue().setSeverity(IssueSeverity.INFORMATION).setDiagnostics("Ok to delete");
97  			return new MethodOutcome(new IdType(theId.getValue()), oo);
98  		}
99  
100 		FhirValidator validator = getContext().newValidator();
101 
102 		validator.registerValidatorModule(myInstanceValidator);
103 
104 		validator.registerValidatorModule(new IdChecker(theMode));
105 
106 		IBaseResource resourceToValidateById = null;
107 		if (theId != null && theId.hasResourceType() && theId.hasIdPart()) {
108 			Class<? extends IBaseResource> type = getContext().getResourceDefinition(theId.getResourceType()).getImplementingClass();
109 			IFhirResourceDao<? extends IBaseResource> dao = getDao(type);
110 			resourceToValidateById = dao.read(theId, theRequestDetails);
111 		}
112 
113 		ValidationResult result;
114 		if (theResource == null) {
115 			if (resourceToValidateById != null) {
116 				result = validator.validateWithResult(resourceToValidateById);
117 			} else {
118 				String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "cantValidateWithNoResource");
119 				throw new InvalidRequestException(msg);
120 			}
121 		} else if (isNotBlank(theRawResource)) {
122 			result = validator.validateWithResult(theRawResource);
123 		} else {
124 			result = validator.validateWithResult(theResource);
125 		}
126 
127 		if (result.isSuccessful()) {
128 			MethodOutcome retVal = new MethodOutcome();
129 			retVal.setOperationOutcome(result.toOperationOutcome());
130 			return retVal;
131 		} else {
132 			throw new PreconditionFailedException("Validation failed", result.toOperationOutcome());
133 		}
134 
135 	}
136 
137 	private class IdChecker implements IValidatorModule {
138 
139 		private ValidationModeEnum myMode;
140 
141 		public IdChecker(ValidationModeEnum theMode) {
142 			myMode = theMode;
143 		}
144 
145 		@Override
146 		public void validateResource(IValidationContext<IBaseResource> theCtx) {
147 			boolean hasId = theCtx.getResource().getIdElement().hasIdPart();
148 			if (myMode == ValidationModeEnum.CREATE) {
149 				if (hasId) {
150 					throw new UnprocessableEntityException("Resource has an ID - ID must not be populated for a FHIR create");
151 				}
152 			} else if (myMode == ValidationModeEnum.UPDATE) {
153 				if (hasId == false) {
154 					throw new UnprocessableEntityException("Resource has no ID - ID must be populated for a FHIR update");
155 				}
156 			}
157 
158 		}
159 
160 	}
161 
162 }