diff --git a/hapi-fhir-base/.project b/hapi-fhir-base/.project index 790dcdc0123..7afe06363c3 100644 --- a/hapi-fhir-base/.project +++ b/hapi-fhir-base/.project @@ -15,6 +15,11 @@ + + org.eclipse.m2e.core.maven2Builder + + + org.eclipse.jem.workbench.JavaEMFNature diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java index e80d020c3d7..ac628d13763 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.context; +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java index c1fe60cc1f4..0931f84ef90 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java @@ -67,7 +67,7 @@ import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor; import ca.uhn.fhir.util.ReflectionUtil; import ca.uhn.fhir.util.UrlUtil; -abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding { +public abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding { protected static final Set ALLOWED_PARAMS; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseResourceReturningMethodBinding.class); @@ -102,8 +102,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding collectionType = ReflectionUtil.getGenericCollectionTypeOfMethodReturnType(theMethod); if (collectionType != null) { if (!Object.class.equals(collectionType) && !IBaseResource.class.isAssignableFrom(collectionType)) { - throw new ConfigurationException("Method " + theMethod.getDeclaringClass().getSimpleName() + "#" + theMethod.getName() + " returns an invalid collection generic type: " - + collectionType); + throw new ConfigurationException( + "Method " + theMethod.getDeclaringClass().getSimpleName() + "#" + theMethod.getName() + " returns an invalid collection generic type: " + collectionType); } } myResourceListCollectionType = collectionType; @@ -121,8 +121,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding summaryMode = RestfulServerUtils.determineSummaryMode(theRequest); - - // Determine response encoding - EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest(), theServer.getDefaultResponseEncoding()); - - // Is this request coming from a browser - String uaHeader = theRequest.getServletRequest().getHeader("user-agent"); - boolean requestIsBrowser = false; - if (uaHeader != null && uaHeader.contains("Mozilla")) { - requestIsBrowser = true; - } - byte[] requestContents = loadRequestContents(theRequest); - + + final ResourceOrDstu1Bundle responseObject = invokeServer(theServer, theRequest, requestContents); + + Set summaryMode = RestfulServerUtils.determineSummaryMode(theRequest); + if (responseObject.getResource() != null) { + + for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) { + IServerInterceptor next = theServer.getInterceptors().get(i); + boolean continueProcessing = next.outgoingResponse(theRequest, responseObject.getResource(), theRequest.getServletRequest(), theRequest.getServletResponse()); + if (!continueProcessing) { + return; + } + } + + boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest); + HttpServletResponse response = theRequest.getServletResponse(); + RestfulServerUtils.streamResponseAsResource(theServer, response, responseObject.getResource(), prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), + isAddContentLocationHeader(), theRequest); + } else { + // Is this request coming from a browser + String uaHeader = theRequest.getServletRequest().getHeader("user-agent"); + boolean requestIsBrowser = false; + if (uaHeader != null && uaHeader.contains("Mozilla")) { + requestIsBrowser = true; + } + + for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) { + IServerInterceptor next = theServer.getInterceptors().get(i); + boolean continueProcessing = next.outgoingResponse(theRequest, responseObject.getDstu1Bundle(), theRequest.getServletRequest(), theRequest.getServletResponse()); + if (!continueProcessing) { + ourLog.debug("Interceptor {} returned false, not continuing processing"); + return; + } + } + + HttpServletResponse response = theRequest.getServletResponse(); + RestfulServerUtils.streamResponseAsBundle(theServer, response, responseObject.getDstu1Bundle(), theRequest.getFhirServerBase(), summaryMode, theRequest.isRespondGzip(), requestIsBrowser, + theRequest); + } + } + + public ResourceOrDstu1Bundle invokeServer(RestfulServer theServer, RequestDetails theRequest, byte[] requestContents) { // Method params Object[] params = new Object[getParameters().size()]; for (int i = 0; i < getParameters().size(); i++) { @@ -267,9 +290,10 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding parameters = theRequest.getParameters(); @@ -323,17 +347,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding= 0; i--) { - IServerInterceptor next = theServer.getInterceptors().get(i); - boolean continueProcessing = next.outgoingResponse(theRequest, resource, theRequest.getServletRequest(), theRequest.getServletResponse()); - if (!continueProcessing) { - ourLog.debug("Interceptor {} returned false, not continuing processing"); - return; - } - } - - RestfulServerUtils.streamResponseAsResource(theServer, response, resource, prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, respondGzip, - isAddContentLocationHeader(), theRequest); + responseObject = new ResourceOrDstu1Bundle(resource); break; } else { Set includes = getRequestIncludesFromParams(params); @@ -344,32 +358,18 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding= 0; i--) { - IServerInterceptor next = theServer.getInterceptors().get(i); - boolean continueProcessing = next.outgoingResponse(theRequest, bundle, theRequest.getServletRequest(), theRequest.getServletResponse()); - if (!continueProcessing) { - ourLog.debug("Interceptor {} returned false, not continuing processing"); - return; - } - } - RestfulServerUtils.streamResponseAsBundle(theServer, response, bundle, theRequest.getFhirServerBase(), summaryMode, respondGzip, requestIsBrowser, theRequest); + responseObject = new ResourceOrDstu1Bundle(bundle); } else { IBaseResource resBundle = bundleFactory.getResourceBundle(); - for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) { - IServerInterceptor next = theServer.getInterceptors().get(i); - boolean continueProcessing = next.outgoingResponse(theRequest, resBundle, theRequest.getServletRequest(), theRequest.getServletResponse()); - if (!continueProcessing) { - ourLog.debug("Interceptor {} returned false, not continuing processing"); - return; - } - } - RestfulServerUtils.streamResponseAsResource(theServer, response, resBundle, prettyPrint, summaryMode, - Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), isAddContentLocationHeader(), theRequest); + responseObject = new ResourceOrDstu1Bundle(resBundle); } break; @@ -384,22 +384,17 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding= 0; i--) { - IServerInterceptor next = theServer.getInterceptors().get(i); - boolean continueProcessing = next.outgoingResponse(theRequest, resource, theRequest.getServletRequest(), theRequest.getServletResponse()); - if (!continueProcessing) { - return; - } - } - - RestfulServerUtils.streamResponseAsResource(theServer, response, resource, prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, respondGzip, - isAddContentLocationHeader(), theRequest); + responseObject = new ResourceOrDstu1Bundle(resource); break; } + default: + throw new IllegalStateException(); // should not happen } + return responseObject; } + public abstract Object invokeServer(RestfulServer theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException; + /** * Should the response include a Content-Location header. Search method bunding (and any others?) may override this to disable the content-location, since it doesn't make sense */ @@ -412,7 +407,32 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding responseResources = retVal.getResources(0, 1); IBaseResource responseResource = responseResources.get(0); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java index c26ede12486..b4aa63017d7 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java @@ -37,6 +37,7 @@ import ca.uhn.fhir.rest.server.RestfulServer; public class RequestDetails { + private Map> myHeaders = new HashMap>(); private String myCompartmentName; private String myCompleteUrl; private String myFhirServerBase; @@ -230,4 +231,22 @@ public class RequestDetails { return retVal; } + public void addHeader(String theName, String theValue) { + String lowerCase = theName.toLowerCase(); + ArrayList list = myHeaders.get(lowerCase); + if (list == null) { + list = new ArrayList(); + myHeaders.put(lowerCase, list); + } + list.add(theValue); + } + + public String getFirstHeader(String theName) { + ArrayList list = myHeaders.get(theName.toLowerCase()); + if (list == null || list.isEmpty()) { + return null; + } + return list.get(0); + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetailsParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetailsParameter.java new file mode 100644 index 00000000000..adab1dcb613 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetailsParameter.java @@ -0,0 +1,55 @@ +package ca.uhn.fhir.rest.method; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.hl7.fhir.instance.model.api.IBaseResource; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; + +class RequestDetailsParameter implements IParameter { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RequestDetailsParameter.class); + + @Override + public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { + /* + * Does nothing, since we just ignore HttpServletRequest arguments + */ + ourLog.trace("Ignoring RequestDetailsParameter argument: {}", theSourceClientArgument); + } + + @Override + public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, byte[] theRequestContents, BaseMethodBinding theMethodBinding) throws InternalErrorException, InvalidRequestException { + return theRequest; + } + + @Override + public void initializeTypes(Method theMethod, Class> theOuterCollectionType, Class> theInnerCollectionType, Class theParameterType) { + // ignore + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java index 3f4026bb9f1..73a936c60d1 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java @@ -52,9 +52,6 @@ import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -/** - * Created by dsotnikov on 2/25/2014. - */ public class SearchMethodBinding extends BaseResourceReturningMethodBinding { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchMethodBinding.class); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java index a18a8dd5544..ef00e1a79e6 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -477,14 +478,14 @@ public class RestfulServer extends HttpServlet { return; } - Integer count = RestfulServerUtils.extractCountParameter(theRequest.getServletRequest()); + Integer count = RestfulServerUtils.extractCountParameter(theRequest); if (count == null) { count = getPagingProvider().getDefaultPageSize(); } else if (count > getPagingProvider().getMaximumPageSize()) { count = getPagingProvider().getMaximumPageSize(); } - Integer offsetI = RestfulServerUtils.tryToExtractNamedParameter(theRequest.getServletRequest(), Constants.PARAM_PAGINGOFFSET); + Integer offsetI = RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_PAGINGOFFSET); if (offsetI == null || offsetI < 0) { offsetI = 0; } @@ -545,6 +546,12 @@ public class RestfulServer extends HttpServlet { requestDetails.setRequestType(theRequestType); requestDetails.setServletRequest(theRequest); requestDetails.setServletResponse(theResponse); + for (Enumeration iter = theRequest.getHeaderNames(); iter.hasMoreElements(); ) { + String nextName = iter.nextElement(); + for (Enumeration valueIter = theRequest.getHeaders(nextName); valueIter.hasMoreElements();) { + requestDetails.addHeader(nextName, valueIter.nextElement()); + } + } try { @@ -556,7 +563,6 @@ public class RestfulServer extends HttpServlet { } } - String resourceName = null; String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI()); String servletPath = StringUtils.defaultString(theRequest.getServletPath()); StringBuffer requestUrl = theRequest.getRequestURL(); @@ -572,11 +578,9 @@ public class RestfulServer extends HttpServlet { ourLog.trace("Context Path: {}", servletContextPath); } - IdDt id = null; - String operation = null; - String compartment = null; - + String requestPath = getRequestPath(requestFullPath, servletContextPath, servletPath); + if (requestPath.length() > 0 && requestPath.charAt(0) == '/') { requestPath = requestPath.substring(1); } @@ -588,84 +592,16 @@ public class RestfulServer extends HttpServlet { Map params = new HashMap(theRequest.getParameterMap()); requestDetails.setParameters(params); - StringTokenizer tok = new StringTokenizer(requestPath, "/"); - if (tok.hasMoreTokens()) { - resourceName = tok.nextToken(); - if (partIsOperation(resourceName)) { - operation = resourceName; - resourceName = null; - } - } - requestDetails.setResourceName(resourceName); - - ResourceBinding resourceBinding = null; - BaseMethodBinding resourceMethod = null; - if (Constants.URL_TOKEN_METADATA.equals(resourceName) || theRequestType == RequestTypeEnum.OPTIONS) { - resourceMethod = myServerConformanceMethod; - } else if (resourceName == null) { - resourceBinding = myServerBinding; - } else { - resourceBinding = myResourceNameToBinding.get(resourceName); - if (resourceBinding == null) { - throw new InvalidRequestException("Unknown resource type '" + resourceName + "' - Server knows how to handle: " + myResourceNameToBinding.keySet()); - } - } - - if (tok.hasMoreTokens()) { - String nextString = tok.nextToken(); - if (partIsOperation(nextString)) { - operation = nextString; - } else { - id = new IdDt(resourceName, UrlUtil.unescape(nextString)); - } - } - - if (tok.hasMoreTokens()) { - String nextString = tok.nextToken(); - if (nextString.equals(Constants.PARAM_HISTORY)) { - if (tok.hasMoreTokens()) { - String versionString = tok.nextToken(); - if (id == null) { - throw new InvalidRequestException("Don't know how to handle request path: " + requestPath); - } - id = new IdDt(resourceName, id.getIdPart(), UrlUtil.unescape(versionString)); - } else { - operation = Constants.PARAM_HISTORY; - } - } else if (partIsOperation(nextString)) { - if (operation != null) { - throw new InvalidRequestException("URL Path contains two operations: " + requestPath); - } - operation = nextString; - } else { - compartment = nextString; - } - } - - // Secondary is for things like ..../_tags/_delete - String secondaryOperation = null; - - while (tok.hasMoreTokens()) { - String nextString = tok.nextToken(); - if (operation == null) { - operation = nextString; - } else if (secondaryOperation == null) { - secondaryOperation = nextString; - } else { - throw new InvalidRequestException("URL path has unexpected token '" + nextString + "' at the end: " + requestPath); - } - } + IdDt id; + populateRequestDetailsFromRequestPath(requestDetails, requestPath); if (theRequestType == RequestTypeEnum.PUT) { String contentLocation = theRequest.getHeader(Constants.HEADER_CONTENT_LOCATION); if (contentLocation != null) { id = new IdDt(contentLocation); + requestDetails.setId(id); } } - requestDetails.setId(id); - requestDetails.setOperation(operation); - requestDetails.setSecondaryOperation(secondaryOperation); - requestDetails.setCompartmentName(compartment); String acceptEncoding = theRequest.getHeader(Constants.HEADER_ACCEPT_ENCODING); boolean respondGzip = false; @@ -696,18 +632,7 @@ public class RestfulServer extends HttpServlet { return; } - if (resourceMethod == null) { - if (resourceBinding != null) { - resourceMethod = resourceBinding.getMethod(requestDetails); - } - } - if (resourceMethod == null) { - if (isBlank(requestPath)) { - throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "rootRequest")); - } else { - throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "unknownMethod", theRequestType.name(), requestPath, params.keySet())); - } - } + BaseMethodBinding resourceMethod = determineResourceMethod(requestDetails, requestPath); requestDetails.setRestOperationType(resourceMethod.getRestOperationType()); @@ -806,6 +731,105 @@ public class RestfulServer extends HttpServlet { } } + public BaseMethodBinding determineResourceMethod(RequestDetails requestDetails, String requestPath) { + RequestTypeEnum requestType = requestDetails.getRequestType(); + + ResourceBinding resourceBinding = null; + BaseMethodBinding resourceMethod = null; + String resourceName = requestDetails.getResourceName(); + if (Constants.URL_TOKEN_METADATA.equals(resourceName) || requestType == RequestTypeEnum.OPTIONS) { + resourceMethod = myServerConformanceMethod; + } else if (resourceName == null) { + resourceBinding = myServerBinding; + } else { + resourceBinding = myResourceNameToBinding.get(resourceName); + if (resourceBinding == null) { + throw new InvalidRequestException("Unknown resource type '" + resourceName + "' - Server knows how to handle: " + myResourceNameToBinding.keySet()); + } + } + + if (resourceMethod == null) { + if (resourceBinding != null) { + resourceMethod = resourceBinding.getMethod(requestDetails); + } + } + if (resourceMethod == null) { + if (isBlank(requestPath)) { + throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "rootRequest")); + } else { + throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "unknownMethod", requestType.name(), requestPath, requestDetails.getParameters().keySet())); + } + } + return resourceMethod; + } + + public void populateRequestDetailsFromRequestPath(RequestDetails theRequestDetails, String theRequestPath) { + StringTokenizer tok = new StringTokenizer(theRequestPath, "/"); + String resourceName = null; + + IdDt id = null; + String operation = null; + String compartment = null; + if (tok.hasMoreTokens()) { + resourceName = tok.nextToken(); + if (partIsOperation(resourceName)) { + operation = resourceName; + resourceName = null; + } + } + theRequestDetails.setResourceName(resourceName); + + if (tok.hasMoreTokens()) { + String nextString = tok.nextToken(); + if (partIsOperation(nextString)) { + operation = nextString; + } else { + id = new IdDt(resourceName, UrlUtil.unescape(nextString)); + } + } + + if (tok.hasMoreTokens()) { + String nextString = tok.nextToken(); + if (nextString.equals(Constants.PARAM_HISTORY)) { + if (tok.hasMoreTokens()) { + String versionString = tok.nextToken(); + if (id == null) { + throw new InvalidRequestException("Don't know how to handle request path: " + theRequestPath); + } + id = new IdDt(resourceName, id.getIdPart(), UrlUtil.unescape(versionString)); + } else { + operation = Constants.PARAM_HISTORY; + } + } else if (partIsOperation(nextString)) { + if (operation != null) { + throw new InvalidRequestException("URL Path contains two operations: " + theRequestPath); + } + operation = nextString; + } else { + compartment = nextString; + } + } + + // Secondary is for things like ..../_tags/_delete + String secondaryOperation = null; + + while (tok.hasMoreTokens()) { + String nextString = tok.nextToken(); + if (operation == null) { + operation = nextString; + } else if (secondaryOperation == null) { + secondaryOperation = nextString; + } else { + throw new InvalidRequestException("URL path has unexpected token '" + nextString + "' at the end: " + theRequestPath); + } + } + + theRequestDetails.setId(id); + theRequestDetails.setOperation(operation); + theRequestDetails.setSecondaryOperation(secondaryOperation); + theRequestDetails.setCompartmentName(compartment); + } + /** * Initializes the server. Note that this method is final to avoid accidentally introducing bugs in implementations, but subclasses may put initialization code in {@link #initialize()}, which is * called immediately before beginning initialization of the restful server's internal init. diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java index f0cf84d7250..5f13cb2b324 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java @@ -394,8 +394,9 @@ public class RestfulServerUtils { return retVal; } - public static Integer extractCountParameter(HttpServletRequest theRequest) { - return RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_COUNT); + public static Integer extractCountParameter(RequestDetails theRequest) { + String paramName = Constants.PARAM_COUNT; + return tryToExtractNamedParameter(theRequest, paramName); } public static IParser getNewParser(FhirContext theContext, RequestDetails theRequestDetails) { @@ -674,18 +675,18 @@ public class RestfulServerUtils { } } - static Integer tryToExtractNamedParameter(HttpServletRequest theRequest, String name) { - String countString = theRequest.getParameter(name); - Integer count = null; - if (isNotBlank(countString)) { - try { - count = Integer.parseInt(countString); - } catch (NumberFormatException e) { - ourLog.debug("Failed to parse _count value '{}': {}", countString, e); - } - } - return count; - } +// static Integer tryToExtractNamedParameter(HttpServletRequest theRequest, String name) { +// String countString = theRequest.getParameter(name); +// Integer count = null; +// if (isNotBlank(countString)) { +// try { +// count = Integer.parseInt(countString); +// } catch (NumberFormatException e) { +// ourLog.debug("Failed to parse _count value '{}': {}", countString, e); +// } +// } +// return count; +// } public static void validateResourceListNotNull(List theResourceList) { if (theResourceList == null) { @@ -701,4 +702,17 @@ public class RestfulServerUtils { } } + public static Integer tryToExtractNamedParameter(RequestDetails theRequest, String theParamName) { + String[] retVal = theRequest.getParameters().get(theParamName); + if (retVal == null) { + return null; + } + try { + return Integer.parseInt(retVal[0]); + } catch (NumberFormatException e) { + ourLog.debug("Failed to parse {} value '{}': {}", new Object[] {theParamName, retVal[0], e}); + return null; + } + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java index b5dfc950b2a..8359edae06d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java @@ -187,7 +187,7 @@ public class UrlUtil { char nextChar = url.charAt(idx); boolean atEnd = (idx + 1) == url.length(); if (nextChar == '?' || nextChar == '/' || atEnd) { - int endIdx = atEnd ? idx + 1 : idx; + int endIdx = (atEnd && nextChar != '?') ? idx + 1 : idx; String nextSubstring = url.substring(nextStart, endIdx); if (retVal.getResourceType() == null) { retVal.setResourceType(nextSubstring); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronProvider.java index a48abde04b1..82997ef1327 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronProvider.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronProvider.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.validation.schematron; +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.lang.reflect.Constructor; import ca.uhn.fhir.context.FhirContext; diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/WebsocketSubscribeCommand.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/WebsocketSubscribeCommand.java index 82f762a7456..3f62b076604 100644 --- a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/WebsocketSubscribeCommand.java +++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/WebsocketSubscribeCommand.java @@ -8,6 +8,7 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame; @@ -100,8 +101,12 @@ public class WebsocketSubscribeCommand extends BaseCommand { @OnWebSocketFrame public void onFrame(Frame theFrame) { - ourLog.info("Websocket frame: {}", theFrame); - myQuit = true; + ourLog.debug("Websocket frame: {}", theFrame); + } + + @OnWebSocketClose + public void onClose(int statusCode, String reason) { + ourLog.info("Received CLOSE status={} reason={}", statusCode, reason); } @OnWebSocketConnect diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java index f7feb361d22..2b302234187 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.config; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu1Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu1Config.java index 78b24f7ec90..51a9b8aac30 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu1Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu1Config.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.config; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.List; import org.springframework.beans.factory.annotation.Autowire; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu2Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu2Config.java index d06555616fe..9fd9a5df70d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu2Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu2Config.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.config; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.springframework.beans.factory.annotation.Autowire; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/WebsocketDstu2Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/WebsocketDstu2Config.java index df988da814f..2e4ea229d30 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/WebsocketDstu2Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/WebsocketDstu2Config.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.config; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.springframework.beans.factory.annotation.Autowire; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index 570c416f71c..3a9292b9323 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -802,22 +802,7 @@ public abstract class BaseHapiFhirDao implements IDao { public static SearchParameterMap translateMatchUrl(String theMatchUrl, RuntimeResourceDefinition resourceDef) { SearchParameterMap paramMap = new SearchParameterMap(); - List parameters; - String matchUrl = theMatchUrl; - int questionMarkIndex = matchUrl.indexOf('?'); - if (questionMarkIndex != -1) { - matchUrl = matchUrl.substring(questionMarkIndex + 1); - } - matchUrl = matchUrl.replace("|", "%7C"); - matchUrl = matchUrl.replace("=>=", "=%3E%3D"); - matchUrl = matchUrl.replace("=<=", "=%3C%3D"); - matchUrl = matchUrl.replace("=>", "=%3E"); - matchUrl = matchUrl.replace("=<", "=%3C"); - if (matchUrl.contains(" ")) { - throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)"); - } - - parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&'); + List parameters = translateMatchUrl(theMatchUrl); ArrayListMultimap nameToParamLists = ArrayListMultimap.create(); for (NameValuePair next : parameters) { @@ -891,6 +876,26 @@ public abstract class BaseHapiFhirDao implements IDao { return paramMap; } + protected static List translateMatchUrl(String theMatchUrl) { + List parameters; + String matchUrl = theMatchUrl; + int questionMarkIndex = matchUrl.indexOf('?'); + if (questionMarkIndex != -1) { + matchUrl = matchUrl.substring(questionMarkIndex + 1); + } + matchUrl = matchUrl.replace("|", "%7C"); + matchUrl = matchUrl.replace("=>=", "=%3E%3D"); + matchUrl = matchUrl.replace("=<=", "=%3C%3D"); + matchUrl = matchUrl.replace("=>", "=%3E"); + matchUrl = matchUrl.replace("=<", "=%3C"); + if (matchUrl.contains(" ")) { + throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)"); + } + + parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&'); + return parameters; + } + @Override public void registerDaoListener(IDaoListener theListener) { Validate.notNull(theListener, "theListener"); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSearchParameterDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSearchParameterDstu2.java index 6f1210d209e..ecd483ea18d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSearchParameterDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSearchParameterDstu2.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.dao; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.apache.commons.lang3.time.DateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java index 235cc471b43..53707a0a4c8 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSearchDao.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.dao; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import static org.apache.commons.lang3.StringUtils.isNotBlank; import java.util.ArrayList; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java index 16f79a65a38..fd2c690e07f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java @@ -44,6 +44,7 @@ import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; +import ca.uhn.fhir.rest.method.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; @@ -59,7 +60,7 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao> { @Transactional(propagation = Propagation.REQUIRED) @Override - public List transaction(List theResources) { + public List transaction(RequestDetails theRequestDetails, List theResources) { ourLog.info("Beginning transaction with {} resources", theResources.size()); // Notify interceptors diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java index 1345274c576..da7c2077323 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java @@ -23,6 +23,7 @@ import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashSet; @@ -32,15 +33,19 @@ import java.util.Set; import javax.persistence.TypedQuery; +import org.apache.http.NameValuePair; import org.hl7.fhir.instance.model.api.IBaseResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; +import com.google.common.collect.ArrayListMultimap; + import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.jpa.entity.TagDefinition; import ca.uhn.fhir.model.api.IResource; @@ -57,13 +62,19 @@ import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; -import ca.uhn.fhir.rest.method.MethodUtil; +import ca.uhn.fhir.rest.method.BaseMethodBinding; +import ca.uhn.fhir.rest.method.BaseResourceReturningMethodBinding; +import ca.uhn.fhir.rest.method.BaseResourceReturningMethodBinding.ResourceOrDstu1Bundle; +import ca.uhn.fhir.rest.method.RequestDetails; import ca.uhn.fhir.rest.server.Constants; -import ca.uhn.fhir.rest.server.IBundleProvider; +import ca.uhn.fhir.rest.server.RestfulServerUtils; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.NotModifiedException; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.UrlUtil; @@ -83,12 +94,12 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { return url; } - private Bundle batch(Bundle theRequest) { + private Bundle batch(final RequestDetails theRequestDetails, Bundle theRequest) { ourLog.info("Beginning batch with {} resources", theRequest.getEntry().size()); long start = System.currentTimeMillis(); TransactionTemplate txTemplate = new TransactionTemplate(myTxManager); - txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW); + txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); Bundle resp = new Bundle(); resp.setType(BundleTypeEnum.BATCH_RESPONSE); @@ -96,8 +107,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { resp.addEntry().setResource(ooResp); /* - * For batch, we handle each entry as a mini-transaction in its own database transaction so that if one fails, it - * doesn't prevent others + * For batch, we handle each entry as a mini-transaction in its own database transaction so that if one fails, it doesn't prevent others */ for (final Entry nextRequestEntry : theRequest.getEntry()) { @@ -109,7 +119,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { subRequestBundle.setType(BundleTypeEnum.TRANSACTION); subRequestBundle.addEntry(nextRequestEntry); - Bundle subResponseBundle = transaction(subRequestBundle, "Batch sub-request"); + Bundle subResponseBundle = transaction(theRequestDetails, subRequestBundle, "Batch sub-request"); return subResponseBundle; } }; @@ -122,8 +132,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { Entry subResponseEntry = nextResponseBundle.getEntry().get(0); resp.addEntry(subResponseEntry); /* - * If the individual entry didn't have a resource in its response, bring the sub-transaction's - * OperationOutcome across so the client can see it + * If the individual entry didn't have a resource in its response, bring the sub-transaction's OperationOutcome across so the client can see it */ if (subResponseEntry.getResource() == null) { subResponseEntry.setResource(nextResponseBundle.getEntry().get(0).getResource()); @@ -173,19 +182,19 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { @Transactional(propagation = Propagation.REQUIRED) @Override - public Bundle transaction(Bundle theRequest) { + public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) { ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest); notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails); - String theActionName = "Transaction"; - return transaction(theRequest, theActionName); + String actionName = "Transaction"; + return transaction(theRequestDetails, theRequest, actionName); } @SuppressWarnings("unchecked") - private Bundle transaction(Bundle theRequest, String theActionName) { + private Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest, String theActionName) { BundleTypeEnum transactionType = theRequest.getTypeElement().getValueAsEnum(); if (transactionType == BundleTypeEnum.BATCH) { - return batch(theRequest); + return batch(theRequestDetails, theRequest); } if (transactionType == null) { @@ -222,7 +231,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { if (res != null) { nextResourceId = res.getId(); - + if (nextResourceId.hasIdPart() == false) { if (isNotBlank(nextEntry.getFullUrl())) { nextResourceId = new IdDt(nextEntry.getFullUrl()); @@ -232,7 +241,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { if (nextResourceId.hasIdPart() && nextResourceId.getIdPart().matches("[a-zA-Z]+\\:.*") && !isPlaceholder(nextResourceId)) { throw new InvalidRequestException("Invalid placeholder ID found: " + nextResourceId.getIdPart() + " - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'"); } - + if (nextResourceId.hasIdPart() && !nextResourceId.hasResourceType() && !isPlaceholder(nextResourceId)) { nextResourceId = new IdDt(toResourceName(res.getClass()), nextResourceId.getIdPart()); res.setId(nextResourceId); @@ -312,67 +321,67 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { } case GET: { // SEARCH/READ/VREAD + RequestDetails requestDetails = new RequestDetails(); + requestDetails.setServletRequest(theRequestDetails.getServletRequest()); + requestDetails.setRequestType(RequestTypeEnum.GET); + requestDetails.setServer(theRequestDetails.getServer()); + String url = extractTransactionUrlOrThrowException(nextEntry, verb); - UrlParts parts = UrlUtil.parseUrl(url); - - @SuppressWarnings("rawtypes") - IFhirResourceDao dao = toDao(parts, verb.getCode(), url); - - String ifNoneMatch = nextEntry.getRequest().getIfNoneMatch(); - if (isNotBlank(ifNoneMatch)) { - ifNoneMatch = MethodUtil.parseETagValue(ifNoneMatch); + + int qIndex = url.indexOf('?'); + ArrayListMultimap paramValues = ArrayListMultimap.create(); + requestDetails.setParameters(new HashMap()); + if (qIndex != -1) { + String params = url.substring(qIndex); + List parameters = translateMatchUrl(params); + for (NameValuePair next : parameters) { + paramValues.put(next.getName(), next.getValue()); + } + for (java.util.Map.Entry> nextParamEntry : paramValues.asMap().entrySet()) { + String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]); + requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue); + } + url = url.substring(0, qIndex); } - if (parts.getResourceId() != null && parts.getParams() == null) { - IResource found; - boolean notChanged = false; - if (parts.getVersionId() != null) { - if (isNotBlank(ifNoneMatch)) { - throw new InvalidRequestException("Unable to perform vread on '" + url + "' with ifNoneMatch also set. Do not include a version in the URL to perform a conditional read."); - } - found = (IResource) dao.read(new IdDt(parts.getResourceType(), parts.getResourceId(), parts.getVersionId())); - } else { - found = (IResource) dao.read(new IdDt(parts.getResourceType(), parts.getResourceId())); - if (isNotBlank(ifNoneMatch) && ifNoneMatch.equals(found.getId().getVersionIdPart())) { - notChanged = true; + requestDetails.setRequestPath(url); + requestDetails.setFhirServerBase(theRequestDetails.getFhirServerBase()); + + theRequestDetails.getServer().populateRequestDetailsFromRequestPath(requestDetails, url); + BaseMethodBinding method = theRequestDetails.getServer().determineResourceMethod(requestDetails, url); + if (method == null) { + throw new IllegalArgumentException("Unable to handle GET " + url); + } + + if (isNotBlank(nextEntry.getRequest().getIfMatch())) { + requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextEntry.getRequest().getIfMatch()); + } + if (isNotBlank(nextEntry.getRequest().getIfNoneExist())) { + requestDetails.addHeader(Constants.HEADER_IF_NONE_EXIST, nextEntry.getRequest().getIfNoneExist()); + } + if (isNotBlank(nextEntry.getRequest().getIfNoneMatch())) { + requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextEntry.getRequest().getIfNoneMatch()); + } + + if (method instanceof BaseResourceReturningMethodBinding) { + try { + ResourceOrDstu1Bundle responseData = ((BaseResourceReturningMethodBinding) method).invokeServer(theRequestDetails.getServer(), requestDetails, new byte[0]); + Entry newEntry = response.addEntry(); + IBaseResource resource = responseData.getResource(); + if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) { + resource = filterNestedBundle(requestDetails, resource); } + newEntry.setResource((IResource) resource); + newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK)); + } catch (NotModifiedException e) { + Entry newEntry = response.addEntry(); + newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED)); } - Entry entry = response.addEntry(); - if (notChanged == false) { - entry.setResource(found); - } - EntryResponse resp = entry.getResponse(); - resp.setLocation(found.getId().toUnqualified().getValue()); - resp.setEtag(found.getId().getVersionIdPart()); - if (!notChanged) { - resp.setStatus(toStatusString(Constants.STATUS_HTTP_200_OK)); - } else { - resp.setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED)); - } - } else if (parts.getParams() != null) { - RuntimeResourceDefinition def = getContext().getResourceDefinition(dao.getResourceType()); - SearchParameterMap params = translateMatchUrl(url, def); - IBundleProvider bundle = dao.search(params); - - Bundle searchBundle = new Bundle(); - searchBundle.setTotal(bundle.size()); - - int configuredMax = 200; // this should probably be configurable or something - if (bundle.size() > configuredMax) { - throw new InvalidRequestException("Search nested within transaction found more than " + configuredMax + " matches, but paging is not supported in nested transactions"); - } - List resourcesToAdd = bundle.getResources(0, Math.min(bundle.size(), configuredMax)); - for (IBaseResource next : resourcesToAdd) { - searchBundle.addEntry().setResource((IResource) next); - } - - Entry newEntry = response.addEntry(); - newEntry.setResource(searchBundle); - newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK)); + } else { + throw new IllegalArgumentException("Unable to handle GET " + url); } } } - } FhirTerser terser = getContext().newTerser(); @@ -416,7 +425,8 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { IFhirResourceDao resourceDao = getDao(nextEntry.getResource().getClass()); Set val = resourceDao.processMatchUrl(matchUrl); if (val.size() > 1) { - throw new InvalidRequestException("Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?"); + throw new InvalidRequestException( + "Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?"); } } } @@ -442,6 +452,20 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { return response; } + /** + * This method is called for nested bundles (e.g. if we received a transaction with an entry that + * was a GET search, this method is called on the bundle for the search result, that will be placed in the + * outer bundle). This method applies the _summary and _content parameters to the output of + * that bundle. + * + * TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future. + */ + private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) { + IParser p = getContext().newJsonParser(); + RestfulServerUtils.configureResponseParser(theRequestDetails, p); + return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource)); + } + private ca.uhn.fhir.jpa.dao.IFhirResourceDao toDao(UrlParts theParts, String theVerb, String theUrl) { RuntimeResourceDefinition resType; try { @@ -459,10 +483,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { throw new InvalidRequestException(msg); } - if (theParts.getResourceId() == null && theParts.getParams() == null) { - String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); - throw new InvalidRequestException(msg); - } + // if (theParts.getResourceId() == null && theParts.getParams() == null) { + // String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl); + // throw new InvalidRequestException(msg); + // } return dao; } @@ -475,15 +499,15 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { return retVal; } - private static void handleTransactionCreateOrUpdateOutcome(Map idSubstitutions, Map idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome, Entry newEntry, String theResourceType, IResource theRes) { + private static void handleTransactionCreateOrUpdateOutcome(Map idSubstitutions, Map idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome, + Entry newEntry, String theResourceType, IResource theRes) { IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless(); IdDt resourceId = isPlaceholder(nextResourceId) ? nextResourceId : nextResourceId.toUnqualifiedVersionless(); if (newId.equals(resourceId) == false) { idSubstitutions.put(resourceId, newId); if (isPlaceholder(resourceId)) { /* - * The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified - * kind too just to be lenient. + * The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified kind too just to be lenient. */ idSubstitutions.put(new IdDt(theResourceType + '/' + resourceId.getValue()), newId); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirSystemDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirSystemDao.java index cec8fca78dd..9e5c05a783a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirSystemDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirSystemDao.java @@ -25,6 +25,7 @@ import java.util.Map; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.dstu2.composite.MetaDt; +import ca.uhn.fhir.rest.method.RequestDetails; import ca.uhn.fhir.rest.server.IBundleProvider; /** @@ -58,6 +59,6 @@ public interface IFhirSystemDao extends IDao { */ MetaDt metaGetOperation(); - T transaction(T theResources); + T transaction(RequestDetails theRequestDetails, T theResources); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java index f273037aadb..9b52fa3c561 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchDao.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.dao; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.List; public interface ISearchDao { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaProvider.java index 3f3e9c9350a..22efc907338 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaProvider.java @@ -29,12 +29,23 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.jboss.logging.MDC; +import ca.uhn.fhir.rest.method.RequestDetails; + public class BaseJpaProvider { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaProvider.class); public static final String REMOTE_ADDR = "req.remoteAddr"; + public static final String REMOTE_UA = "req.userAgent"; - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaProvider.class); + public void endRequest(HttpServletRequest theRequest) { + MDC.remove(REMOTE_ADDR); + MDC.remove(REMOTE_UA); + } + + public void endRequest(RequestDetails theRequest) { + endRequest(theRequest.getServletRequest()); + } public void startRequest(HttpServletRequest theRequest) { if (theRequest == null) { @@ -49,13 +60,13 @@ public class BaseJpaProvider { Enumeration forwardedFors = theRequest.getHeaders("x-forwarded-for"); StringBuilder b = new StringBuilder(); - for (Enumeration enums = forwardedFors; enums.hasMoreElements();) { + for (Enumeration enums = forwardedFors; enums != null && enums.hasMoreElements();) { if (b.length() > 0) { b.append(" / "); } b.append(enums.nextElement()); } - + String forwardedFor = b.toString(); String ip = theRequest.getRemoteAddr(); if (StringUtils.isBlank(forwardedFor)) { @@ -68,12 +79,11 @@ public class BaseJpaProvider { String userAgent = StringUtils.defaultString(theRequest.getHeader("user-agent")); org.slf4j.MDC.put(REMOTE_UA, userAgent); - + } - public void endRequest(HttpServletRequest theRequest) { - MDC.remove(REMOTE_ADDR); - MDC.remove(REMOTE_UA); + public void startRequest(RequestDetails theRequest) { + startRequest(theRequest.getServletRequest()); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu1.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu1.java index 3b20234a2d1..e4f958d3757 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu1.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu1.java @@ -22,21 +22,20 @@ package ca.uhn.fhir.jpa.provider; import java.util.List; -import javax.servlet.http.HttpServletRequest; - import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.rest.annotation.Transaction; import ca.uhn.fhir.rest.annotation.TransactionParam; +import ca.uhn.fhir.rest.method.RequestDetails; public class JpaSystemProviderDstu1 extends BaseJpaSystemProvider> { @Transaction - public List transaction(HttpServletRequest theRequest, @TransactionParam List theResources) { - startRequest(theRequest); + public List transaction(RequestDetails theRequestDetails, @TransactionParam List theResources) { + startRequest(theRequestDetails); try { - return getDao().transaction(theResources); + return getDao().transaction(theRequestDetails, theResources); } finally { - endRequest(theRequest); + endRequest(theRequestDetails); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu2.java index e164cf34d40..61dd3473c9a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaSystemProviderDstu2.java @@ -40,6 +40,7 @@ import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.Transaction; import ca.uhn.fhir.rest.annotation.TransactionParam; +import ca.uhn.fhir.rest.method.RequestDetails; public class JpaSystemProviderDstu2 extends BaseJpaSystemProvider { @@ -182,12 +183,12 @@ public class JpaSystemProviderDstu2 extends BaseJpaSystemProvider { } @Transaction - public Bundle transaction(HttpServletRequest theRequest, @TransactionParam Bundle theResources) { - startRequest(theRequest); + public Bundle transaction(RequestDetails theRequestDetails, @TransactionParam Bundle theResources) { + startRequest(theRequestDetails); try { - return getDao().transaction(theResources); + return getDao().transaction(theRequestDetails, theResources); } finally { - endRequest(theRequest); + endRequest(theRequestDetails); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/IndexNonDeletedInterceptor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/IndexNonDeletedInterceptor.java index d960832fac2..e440cf65917 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/IndexNonDeletedInterceptor.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/IndexNonDeletedInterceptor.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.search; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.hibernate.search.indexes.interceptor.EntityIndexingInterceptor; import org.hibernate.search.indexes.interceptor.IndexingOverride; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionWebsocketHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionWebsocketHandler.java index 922ffc7668a..39f4ee4abdb 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionWebsocketHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionWebsocketHandler.java @@ -218,7 +218,9 @@ public class SubscriptionWebsocketHandler extends TextWebSocketHandler implement if (!id.hasIdPart() || !id.isIdPartValid()) { try { - theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - No ID included")); + String message = "Invalid bind request - No ID included"; + ourLog.warn(message); + theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), message)); } catch (IOException e) { handleFailure(e); } @@ -236,7 +238,9 @@ public class SubscriptionWebsocketHandler extends TextWebSocketHandler implement myState = new BoundStaticSubscipriptionState(theSession); } catch (ResourceNotFoundException e) { try { - theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - Unknown subscription: " + id.getValue())); + String message = "Invalid bind request - Unknown subscription: " + id.getValue(); + ourLog.warn(message); + theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), message)); } catch (IOException e1) { handleFailure(e); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/BigDecimalNumericFieldBridge.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/BigDecimalNumericFieldBridge.java index 444383addd1..97bafcc760e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/BigDecimalNumericFieldBridge.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/BigDecimalNumericFieldBridge.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.util; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.math.BigDecimal; import org.apache.lucene.document.Document; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java index 742711a7c7f..5ce08eeab7a 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java @@ -60,6 +60,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 { extraProperties.put("hibernate.format_sql", "true"); extraProperties.put("hibernate.show_sql", "false"); extraProperties.put("hibernate.hbm2ddl.auto", "update"); + extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect"); return extraProperties; } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java index 6fc5146a06c..1d4e35945a6 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java @@ -9,6 +9,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.io.InputStream; import java.io.InputStreamReader; @@ -21,10 +22,10 @@ import java.util.Map; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.config.TestDstu1Config; @@ -41,6 +42,7 @@ import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.rest.method.RequestDetails; import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; @@ -54,6 +56,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { private static IFhirResourceDao ourObservationDao; private static IFhirResourceDao ourPatientDao; private static IFhirSystemDao> ourSystemDao; + private RequestDetails myRequestDetails; @Test public void testGetResourceCounts() { @@ -140,7 +143,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01"); obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01")); - ourSystemDao.transaction(Arrays.asList((IResource) patient, obs)); + ourSystemDao.transaction(myRequestDetails, Arrays.asList((IResource) patient, obs)); String patientId = (patient.getId().getIdPart()); String obsId = (obs.getId().getIdPart()); @@ -169,7 +172,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02"); obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02"); - ourSystemDao.transaction(Arrays.asList((IResource) patient, obs)); + ourSystemDao.transaction(myRequestDetails, Arrays.asList((IResource) patient, obs)); String patientId2 = (patient.getId().getIdPart()); String patientVersion2 = (patient.getId().getVersionIdPart()); @@ -182,6 +185,11 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { assertEquals(obsVersion2, "2"); } + + @Before + public void before() { + myRequestDetails = mock(RequestDetails.class); + } @Test public void testPersistWithUnknownId() { @@ -190,7 +198,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { obs.setSubject(new ResourceReferenceDt("Patient/999998888888")); try { - ourSystemDao.transaction(Arrays.asList((IResource) obs)); + ourSystemDao.transaction(myRequestDetails, Arrays.asList((IResource) obs)); } catch (InvalidRequestException e) { assertThat(e.getMessage(), containsString("Resource Patient/999998888888 not found, specified in path: Observation.subject")); } @@ -200,7 +208,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { obs.setSubject(new ResourceReferenceDt("Patient/1.2.3.4")); try { - ourSystemDao.transaction(Arrays.asList((IResource) obs)); + ourSystemDao.transaction(myRequestDetails, Arrays.asList((IResource) obs)); } catch (InvalidRequestException e) { assertThat(e.getMessage(), containsString("Resource Patient/1.2.3.4 not found, specified in path: Observation.subject")); } @@ -290,7 +298,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds")); patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02"); - ourSystemDao.transaction(Arrays.asList((IResource) patient1, patient2)); + ourSystemDao.transaction(myRequestDetails, Arrays.asList((IResource) patient1, patient2)); } @Test @@ -300,7 +308,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { Bundle bundle = ourFhirContext.newXmlParser().parseBundle(new InputStreamReader(bundleRes)); List res = bundle.toListOfResources(); - ourSystemDao.transaction(res); + ourSystemDao.transaction(myRequestDetails, res); Patient p1 = (Patient) res.get(0); String id = p1.getId().getValue(); @@ -333,7 +341,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1")); res.add(o2); - ourSystemDao.transaction(res); + ourSystemDao.transaction(myRequestDetails, res); assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$")); assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$")); @@ -355,7 +363,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { res.add(next.getResource()); } - List response = ourSystemDao.transaction(res); + List response = ourSystemDao.transaction(myRequestDetails, res); String encodeResourceToString = ourFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(response.get(0)); ourLog.info(encodeResourceToString); @@ -388,7 +396,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { o2.setSubject(new ResourceReferenceDt("cid:patient1")); res.add(o2); - ourSystemDao.transaction(res); + ourSystemDao.transaction(myRequestDetails, res); assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$")); assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$")); @@ -421,7 +429,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { p3.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete"); res.add(p3); - ourSystemDao.transaction(res); + ourSystemDao.transaction(myRequestDetails, res); /* * Verify @@ -447,7 +455,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest { ResourceMetadataKeyEnum.DELETED_AT.put(p2, InstantDt.withCurrentTime()); res.add(p2); - ourSystemDao.transaction(res); + ourSystemDao.transaction(myRequestDetails, res); /* * Verify diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java index c2a4acc8257..e8692018115 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java @@ -14,28 +14,36 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; import java.util.List; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + import org.apache.commons.io.IOUtils; -import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; -import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum; import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.jpa.entity.TagTypeEnum; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; +import ca.uhn.fhir.jpa.rp.dstu2.PatientResourceProvider; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TagList; @@ -47,7 +55,6 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryRequest; import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryResponse; -import ca.uhn.fhir.model.dstu2.resource.Communication; import ca.uhn.fhir.model.dstu2.resource.Medication; import ca.uhn.fhir.model.dstu2.resource.MedicationOrder; import ca.uhn.fhir.model.dstu2.resource.Observation; @@ -58,11 +65,13 @@ import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum; import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum; import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum; import ca.uhn.fhir.model.primitive.IdDt; -import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; +import ca.uhn.fhir.rest.method.RequestDetails; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.IBundleProvider; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; @@ -72,14 +81,26 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetai public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2Test.class); + private RequestDetails myRequestDetails; + private RestfulServer myServer; @Test public void testTransactionFromBundle6() throws Exception { InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle3.xml"); String bundle = IOUtils.toString(bundleRes); - Bundle output = mySystemDao.transaction(myFhirCtx.newXmlParser().parseResource(Bundle.class, bundle)); + Bundle output = mySystemDao.transaction(myRequestDetails, myFhirCtx.newXmlParser().parseResource(Bundle.class, bundle)); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output)); } + + + @Test + public void testNestedCount() { + Patient p = new Patient(); + p.addName().addFamily("family"); + final IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); + + } + @Test public void testRendexing() { @@ -262,7 +283,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { o.getSubject().setReference("Patient/" + methodName); request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(2, resp.getEntry().size()); Entry respEntry = resp.getEntry().get(0); @@ -290,7 +311,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertEquals("Unable to process transaction where incoming Bundle.type = searchset", e.getMessage()); @@ -298,6 +319,27 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } + @SuppressWarnings("unchecked") + @Before + public void before() throws ServletException { + myRequestDetails = mock(RequestDetails.class); + + if (myServer == null) { + myServer = new RestfulServer(myFhirCtx); + + PatientResourceProvider patientRp = new PatientResourceProvider(); + patientRp.setDao(myPatientDao); + myServer.setResourceProviders(patientRp); + myServer.init(mock(ServletConfig.class)); + } + + when(myRequestDetails.getServer()).thenReturn(myServer); + HttpServletRequest servletRequest = mock(HttpServletRequest.class); + when(myRequestDetails.getServletRequest()).thenReturn(servletRequest); + when(servletRequest.getHeaderNames()).thenReturn(mock(Enumeration.class)); + when(servletRequest.getRequestURL()).thenReturn(new StringBuffer("/Patient")); + } + @Test public void testTransactionSingleEmptyResource() { @@ -307,7 +349,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertEquals("Unable to process transaction where incoming Bundle.type = searchset", e.getMessage()); @@ -327,7 +369,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient/THIS_ID_DOESNT_EXIST"); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(3, resp.getEntry().size()); assertEquals(BundleTypeEnum.BATCH_RESPONSE, resp.getTypeElement().getValueAsEnum()); @@ -377,7 +419,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertEquals(e.getMessage(), @@ -397,7 +439,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { try { entry.setIfNoneExist("Patient?identifier identifier" + methodName); - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertEquals("Failed to parse match URL[Patient?identifier identifiertestTransactionCreateWithInvalidMatchUrl] - URL is invalid (must not contain spaces)", e.getMessage()); @@ -405,7 +447,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { try { entry.setIfNoneExist("Patient?identifier="); - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertEquals("Invalid match URL[Patient?identifier=] - URL has no search parameters", e.getMessage()); @@ -413,7 +455,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { try { entry.setIfNoneExist("Patient?foo=bar"); - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertEquals("Failed to parse match URL[Patient?foo=bar] - Resource type Patient does not have a parameter with name: foo", e.getMessage()); @@ -435,7 +477,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertEquals(e.getMessage(), @@ -470,7 +512,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (PreconditionFailedException e) { assertThat(e.getMessage(), containsString("with match URL \"Patient")); @@ -493,7 +535,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { o.getSubject().setReference("Patient/" + methodName); request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(BundleTypeEnum.TRANSACTION_RESPONSE, resp.getTypeElement().getValueAsEnum()); assertEquals(2, resp.getEntry().size()); @@ -525,7 +567,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { p.setId("Patient/" + methodName); request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(1, resp.getEntry().size()); Entry respEntry = resp.getEntry().get(0); @@ -564,7 +606,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertThat(e.getMessage(), containsString("Resource Organization/9999999999999999 not found, specified in path: Patient.managingOrganization")); @@ -583,7 +625,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (InvalidRequestException e) { assertThat(e.getMessage(), containsString("Resource Organization/" + methodName + " not found, specified in path: Patient.managingOrganization")); @@ -613,7 +655,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { myPatientDao.read(id1.toVersionless()); myPatientDao.read(id2.toVersionless()); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(2, resp.getEntry().size()); assertEquals("204 No Content", resp.getEntry().get(0).getResponse().getStatus()); @@ -647,7 +689,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { Bundle request = new Bundle(); request.addEntry().getRequest().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(1, resp.getEntry().size()); Entry nextEntry = resp.getEntry().get(0); @@ -701,7 +743,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().getRequest().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (PreconditionFailedException e) { assertThat(e.getMessage(), containsString("resource with match URL \"Patient?")); @@ -716,7 +758,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().getRequest().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName); // try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); // fail(); // } catch (ResourceNotFoundException e) { // assertThat(e.getMessage(), containsString("resource matching URL \"Patient?")); @@ -736,7 +778,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { Bundle request = new Bundle(); request.addEntry().getRequest().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName); - Bundle res = mySystemDao.transaction(request); + Bundle res = mySystemDao.transaction(myRequestDetails, request); assertEquals(1, res.getEntry().size()); assertEquals(Constants.STATUS_HTTP_204_NO_CONTENT + " No Content", res.getEntry().get(0).getResponse().getStatus()); @@ -763,7 +805,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02"); request.addEntry().setResource(patient2).getRequest().setMethod(HTTPVerbEnum.POST); - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); } @Test @@ -773,7 +815,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { String bundleStr = IOUtils.toString(bundleRes); Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, bundleStr); - Bundle resp = mySystemDao.transaction(bundle); + Bundle resp = mySystemDao.transaction(myRequestDetails, bundle); ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp)); @@ -792,7 +834,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { String bundleStr = IOUtils.toString(bundleRes); Bundle bundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, bundleStr); - Bundle resp = mySystemDao.transaction(bundle); + Bundle resp = mySystemDao.transaction(myRequestDetails, bundle); ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp)); @@ -817,7 +859,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { ourLog.info("Request:\n"+myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); - Bundle outcome = mySystemDao.transaction(bundle); + Bundle outcome = mySystemDao.transaction(myRequestDetails, bundle); ourLog.info("Response:\n"+myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome)); IdDt medId1 = new IdDt(outcome.getEntry().get(0).getResponse().getLocation()); @@ -839,7 +881,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { mo.setMedication(new ResourceReferenceDt(medId)); bundle.addEntry().setResource(mo).setFullUrl(mo.getId().getValue()).getRequest().setMethod(HTTPVerbEnum.POST); - outcome = mySystemDao.transaction(bundle); + outcome = mySystemDao.transaction(myRequestDetails, bundle); IdDt medId2 = new IdDt(outcome.getEntry().get(0).getResponse().getLocation()); IdDt medOrderId2 = new IdDt(outcome.getEntry().get(1).getResponse().getLocation()); @@ -875,7 +917,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualified().getValue()); request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(3, resp.getEntry().size()); @@ -943,7 +985,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { Bundle request = new Bundle(); request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient?" + Constants.PARAM_COUNT + "=1"); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(1, resp.getEntry().size()); @@ -957,7 +999,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request = new Bundle(); request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient?" + Constants.PARAM_COUNT + "=GKJGKJG"); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); } catch (InvalidRequestException e) { assertEquals(e.getMessage(), ("Invalid _count value: GKJGKJG")); } @@ -966,7 +1008,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request = new Bundle(); request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient?" + Constants.PARAM_COUNT + "="); - respBundle = mySystemDao.transaction(request); + respBundle = mySystemDao.transaction(myRequestDetails, request); assertThat(respBundle.getEntry().size(), greaterThan(0)); } @@ -992,7 +1034,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()).setIfNoneMatch("W/\"" + idv1.getVersionIdPart() + "\""); request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue()).setIfNoneMatch("W/\"" + idv2.getVersionIdPart() + "\""); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(3, resp.getEntry().size()); @@ -1011,8 +1053,8 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { assertEquals("200 OK", nextEntry.getResponse().getStatus()); nextEntry = resp.getEntry().get(2); - assertNull(nextEntry.getResource()); assertEquals("304 Not Modified", nextEntry.getResponse().getStatus()); + assertNull(nextEntry.getResource()); } @Test @@ -1036,7 +1078,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { o.getSubject().setReference("Patient/" + methodName); request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(2, resp.getEntry().size()); Entry nextEntry = resp.getEntry().get(0); @@ -1083,7 +1125,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST); try { - mySystemDao.transaction(request); + mySystemDao.transaction(myRequestDetails, request); fail(); } catch (PreconditionFailedException e) { assertThat(e.getMessage(), containsString("with match URL \"Patient")); @@ -1110,7 +1152,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { o.getSubject().setReference("Patient/" + methodName); request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(2, resp.getEntry().size()); Entry nextEntry = resp.getEntry().get(0); @@ -1150,7 +1192,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { o.getSubject().setReference("Patient/" + methodName); request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST); - Bundle resp = mySystemDao.transaction(request); + Bundle resp = mySystemDao.transaction(myRequestDetails, request); assertEquals(2, resp.getEntry().size()); Entry nextEntry = resp.getEntry().get(0); @@ -1293,7 +1335,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { o2.setSubject(new ResourceReferenceDt("urn:oid:0.1.2.3")); res.addEntry().setResource(o2).getRequest().setMethod(HTTPVerbEnum.POST).setUrl("Observation"); - Bundle resp = mySystemDao.transaction(res); + Bundle resp = mySystemDao.transaction(myRequestDetails, res); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); @@ -1336,7 +1378,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { o2.setSubject(new ResourceReferenceDt("Patient/urn:oid:0.1.2.3")); res.addEntry().setResource(o2).getRequest().setMethod(HTTPVerbEnum.POST).setUrl("Observation"); - Bundle resp = mySystemDao.transaction(res); + Bundle resp = mySystemDao.transaction(myRequestDetails, res); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); @@ -1355,22 +1397,4 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2Test { } - static void doDeleteEverything(IFhirSystemDao systemDao) { - IBundleProvider all = systemDao.history(null); - List allRes = all.getResources(0, all.size()); - for (IBaseResource iResource : allRes) { - if (ResourceMetadataKeyEnum.DELETED_AT.get((IResource) iResource) == null) { - ourLog.info("Deleting: {}", iResource.getIdElement()); - - Bundle b = new Bundle(); - b.setType(BundleTypeEnum.TRANSACTION); - String url = iResource.getIdElement().toVersionless().getValue(); - b.addEntry().getRequest().setMethod(HTTPVerbEnum.DELETE).setUrl(url); - systemDao.transaction(b); - } - } - - systemDao.deleteAllTagsOnServer(); - } - } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderDstu2Test.java index cd6dba0bd76..0b5c23ba4b8 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderDstu2Test.java @@ -2,7 +2,12 @@ package ca.uhn.fhir.jpa.provider; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.InputStream; import java.util.concurrent.TimeUnit; @@ -16,29 +21,22 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.junit.AfterClass; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.config.TestDstu1Config; -import ca.uhn.fhir.jpa.config.TestDstu2Config; -import ca.uhn.fhir.jpa.dao.BaseJpaTest; -import ca.uhn.fhir.jpa.dao.IFhirResourceDao; +import ca.uhn.fhir.jpa.dao.BaseJpaDstu2Test; import ca.uhn.fhir.jpa.rp.dstu2.ObservationResourceProvider; import ca.uhn.fhir.jpa.rp.dstu2.OrganizationResourceProvider; import ca.uhn.fhir.jpa.rp.dstu2.PatientResourceProvider; import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider; -import ca.uhn.fhir.model.dstu2.resource.Observation; -import ca.uhn.fhir.model.dstu2.resource.Organization; -import ca.uhn.fhir.model.dstu2.resource.Patient; -import ca.uhn.fhir.model.dstu2.resource.Questionnaire; import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.OperationDefinition; import ca.uhn.fhir.model.dstu2.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum; +import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.server.EncodingEnum; @@ -46,18 +44,95 @@ import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor; -import net.sf.saxon.lib.OutputURIResolver; -public class SystemProviderDstu2Test extends BaseJpaTest { +public class SystemProviderDstu2Test extends BaseJpaDstu2Test { + private static RestfulServer myRestServer; + private static IGenericClient ourClient; + private static FhirContext ourCtx; + private static CloseableHttpClient ourHttpClient; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SystemProviderDstu2Test.class); private static Server ourServer; - private static AnnotationConfigApplicationContext ourAppCtx; - private static FhirContext ourCtx; - private static IGenericClient ourClient; private static String ourServerBase; - private static CloseableHttpClient ourHttpClient; - private static RestfulServer restServer; + + @Before + public void beforeStartServer() throws Exception { + if (myRestServer == null) { + PatientResourceProvider patientRp = new PatientResourceProvider(); + patientRp.setDao(myPatientDao); + + QuestionnaireResourceProviderDstu2 questionnaireRp = new QuestionnaireResourceProviderDstu2(); + questionnaireRp.setDao(myQuestionnaireDao); + + ObservationResourceProvider observationRp = new ObservationResourceProvider(); + observationRp.setDao(myObservationDao); + + OrganizationResourceProvider organizationRp = new OrganizationResourceProvider(); + organizationRp.setDao(myOrganizationDao); + + RestfulServer restServer = new RestfulServer(ourCtx); + restServer.setPagingProvider(new FifoMemoryPagingProvider(10).setDefaultPageSize(10)); + restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp); + + restServer.setPlainProviders(mySystemProvider); + + int myPort = RandomServerPortProvider.findFreePort(); + ourServer = new Server(myPort); + + ServletContextHandler proxyHandler = new ServletContextHandler(); + proxyHandler.setContextPath("/"); + + ourServerBase = "http://localhost:" + myPort + "/fhir/context"; + + ServletHolder servletHolder = new ServletHolder(); + servletHolder.setServlet(restServer); + proxyHandler.addServlet(servletHolder, "/fhir/context/*"); + + ourCtx = FhirContext.forDstu2(); + restServer.setFhirContext(ourCtx); + + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourHttpClient = builder.build(); + + ourCtx.getRestfulClientFactory().setSocketTimeout(600 * 1000); + ourClient = ourCtx.newRestfulGenericClient(ourServerBase); + ourClient.setLogRequestAndResponse(true); + myRestServer = restServer; + } + } + + @Test + public void testEverythingReturnsCorrectFormatInPagingLink() throws Exception { + myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON); + myRestServer.setPagingProvider(new FifoMemoryPagingProvider(1).setDefaultPageSize(10)); + ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor(); + myRestServer.registerInterceptor(interceptor); + + for (int i = 0; i < 11; i++) { + Patient p = new Patient(); + p.addName().addFamily("Name" + i); + ourClient.create().resource(p).execute(); + } + + HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything"); + get.addHeader("Accept", "application/xml, text/html"); + CloseableHttpResponse http = ourHttpClient.execute(get); + try { + String response = IOUtils.toString(http.getEntity().getContent()); + ourLog.info(response); + assertThat(response, not(containsString("_format"))); + assertEquals(200, http.getStatusLine().getStatusCode()); + } finally { + http.close(); + } + + myRestServer.unregisterInterceptor(interceptor); + } @Test public void testEverythingType() throws Exception { @@ -71,74 +146,9 @@ public class SystemProviderDstu2Test extends BaseJpaTest { } @Test - public void testEverythingReturnsCorrectFormatInPagingLink() throws Exception { - restServer.setDefaultResponseEncoding(EncodingEnum.JSON); - restServer.setPagingProvider(new FifoMemoryPagingProvider(1).setDefaultPageSize(10)); - ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor(); - restServer.registerInterceptor(interceptor); - - for (int i = 0; i < 11; i++) { - Patient p = new Patient(); - p.addName().addFamily("Name" + i); - ourClient.create().resource(p).execute(); - } - - HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything"); - get.addHeader("Accept", "application/xml, text/html"); - CloseableHttpResponse http = ourHttpClient.execute(get); - try { - String response = IOUtils.toString(http.getEntity().getContent()); - ourLog.info(response); - assertThat(response, not(containsString("_format"))); - assertEquals(200, http.getStatusLine().getStatusCode()); - } finally { - http.close(); - } - - restServer.unregisterInterceptor(interceptor); - } - - @Test - public void testTransactionFromBundle4() throws Exception { - InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle.xml"); - String bundle = IOUtils.toString(bundleRes); - String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute(); - ourLog.info(response); - Bundle bundleResp = ourCtx.newXmlParser().parseResource(Bundle.class, response); - IdDt id = new IdDt(bundleResp.getEntry().get(0).getResponse().getLocation()); - assertEquals("Patient", id.getResourceType()); - assertTrue(id.hasIdPart()); - assertTrue(id.isIdPartValidLong()); - assertTrue(id.hasVersionIdPart()); - assertTrue(id.isVersionIdPartValidLong()); - } - - @Test - public void testTransactionFromBundle5() throws Exception { - InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle2.xml"); - String bundle = IOUtils.toString(bundleRes); - try { - ourClient.transaction().withBundle(bundle).prettyPrint().execute(); - fail(); - } catch (InvalidRequestException e) { - OperationOutcome oo = (OperationOutcome) e.getOperationOutcome(); - assertEquals("Invalid placeholder ID found: uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'", oo.getIssue().get(0).getDiagnostics()); - assertEquals("processing", oo.getIssue().get(0).getCode()); - } - } - - @Test - public void testTransactionFromBundle6() throws Exception { - InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle3.xml"); - String bundle = IOUtils.toString(bundleRes); - ourClient.transaction().withBundle(bundle).prettyPrint().execute(); -// try { -// fail(); -// } catch (InvalidRequestException e) { -// OperationOutcome oo = (OperationOutcome) e.getOperationOutcome(); -// assertEquals("Invalid placeholder ID found: uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'", oo.getIssue().get(0).getDiagnostics()); -// assertEquals("processing", oo.getIssue().get(0).getCode()); -// } + public void testGetOperationDefinition() { + OperationDefinition op = ourClient.read(OperationDefinition.class, "get-resource-counts"); + assertEquals("$get-resource-counts", op.getCode()); } @Test @@ -149,24 +159,6 @@ public class SystemProviderDstu2Test extends BaseJpaTest { ourLog.info(response); } - /** - * This is Gramahe's test transaction - it requires some set up in order to work - */ - // @Test - public void testTransactionFromBundle3() throws Exception { - - InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/grahame-transaction.xml"); - String bundle = IOUtils.toString(bundleRes); - String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute(); - ourLog.info(response); - } - - @Test - public void testGetOperationDefinition() { - OperationDefinition op = ourClient.read(OperationDefinition.class, "get-resource-counts"); - assertEquals("$get-resource-counts", op.getCode()); - } - @Test public void testTransactionFromBundle2() throws Exception { @@ -204,65 +196,108 @@ public class SystemProviderDstu2Test extends BaseJpaTest { assertEquals(id1_4.toVersionless(), id2_4.toVersionless()); } + /** + * This is Gramahe's test transaction - it requires some set up in order to work + */ + // @Test + public void testTransactionFromBundle3() throws Exception { + + InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/grahame-transaction.xml"); + String bundle = IOUtils.toString(bundleRes); + String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute(); + ourLog.info(response); + } + + @Test + public void testTransactionFromBundle4() throws Exception { + InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle.xml"); + String bundle = IOUtils.toString(bundleRes); + String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute(); + ourLog.info(response); + Bundle bundleResp = ourCtx.newXmlParser().parseResource(Bundle.class, response); + IdDt id = new IdDt(bundleResp.getEntry().get(0).getResponse().getLocation()); + assertEquals("Patient", id.getResourceType()); + assertTrue(id.hasIdPart()); + assertTrue(id.isIdPartValidLong()); + assertTrue(id.hasVersionIdPart()); + assertTrue(id.isVersionIdPartValidLong()); + } + + @Test + public void testTransactionFromBundle5() throws Exception { + InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle2.xml"); + String bundle = IOUtils.toString(bundleRes); + try { + ourClient.transaction().withBundle(bundle).prettyPrint().execute(); + fail(); + } catch (InvalidRequestException e) { + OperationOutcome oo = (OperationOutcome) e.getOperationOutcome(); + assertEquals("Invalid placeholder ID found: uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'", oo.getIssue().get(0).getDiagnostics()); + assertEquals("processing", oo.getIssue().get(0).getCode()); + } + } + + @Test + public void testTransactionFromBundle6() throws Exception { + InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle3.xml"); + String bundle = IOUtils.toString(bundleRes); + ourClient.transaction().withBundle(bundle).prettyPrint().execute(); + // try { + // fail(); + // } catch (InvalidRequestException e) { + // OperationOutcome oo = (OperationOutcome) e.getOperationOutcome(); + // assertEquals("Invalid placeholder ID found: uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'", oo.getIssue().get(0).getDiagnostics()); + // assertEquals("processing", oo.getIssue().get(0).getCode()); + // } + } + + @Test + public void testTransactionSearch() throws Exception { + for (int i = 0; i < 20; i ++) { + Patient p = new Patient(); + p.addName().addFamily("PATIENT_" + i); + myPatientDao.create(p); + } + + Bundle req = new Bundle(); + req.setType(BundleTypeEnum.TRANSACTION); + req.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient?"); + Bundle resp = ourClient.transaction().withBundle(req).execute(); + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); + + assertEquals(1, resp.getEntry().size()); + Bundle respSub = (Bundle)resp.getEntry().get(0).getResource(); + assertEquals("self", respSub.getLink().get(0).getRelation()); + assertEquals(ourServerBase + "/Patient", respSub.getLink().get(0).getUrl()); + assertEquals("next", respSub.getLink().get(1).getRelation()); + assertThat(respSub.getLink().get(1).getUrl(), containsString("/fhir/context?_getpages")); + assertThat(respSub.getEntry().get(0).getFullUrl(), startsWith(ourServerBase + "/Patient/")); + assertEquals(Patient.class, respSub.getEntry().get(0).getResource().getClass()); + } + + @Test + public void testTransactionCount() throws Exception { + for (int i = 0; i < 20; i ++) { + Patient p = new Patient(); + p.addName().addFamily("PATIENT_" + i); + myPatientDao.create(p); + } + + Bundle req = new Bundle(); + req.setType(BundleTypeEnum.TRANSACTION); + req.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient?_summary=count"); + Bundle resp = ourClient.transaction().withBundle(req).execute(); + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); + + assertEquals(1, resp.getEntry().size()); + Bundle respSub = (Bundle)resp.getEntry().get(0).getResource(); + assertEquals(20, respSub.getTotal().intValue()); + assertEquals(0, respSub.getEntry().size()); + } + @AfterClass public static void afterClass() throws Exception { ourServer.stop(); - ourAppCtx.stop(); - } - - @SuppressWarnings("unchecked") - @BeforeClass - public static void beforeClass() throws Exception { - ourAppCtx = new AnnotationConfigApplicationContext(TestDstu2Config.class); - - IFhirResourceDao patientDao = (IFhirResourceDao) ourAppCtx.getBean("myPatientDaoDstu2", IFhirResourceDao.class); - PatientResourceProvider patientRp = new PatientResourceProvider(); - patientRp.setDao(patientDao); - - IFhirResourceDao questionnaireDao = (IFhirResourceDao) ourAppCtx.getBean("myQuestionnaireDaoDstu2", IFhirResourceDao.class); - QuestionnaireResourceProviderDstu2 questionnaireRp = new QuestionnaireResourceProviderDstu2(); - questionnaireRp.setDao(questionnaireDao); - - IFhirResourceDao observationDao = (IFhirResourceDao) ourAppCtx.getBean("myObservationDaoDstu2", IFhirResourceDao.class); - ObservationResourceProvider observationRp = new ObservationResourceProvider(); - observationRp.setDao(observationDao); - - IFhirResourceDao organizationDao = (IFhirResourceDao) ourAppCtx.getBean("myOrganizationDaoDstu2", IFhirResourceDao.class); - OrganizationResourceProvider organizationRp = new OrganizationResourceProvider(); - organizationRp.setDao(organizationDao); - - restServer = new RestfulServer(ourCtx); - restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp); - - JpaSystemProviderDstu2 systemProv = ourAppCtx.getBean(JpaSystemProviderDstu2.class, "mySystemProviderDstu2"); - restServer.setPlainProviders(systemProv); - - int myPort = RandomServerPortProvider.findFreePort(); - ourServer = new Server(myPort); - - ServletContextHandler proxyHandler = new ServletContextHandler(); - proxyHandler.setContextPath("/"); - - ourServerBase = "http://localhost:" + myPort + "/fhir/context"; - - ServletHolder servletHolder = new ServletHolder(); - servletHolder.setServlet(restServer); - proxyHandler.addServlet(servletHolder, "/fhir/context/*"); - - ourCtx = FhirContext.forDstu2(); - restServer.setFhirContext(ourCtx); - - ourServer.setHandler(proxyHandler); - ourServer.start(); - - PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); - HttpClientBuilder builder = HttpClientBuilder.create(); - builder.setConnectionManager(connectionManager); - ourHttpClient = builder.build(); - - ourCtx.getRestfulClientFactory().setSocketTimeout(600 * 1000); - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); - ourClient.setLogRequestAndResponse(true); } } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu1.xml_ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu1.xml_ deleted file mode 100644 index 5acd1694112..00000000000 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu1.xml_ +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - ca.uhn.fhir.jpa.entity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu2.xml_ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu2.xml_ deleted file mode 100644 index 9c14d15cbc9..00000000000 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu2.xml_ +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - ca.uhn.fhir.jpa.entity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java index 15c16ae9514..c525cf03b09 100644 --- a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java @@ -2,7 +2,7 @@ package ca.uhn.fhir.rest.server; /* * #%L - * HAPI FHIR - Core Library + * HAPI FHIR Structures - DSTU1 (FHIR v0.80) * %% * Copyright (C) 2014 - 2015 University Health Network * %% diff --git a/hapi-fhir-testpage-overlay/src/main/webapp/WEB-INF/templates/tmpl-navbar-top.html b/hapi-fhir-testpage-overlay/src/main/webapp/WEB-INF/templates/tmpl-navbar-top.html index 7efd7b63486..4bdc287ed34 100644 --- a/hapi-fhir-testpage-overlay/src/main/webapp/WEB-INF/templates/tmpl-navbar-top.html +++ b/hapi-fhir-testpage-overlay/src/main/webapp/WEB-INF/templates/tmpl-navbar-top.html @@ -11,7 +11,7 @@ - HAPI FHIR + Home