Work on subscription

This commit is contained in:
jamesagnew 2018-08-11 16:14:53 -04:00
parent 6d10260d8f
commit 7eb36c3392
4 changed files with 25 additions and 214 deletions

View File

@ -25,7 +25,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.provider.AbstractHashMapResourceProvider;
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
import com.google.common.base.Charsets;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
@ -42,7 +42,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
/**
* This is a subclass to implement FHIR operations specific to DSTU3 ConceptMap
* resources. Its superclass, {@link AbstractHashMapResourceProvider}, is a simple
* resources. Its superclass, {@link HashMapResourceProvider}, is a simple
* implementation of the resource provider interface that uses a HashMap to
* store all resources in memory.
* <p>
@ -53,7 +53,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* <li>Conditional update for DSTU3 ConceptMap resources by ConceptMap.url</li>
* </ul>
*/
public class HashMapResourceProviderConceptMapDstu3 extends AbstractHashMapResourceProvider<ConceptMap> {
public class HashMapResourceProviderConceptMapDstu3 extends HashMapResourceProvider<ConceptMap> {
@SuppressWarnings("unchecked")
public HashMapResourceProviderConceptMapDstu3(FhirContext theFhirContext) {
super(theFhirContext, ConceptMap.class);
@ -84,10 +84,10 @@ public class HashMapResourceProviderConceptMapDstu3 extends AbstractHashMapResou
return retVal;
}
@Override
@Update
public MethodOutcome updateConceptMapConditional(
public MethodOutcome update(
@ResourceParam ConceptMap theConceptMap,
@IdParam IdType theId,
@ConditionalUrlParam String theConditional) {
MethodOutcome methodOutcome = new MethodOutcome();
@ -112,14 +112,14 @@ public class HashMapResourceProviderConceptMapDstu3 extends AbstractHashMapResou
List<ConceptMap> conceptMaps = searchByUrl(url);
if (!conceptMaps.isEmpty()) {
methodOutcome = update(conceptMaps.get(0));
methodOutcome = super.update(conceptMaps.get(0), null);
} else {
methodOutcome = create(theConceptMap);
}
}
} else {
methodOutcome = update(theConceptMap);
methodOutcome = super.update(theConceptMap, null);
}
return methodOutcome;

View File

@ -25,7 +25,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.provider.AbstractHashMapResourceProvider;
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
import com.google.common.base.Charsets;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
@ -42,7 +42,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
/**
* This is a subclass to implement FHIR operations specific to R4 ConceptMap
* resources. Its superclass, {@link AbstractHashMapResourceProvider}, is a simple
* resources. Its superclass, {@link HashMapResourceProvider}, is a simple
* implementation of the resource provider interface that uses a HashMap to
* store all resources in memory.
* <p>
@ -53,7 +53,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* <li>Conditional update for R4 ConceptMap resources by ConceptMap.url</li>
* </ul>
*/
public class HashMapResourceProviderConceptMapR4 extends AbstractHashMapResourceProvider<ConceptMap> {
public class HashMapResourceProviderConceptMapR4 extends HashMapResourceProvider<ConceptMap> {
@SuppressWarnings("unchecked")
public HashMapResourceProviderConceptMapR4(FhirContext theFhirContext) {
super(theFhirContext, ConceptMap.class);
@ -84,16 +84,15 @@ public class HashMapResourceProviderConceptMapR4 extends AbstractHashMapResource
return retVal;
}
@Override
@Update
public MethodOutcome updateConceptMapConditional(
public MethodOutcome update(
@ResourceParam ConceptMap theConceptMap,
@IdParam IdType theId,
@ConditionalUrlParam String theConditional) {
MethodOutcome methodOutcome = new MethodOutcome();
if (theConditional != null) {
String url = null;
try {
@ -112,14 +111,14 @@ public class HashMapResourceProviderConceptMapR4 extends AbstractHashMapResource
List<ConceptMap> conceptMaps = searchByUrl(url);
if (!conceptMaps.isEmpty()) {
methodOutcome = update(conceptMaps.get(0));
methodOutcome = super.update(conceptMaps.get(0), null);
} else {
methodOutcome = create(theConceptMap);
}
}
} else {
methodOutcome = update(theConceptMap);
methodOutcome = super.update(theConceptMap, null);
}
return methodOutcome;

View File

@ -1,198 +0,0 @@
package ca.uhn.fhir.rest.server.provider;
/*-
* #%L
* HAPI FHIR - Server Framework
* %%
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* This class is a simple implementation of the resource provider
* interface that uses a HashMap to store all resources in memory.
* It is essentially a copy of {@link ca.uhn.fhir.rest.server.provider.HashMapResourceProvider}
* with the {@link Update} and {@link ResourceParam} annotations removed from method
* {@link ca.uhn.fhir.rest.server.provider.HashMapResourceProvider#update(IBaseResource)}.
* Non-generic subclasses of this abstract class may implement their own annotated methods (e.g. a conditional
* update method specifically for ConceptMap resources).
* <p>
* This class currently supports the following FHIR operations:
* </p>
* <ul>
* <li>Create</li>
* <li>Update existing resource</li>
* <li>Update non-existing resource (e.g. create with client-supplied ID)</li>
* <li>Delete</li>
* <li>Search by resource type with no parameters</li>
* </ul>
*
* @param <T> The resource type to support
*/
public class AbstractHashMapResourceProvider<T extends IBaseResource> implements IResourceProvider {
private static final Logger ourLog = LoggerFactory.getLogger(AbstractHashMapResourceProvider.class);
private final Class<T> myResourceType;
private final FhirContext myFhirContext;
private final String myResourceName;
protected Map<String, TreeMap<Long, T>> myIdToVersionToResourceMap = new HashMap<>();
private long myNextId;
/**
* Constructor
*
* @param theFhirContext The FHIR context
* @param theResourceType The resource type to support
*/
@SuppressWarnings("WeakerAccess")
public AbstractHashMapResourceProvider(FhirContext theFhirContext, Class<T> theResourceType) {
myFhirContext = theFhirContext;
myResourceType = theResourceType;
myResourceName = myFhirContext.getResourceDefinition(theResourceType).getName();
clear();
}
/**
* Clear all data held in this resource provider
*/
public void clear() {
myNextId = 1;
myIdToVersionToResourceMap.clear();
}
@Create
public MethodOutcome create(@ResourceParam T theResource) {
long idPart = myNextId++;
String idPartAsString = Long.toString(idPart);
Long versionIdPart = 1L;
IIdType id = store(theResource, idPartAsString, versionIdPart);
return new MethodOutcome()
.setCreated(true)
.setId(id);
}
@Delete
public MethodOutcome delete(@IdParam IIdType theId) {
TreeMap<Long, T> versions = myIdToVersionToResourceMap.get(theId.getIdPart());
if (versions == null || versions.isEmpty()) {
throw new ResourceNotFoundException(theId);
}
long nextVersion = versions.lastEntry().getKey() + 1L;
IIdType id = store(null, theId.getIdPart(), nextVersion);
return new MethodOutcome()
.setId(id);
}
@Override
public Class<? extends IBaseResource> getResourceType() {
return myResourceType;
}
private synchronized TreeMap<Long, T> getVersionToResource(String theIdPart) {
if (!myIdToVersionToResourceMap.containsKey(theIdPart)) {
myIdToVersionToResourceMap.put(theIdPart, new TreeMap<Long, T>());
}
return myIdToVersionToResourceMap.get(theIdPart);
}
@Read(version = true)
public IBaseResource read(@IdParam IIdType theId) {
TreeMap<Long, T> versions = myIdToVersionToResourceMap.get(theId.getIdPart());
if (versions == null || versions.isEmpty()) {
throw new ResourceNotFoundException(theId);
}
if (theId.hasVersionIdPart()) {
Long versionId = theId.getVersionIdPartAsLong();
if (!versions.containsKey(versionId)) {
throw new ResourceNotFoundException(theId);
} else {
T resource = versions.get(versionId);
if (resource == null) {
throw new ResourceGoneException(theId);
}
return resource;
}
} else {
return versions.lastEntry().getValue();
}
}
@Search
public List<IBaseResource> search() {
List<IBaseResource> retVal = new ArrayList<>();
for (TreeMap<Long, T> next : myIdToVersionToResourceMap.values()) {
if (next.isEmpty() == false) {
retVal.add(next.lastEntry().getValue());
}
}
return retVal;
}
private IIdType store(@ResourceParam T theResource, String theIdPart, Long theVersionIdPart) {
IIdType id = myFhirContext.getVersion().newIdType();
id.setParts(null, myResourceName, theIdPart, Long.toString(theVersionIdPart));
if (theResource != null) {
theResource.setId(id);
}
TreeMap<Long, T> versionToResource = getVersionToResource(theIdPart);
versionToResource.put(theVersionIdPart, theResource);
ourLog.info("Storing resource with ID: {}", id.getValue());
return id;
}
public MethodOutcome update(T theResource) {
String idPartAsString = theResource.getIdElement().getIdPart();
TreeMap<Long, T> versionToResource = getVersionToResource(idPartAsString);
Long versionIdPart;
Boolean created;
if (versionToResource.isEmpty()) {
versionIdPart = 1L;
created = true;
} else {
versionIdPart = versionToResource.lastKey() + 1L;
created = false;
}
IIdType id = store(theResource, idPartAsString, versionIdPart);
return new MethodOutcome()
.setCreated(created)
.setId(id);
}
}

View File

@ -34,6 +34,7 @@ import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.ValidateUtil;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -44,6 +45,8 @@ import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import static org.apache.commons.lang3.StringUtils.isBlank;
/**
* This class is a simple implementation of the resource provider
* interface that uses a HashMap to store all resources in memory.
@ -338,8 +341,15 @@ public class HashMapResourceProvider<T extends IBaseResource> implements IResour
return id;
}
/**
* @param theConditional This is provided only so that subclasses can implement if they want
*/
@Update
public MethodOutcome update(@ResourceParam T theResource) {
public MethodOutcome update(
@ResourceParam T theResource,
@ConditionalUrlParam String theConditional) {
ValidateUtil.isTrueOrThrowInvalidRequest(isBlank(theConditional), "This server doesn't support conditional update");
String idPartAsString = theResource.getIdElement().getIdPart();
TreeMap<Long, T> versionToResource = getVersionToResource(idPartAsString);