001package ca.uhn.fhir.validation;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2017 University Health Network
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import org.hl7.fhir.instance.model.api.IBaseResource;
024
025import ca.uhn.fhir.context.FhirContext;
026import ca.uhn.fhir.model.api.Bundle;
027import ca.uhn.fhir.model.api.IResource;
028import ca.uhn.fhir.parser.IParser;
029import ca.uhn.fhir.parser.LenientErrorHandler;
030import ca.uhn.fhir.rest.method.MethodUtil;
031import ca.uhn.fhir.rest.server.EncodingEnum;
032import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
033import ca.uhn.fhir.util.ObjectUtil;
034
035public class ValidationContext<T> extends BaseValidationContext<T> implements IValidationContext<T> {
036
037        private final IEncoder myEncoder;
038        private final T myResource;
039        private String myResourceAsString;
040        private final EncodingEnum myResourceAsStringEncoding;
041
042        private ValidationContext(FhirContext theContext, T theResource, IEncoder theEncoder) {
043                super(theContext);
044                myResource = theResource;
045                myEncoder = theEncoder;
046                if (theEncoder != null) {
047                        myResourceAsStringEncoding = theEncoder.getEncoding();
048                } else {
049                        myResourceAsStringEncoding = null;
050                }
051        }
052
053        @Override
054        public T getResource() {
055                return myResource;
056        }
057
058        @Override
059        public String getResourceAsString() {
060                if (myResourceAsString == null) {
061                        myResourceAsString = myEncoder.encode();
062                }
063                return myResourceAsString;
064        }
065
066        @Override
067        public EncodingEnum getResourceAsStringEncoding() {
068                return myResourceAsStringEncoding;
069        }
070
071        public static IValidationContext<Bundle> forBundle(final FhirContext theContext, final Bundle theBundle) {
072                return new ValidationContext<Bundle>(theContext, theBundle, new IEncoder() {
073                        @Override
074                        public String encode() {
075                                return theContext.newXmlParser().encodeBundleToString(theBundle);
076                        }
077
078                        @Override
079                        public EncodingEnum getEncoding() {
080                                return EncodingEnum.XML;
081                        }
082                });
083        }
084
085        public static <T extends IBaseResource> IValidationContext<T> forResource(final FhirContext theContext, final T theResource) {
086                return new ValidationContext<T>(theContext, theResource, new IEncoder() {
087                        @Override
088                        public String encode() {
089                                return theContext.newXmlParser().encodeResourceToString(theResource);
090                        }
091
092                        @Override
093                        public EncodingEnum getEncoding() {
094                                return EncodingEnum.XML;
095                        }
096                });
097        }
098
099        public static IValidationContext<IBaseResource> newChild(final IValidationContext<Bundle> theContext, final IResource theResource) {
100                return new IValidationContext<IBaseResource>() {
101
102                        @Override
103                        public void addValidationMessage(SingleValidationMessage theMessage) {
104                                theContext.addValidationMessage(theMessage);
105                        }
106
107                        @Override
108                        public FhirContext getFhirContext() {
109                                return theContext.getFhirContext();
110                        }
111
112                        @Override
113                        public IBaseResource getResource() {
114                                return theResource;
115                        }
116
117                        @Override
118                        public String getResourceAsString() {
119                                return theContext.getFhirContext().newXmlParser().encodeResourceToString(theResource);
120                        }
121
122                        @Override
123                        public EncodingEnum getResourceAsStringEncoding() {
124                                return EncodingEnum.XML;
125                        }
126
127                        @Override
128                        public ValidationResult toResult() {
129                                return theContext.toResult();
130                        }
131                };
132        }
133
134        private interface IEncoder {
135                String encode();
136
137                EncodingEnum getEncoding();
138        }
139
140        public static IValidationContext<IBaseResource> forText(final FhirContext theContext, final String theResourceBody) {
141                ObjectUtil.requireNonNull(theContext, "theContext can not be null");
142                ObjectUtil.requireNotEmpty(theResourceBody, "theResourceBody can not be null or empty");
143                return new BaseValidationContext<IBaseResource>(theContext) {
144
145                        private EncodingEnum myEncoding;
146                        private IBaseResource myParsed;
147
148                        @Override
149                        public IBaseResource getResource() {
150                                if (myParsed == null) {
151                                        IParser parser = getResourceAsStringEncoding().newParser(getFhirContext());
152                                        LenientErrorHandler errorHandler = new LenientErrorHandler();
153                                        errorHandler.setErrorOnInvalidValue(false);
154                                        parser.setParserErrorHandler(errorHandler);
155                                        myParsed = parser.parseResource(getResourceAsString());
156                                }
157                                return myParsed;
158                        }
159
160                        @Override
161                        public String getResourceAsString() {
162                                return theResourceBody;
163                        }
164
165                        @Override
166                        public EncodingEnum getResourceAsStringEncoding() {
167                                if (myEncoding == null) {
168                                        myEncoding = MethodUtil.detectEncodingNoDefault(theResourceBody);
169                                        if (myEncoding == null) {
170                                                throw new InvalidRequestException(theContext.getLocalizer().getMessage(ValidationContext.class, "unableToDetermineEncoding"));
171                                        }
172                                }
173                                return myEncoding;
174                        }
175
176                };
177        }
178}