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