Skip to content

Commit

Permalink
Allow plain server @operation methods to declare a wildcard so that any
Browse files Browse the repository at this point in the history
opeeration invocations will be direected to them
  • Loading branch information
jamesagnew committed Oct 29, 2018
1 parent 794d914 commit b66e01c
Show file tree
Hide file tree
Showing 28 changed files with 982 additions and 591 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
* 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.
Expand All @@ -20,15 +20,14 @@
* #L%
*/

import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import org.hl7.fhir.instance.model.api.IBaseResource;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.hl7.fhir.instance.model.api.IBaseResource;

import ca.uhn.fhir.model.valueset.BundleTypeEnum;

/**
* RESTful method annotation used for a method which provides FHIR "operations".
*/
Expand All @@ -37,10 +36,18 @@
public @interface Operation {

/**
* The name of the operation, e.g. "<code>$everything</code>"
*
* This constant is a special return value for {@link #name()}. If this name is
* used, the given operation method will match all operation calls. This is
* generally not desirable, but can be useful if you have a server that should
* dynamically match any FHIR operations that are requested.
*/
String NAME_MATCH_ALL = "*";

/**
* The name of the operation, e.g. "<code>$everything</code>"
*
* <p>
* This may be specified with or without a leading
* This may be specified with or without a leading
* '$'. (If the leading '$' is omitted, it will be added internally by the API).
* </p>
*/
Expand All @@ -61,10 +68,10 @@
* (meaning roughly that it does not modify any data or state on the server)
* then this flag should be set to <code>true</code> (default is <code>false</code>).
* <p>
* One the server, setting this to <code>true</code> means that the
* One the server, setting this to <code>true</code> means that the
* server will allow the operation to be invoked using an <code>HTTP GET</code>
* (on top of the standard <code>HTTP POST</code>)
* </p>
* </p>
*/
boolean idempotent() default false;

Expand All @@ -73,9 +80,9 @@
* response to this operation.
*/
OperationParam[] returnParameters() default {};

/**
* If this operation returns a bundle, this parameter can be used to specify the
* If this operation returns a bundle, this parameter can be used to specify the
* bundle type to set in the bundle.
*/
BundleTypeEnum bundleType() default BundleTypeEnum.COLLECTION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public static void clearAllStaticFieldsForUnitTest() {
* environment
*/
public static void randomizeLocale() {
Locale[] availableLocales = {Locale.CANADA, Locale.GERMANY, Locale.TAIWAN};
Locale[] availableLocales = {Locale.CANADA, Locale.GERMANY, Locale.TAIWAN};
Locale.setDefault(availableLocales[(int) (Math.random() * availableLocales.length)]);
ourLog.info("Tests are running in locale: " + Locale.getDefault().getDisplayName());
if (Math.random() < 0.5) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,6 @@ protected void sendToProcessingChannel(final ResourceModifiedMessage theMessage)
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// FIXME: remove
ourLog.info("** Sending processing message " + theMessage + " for: " + theMessage.getNewPayload(myCtx));
ourLog.trace("Sending resource modified message to processing channel");
getProcessingChannel().send(new ResourceModifiedJsonMessage(theMessage));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@ protected void doDelivery(ResourceDeliveryMessage theMsg, CanonicalSubscription
operation.encoded(thePayloadType);
}

// FIXME: remove
ourLog.info("** This " + this + " Processing delivery message " + theMsg);


ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), thePayloadResource.getIdElement().toUnqualified().getValue(), theSubscription.getIdElement(getContext()).toUnqualifiedVersionless().getValue());

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ protected List<IIdType> toUnqualifiedVersionlessIds(IBundleProvider theProvider)
return retVal;
}

protected List<IIdType> toUnqualifiedVersionlessIds(List<IBaseResource> theFound) {
protected List<IIdType> toUnqualifiedVersionlessIds(List<? extends IBaseResource> theFound) {
List<IIdType> retVal = new ArrayList<IIdType>();
for (IBaseResource next : theFound) {
retVal.add(next.getIdElement().toUnqualifiedVersionless());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1613,16 +1613,18 @@ public void testSearchResourceLinkWithChainWithMultipleTypes() throws Exception
obs01.setSubject(new Reference(patientId01));
IIdType obsId01 = myObservationDao.create(obs01, mySrd).getId().toUnqualifiedVersionless();

ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
Date between = new Date();
Thread.sleep(10);
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);

Observation obs02 = new Observation();
obs02.setEffective(new DateTimeType(new Date()));
obs02.setSubject(new Reference(locId01));
IIdType obsId02 = myObservationDao.create(obs02, mySrd).getId().toUnqualifiedVersionless();

Thread.sleep(10);
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
Date after = new Date();
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);

ourLog.info("P1[{}] L1[{}] Obs1[{}] Obs2[{}]", new Object[] { patientId01, locId01, obsId01, obsId02 });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2865,16 +2865,22 @@ public void testSortByLastUpdated() {
p.addName().setFamily(methodName);
IIdType id1 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();

ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);

p = new Patient();
p.addIdentifier().setSystem("urn:system2").setValue(methodName);
p.addName().setFamily(methodName);
IIdType id2 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();

ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);

p = new Patient();
p.addIdentifier().setSystem("urn:system3").setValue(methodName);
p.addName().setFamily(methodName);
IIdType id3 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();

ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);

p = new Patient();
p.addIdentifier().setSystem("urn:system4").setValue(methodName);
p.addName().setFamily(methodName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ public void testRestHookSubscriptionXml() throws Exception {
waitForSize(0, ourCreatedObservations);
waitForSize(5, ourUpdatedObservations);

ourLog.info("Have observations: {}", toUnqualifiedVersionlessIds(ourUpdatedObservations));

Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
Assert.assertFalse(observation1.getId().isEmpty());
Assert.assertFalse(observation2.getId().isEmpty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ protected void doPut(HttpServletRequest request, HttpServletResponse response) t
/**
* Count length of URL string, but treating unescaped sequences (e.g. ' ') as their unescaped equivalent (%20)
*/
protected int escapedLength(String theServletPath) {
protected static int escapedLength(String theServletPath) {
int delta = 0;
for (int i = 0; i < theServletPath.length(); i++) {
char next = theServletPath.charAt(i);
Expand Down Expand Up @@ -564,6 +564,20 @@ public List<IServerInterceptor> getInterceptors() {
return Collections.unmodifiableList(myInterceptors);
}

/**
* Sets (or clears) the list of interceptors
*
* @param theInterceptors The list of interceptors (may be null)
*/
public void setInterceptors(IServerInterceptor... theInterceptors) {
Validate.noNullElements(theInterceptors, "theInterceptors must not contain any null elements");

myInterceptors.clear();
if (theInterceptors != null) {
myInterceptors.addAll(Arrays.asList(theInterceptors));
}
}

/**
* Sets (or clears) the list of interceptors
*
Expand Down Expand Up @@ -597,6 +611,20 @@ public Collection<Object> getPlainProviders() {
return myPlainProviders;
}

/**
* Sets the non-resource specific providers which implement method calls on this server.
*
* @see #setResourceProviders(Collection)
*/
public void setPlainProviders(Collection<Object> theProviders) {
Validate.noNullElements(theProviders, "theProviders must not contain any null elements");

myPlainProviders.clear();
if (theProviders != null) {
myPlainProviders.addAll(theProviders);
}
}

/**
* Sets the non-resource specific providers which implement method calls on this server.
*
Expand All @@ -615,7 +643,7 @@ public void setPlainProviders(Object... theProv) {
* @param servletPath the servelet path
* @return created resource path
*/
protected String getRequestPath(String requestFullPath, String servletContextPath, String servletPath) {
protected static String getRequestPath(String requestFullPath, String servletContextPath, String servletPath) {
return requestFullPath.substring(escapedLength(servletContextPath) + escapedLength(servletPath));
}

Expand All @@ -630,6 +658,18 @@ public Collection<IResourceProvider> getResourceProviders() {
return myResourceProviders;
}

/**
* Sets the resource providers for this server
*/
public void setResourceProviders(Collection<IResourceProvider> theProviders) {
Validate.noNullElements(theProviders, "theProviders must not contain any null elements");

myResourceProviders.clear();
if (theProviders != null) {
myResourceProviders.addAll(theProviders);
}
}

/**
* Sets the resource providers for this server
*/
Expand Down Expand Up @@ -1521,34 +1561,6 @@ protected void service(HttpServletRequest theReq, HttpServletResponse theResp) t
}
}

/**
* Sets (or clears) the list of interceptors
*
* @param theInterceptors The list of interceptors (may be null)
*/
public void setInterceptors(IServerInterceptor... theInterceptors) {
Validate.noNullElements(theInterceptors, "theInterceptors must not contain any null elements");

myInterceptors.clear();
if (theInterceptors != null) {
myInterceptors.addAll(Arrays.asList(theInterceptors));
}
}

/**
* Sets the non-resource specific providers which implement method calls on this server.
*
* @see #setResourceProviders(Collection)
*/
public void setPlainProviders(Collection<Object> theProviders) {
Validate.noNullElements(theProviders, "theProviders must not contain any null elements");

myPlainProviders.clear();
if (theProviders != null) {
myPlainProviders.addAll(theProviders);
}
}

/**
* Sets the non-resource specific providers which implement method calls on this server
*
Expand All @@ -1563,18 +1575,6 @@ public void setProviders(Object... theProviders) {
}
}

/**
* Sets the resource providers for this server
*/
public void setResourceProviders(Collection<IResourceProvider> theProviders) {
Validate.noNullElements(theProviders, "theProviders must not contain any null elements");

myResourceProviders.clear();
if (theProviders != null) {
myResourceProviders.addAll(theProviders);
}
}

/**
* If provided (default is <code>null</code>), the tenant identification
* strategy provides a mechanism for a multitenant server to identify which tenant
Expand All @@ -1585,7 +1585,8 @@ public void setTenantIdentificationStrategy(ITenantIdentificationStrategy theTen
}

protected void throwUnknownFhirOperationException(RequestDetails requestDetails, String requestPath, RequestTypeEnum theRequestType) {
throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "unknownMethod", theRequestType.name(), requestPath, requestDetails.getParameters().keySet()));
FhirContext fhirContext = myFhirContext;
throwUnknownFhirOperationException(requestDetails, requestPath, theRequestType, fhirContext);
}

protected void throwUnknownResourceTypeException(String theResourceName) {
Expand Down Expand Up @@ -1647,6 +1648,10 @@ private void writeExceptionToResponse(HttpServletResponse theResponse, BaseServe
theResponse.getWriter().write(theException.getMessage());
}

public static void throwUnknownFhirOperationException(RequestDetails requestDetails, String requestPath, RequestTypeEnum theRequestType, FhirContext theFhirContext) {
throw new InvalidRequestException(theFhirContext.getLocalizer().getMessage(RestfulServer.class, "unknownMethod", theRequestType.name(), requestPath, requestDetails.getParameters().keySet()));
}

private static boolean partIsOperation(String nextString) {
return nextString.length() > 0 && (nextString.charAt(0) == '_' || nextString.charAt(0) == '$' || nextString.equals(Constants.URL_TOKEN_METADATA));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
* 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -223,6 +224,7 @@ public Set<Include> getRequestIncludesFromParams(Object[] params) {
*/
public abstract String getResourceName();

@Nonnull
public abstract RestOperationTypeEnum getRestOperationType();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;

import javax.annotation.Nonnull;

public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding {

public ConformanceMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
Expand Down Expand Up @@ -86,6 +88,7 @@ public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
return false;
}

@Nonnull
@Override
public RestOperationTypeEnum getRestOperationType() {
return RestOperationTypeEnum.METADATA;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

import javax.annotation.Nonnull;

public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {

public CreateMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
Expand All @@ -47,6 +49,7 @@ protected String getMatchingOperation() {
return null;
}

@Nonnull
@Override
public RestOperationTypeEnum getRestOperationType() {
return RestOperationTypeEnum.CREATE;
Expand Down

0 comments on commit b66e01c

Please sign in to comment.