001package ca.uhn.fhir.jaxrs.server.util; 002 003/* 004 * #%L 005 * HAPI FHIR JAX-RS Server 006 * %% 007 * Copyright (C) 2014 - 2016 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 java.io.IOException; 024import java.io.InputStream; 025import java.io.Reader; 026import java.nio.charset.Charset; 027import java.util.Collections; 028import java.util.List; 029 030import javax.ws.rs.core.HttpHeaders; 031import javax.ws.rs.core.MediaType; 032 033import org.apache.commons.lang3.StringUtils; 034import org.hl7.fhir.dstu3.model.IdType; 035 036import ca.uhn.fhir.context.FhirVersionEnum; 037import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider; 038import ca.uhn.fhir.model.primitive.IdDt; 039import ca.uhn.fhir.rest.api.RequestTypeEnum; 040import ca.uhn.fhir.rest.api.RestOperationTypeEnum; 041import ca.uhn.fhir.rest.method.RequestDetails; 042import ca.uhn.fhir.rest.param.ResourceParameter; 043import ca.uhn.fhir.rest.server.Constants; 044import ca.uhn.fhir.rest.server.IRestfulResponse; 045import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 046import ca.uhn.fhir.util.UrlUtil; 047 048/** 049 * The JaxRsRequest is a jax-rs specific implementation of the RequestDetails. 050 * 051 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare 052 */ 053public class JaxRsRequest extends RequestDetails { 054 055 /** 056 * An implementation of the builder pattern for the JaxRsRequest 057 */ 058 public static class Builder { 059 private String myResource; 060 private AbstractJaxRsProvider myServer; 061 private RequestTypeEnum myRequestType; 062 private RestOperationTypeEnum myRestOperation; 063 private String myId; 064 private String myVersion; 065 private String myCompartment; 066 private String myRequestUrl; 067 private final String myResourceName; 068 069 /** 070 * Utility Constructor 071 * @param theServer the server 072 * @param theRequestType the request type 073 * @param theRestOperation the rest operation 074 * @param theRequestUrl 075 */ 076 public Builder(AbstractJaxRsProvider theServer, RequestTypeEnum theRequestType, 077 RestOperationTypeEnum theRestOperation, String theRequestUrl, String theResourceName) { 078 this.myServer = theServer; 079 this.myRequestType = theRequestType; 080 this.myRestOperation = theRestOperation; 081 this.myRequestUrl = theRequestUrl; 082 this.myResourceName = theResourceName; 083 } 084 085 /** 086 * Set the resource 087 * @param resource the body contents of an http method 088 * @return the builder 089 */ 090 public Builder resource(String resource) { 091 this.myResource = resource; 092 return this; 093 } 094 095 /** 096 * Set the id 097 * @param id the resource id 098 * @return the builder 099 */ 100 public Builder id(String id) { 101 this.myId = id; 102 return this; 103 } 104 105 /** 106 * Set the id version 107 * @param version the version of the resource 108 * @return the builder 109 */ 110 public Builder version(String version) { 111 this.myVersion = version; 112 return this; 113 } 114 115 /** 116 * Set the compartment 117 * @param compartment the compartment 118 * @return the builder 119 */ 120 public Builder compartment(String compartment) { 121 this.myCompartment = compartment; 122 return this; 123 } 124 125 /** 126 * Create the jax-rs request 127 * @return the jax-rs request 128 */ 129 public JaxRsRequest build() { 130 JaxRsRequest result = new JaxRsRequest(myServer, myResource, myRequestType, myRestOperation); 131 if ((StringUtils.isNotBlank(myVersion) || StringUtils.isNotBlank(myCompartment)) 132 && StringUtils.isBlank(myId)) { 133 throw new InvalidRequestException("Don't know how to handle request path: " 134 + myServer.getUriInfo().getRequestUri().toASCIIString()); 135 } 136 137 FhirVersionEnum fhirContextVersion = myServer.getFhirContext().getVersion().getVersion(); 138 139 if (StringUtils.isNotBlank(myVersion)) { 140 if (FhirVersionEnum.DSTU3.equals(fhirContextVersion) || FhirVersionEnum.DSTU2_HL7ORG.equals(fhirContextVersion)) { 141 result.setId( 142 new IdType(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion))); 143 } else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) { 144 result.setId( 145 new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion))); 146 } 147 } else if (StringUtils.isNotBlank(myId)) { 148 if (FhirVersionEnum.DSTU3.equals(fhirContextVersion) || FhirVersionEnum.DSTU2_HL7ORG.equals(fhirContextVersion)) { 149 result.setId(new IdType(myServer.getBaseForRequest(), UrlUtil.unescape(myId))); 150 } else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) { 151 result.setId(new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId))); 152 } 153 } 154 155 if (myRestOperation == RestOperationTypeEnum.UPDATE) { 156 String contentLocation = result.getHeader(Constants.HEADER_CONTENT_LOCATION); 157 if (contentLocation != null) { 158 if (FhirVersionEnum.DSTU3.equals(fhirContextVersion) || FhirVersionEnum.DSTU2_HL7ORG.equals(fhirContextVersion)) { 159 result.setId(new IdType(contentLocation)); 160 } else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) { 161 result.setId(new IdDt(contentLocation)); 162 } 163 } 164 } 165 166 result.setCompartmentName(myCompartment); 167 result.setCompleteUrl(myRequestUrl); 168 result.setResourceName(myResourceName); 169 170 return result; 171 } 172 } 173 174 private String myResourceString; 175 private HttpHeaders myHeaders; 176 private AbstractJaxRsProvider myServer; 177 178 /** 179 * Utility Constructor 180 * @param server the server 181 * @param resourceString the resource body 182 * @param requestType the request type 183 * @param restOperation the operation type 184 */ 185 public JaxRsRequest(AbstractJaxRsProvider server, String resourceString, RequestTypeEnum requestType, 186 RestOperationTypeEnum restOperation) { 187 this.myHeaders = server.getHeaders(); 188 this.myResourceString = resourceString; 189 this.setRestOperationType(restOperation); 190 setServer(server); 191 setFhirServerBase(server.getBaseForServer()); 192 setParameters(server.getParameters()); 193 setRequestType(requestType); 194 } 195 196 @Override 197 public AbstractJaxRsProvider getServer() { 198 return myServer; 199 } 200 201 /** 202 * Set the server 203 * @param theServer the server to set 204 */ 205 public void setServer(AbstractJaxRsProvider theServer) { 206 this.myServer = theServer; 207 } 208 209 @Override 210 public String getHeader(String headerKey) { 211 List<String> requestHeader = getHeaders(headerKey); 212 return requestHeader.isEmpty() ? null : requestHeader.get(0); 213 } 214 215 @Override 216 public List<String> getHeaders(String name) { 217 List<String> requestHeader = myHeaders.getRequestHeader(name); 218 return requestHeader == null ? Collections.<String> emptyList() : requestHeader; 219 } 220 221 @Override 222 public String getServerBaseForRequest() { 223 return getServer().getServerAddressStrategy().determineServerBase(null, null); 224 } 225 226 @Override 227 protected byte[] getByteStreamRequestContents() { 228 return StringUtils.defaultString(myResourceString, "") 229 .getBytes(ResourceParameter.determineRequestCharset(this)); 230 } 231 232 @Override 233 public IRestfulResponse getResponse() { 234 if (super.getResponse() == null) { 235 setResponse(new JaxRsResponse(this)); 236 } 237 return super.getResponse(); 238 } 239 240 @Override 241 public Reader getReader() throws IOException { 242 // not yet implemented 243 throw new UnsupportedOperationException(); 244 } 245 246 @Override 247 public InputStream getInputStream() { 248 // not yet implemented 249 throw new UnsupportedOperationException(); 250 } 251 252 @Override 253 public Charset getCharset() { 254 String charset = null; 255 256 if(myHeaders.getMediaType() != null && myHeaders.getMediaType().getParameters() != null) { 257 charset = myHeaders.getMediaType().getParameters().get(MediaType.CHARSET_PARAMETER); 258 } 259 if(charset != null) { 260 return Charset.forName(charset); 261 } else { 262 return null; 263 } 264 } 265}