Merge branch 'master' into windows-fixes-2
# Conflicts: # hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/ResourceModifiedMessage.java # hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/FhirObjectPrinter.java # hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/PointcutLatch.java # pom.xml
This commit is contained in:
commit
f40148fba5
|
@ -29,22 +29,20 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
|||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionConstants;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionMatchingStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionStrategyEvaluator;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.SubscriptionUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.hl7.fhir.instance.model.Subscription;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -76,8 +74,6 @@ public class SubscriptionActivatingInterceptor {
|
|||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingInterceptor.class);
|
||||
|
||||
private static boolean ourWaitForSubscriptionActivationSynchronouslyForUnitTest;
|
||||
private static final String REQUESTED_STATUS = Subscription.SubscriptionStatus.REQUESTED.toCode();
|
||||
private static final String ACTIVE_STATUS = Subscription.SubscriptionStatus.ACTIVE.toCode();
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
@ -93,8 +89,6 @@ public class SubscriptionActivatingInterceptor {
|
|||
@Autowired
|
||||
private SubscriptionCanonicalizer mySubscriptionCanonicalizer;
|
||||
@Autowired
|
||||
private MatchUrlService myMatchUrlService;
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
private SubscriptionStrategyEvaluator mySubscriptionStrategyEvaluator;
|
||||
|
@ -104,7 +98,7 @@ public class SubscriptionActivatingInterceptor {
|
|||
// subscriber applies..
|
||||
String subscriptionChannelTypeCode = myFhirContext
|
||||
.newTerser()
|
||||
.getSingleValueOrNull(theSubscription, SubscriptionMatcherInterceptor.SUBSCRIPTION_TYPE, IPrimitiveType.class)
|
||||
.getSingleValueOrNull(theSubscription, SubscriptionConstants.SUBSCRIPTION_TYPE, IPrimitiveType.class)
|
||||
.getValueAsString();
|
||||
|
||||
Subscription.SubscriptionChannelType subscriptionChannelType = Subscription.SubscriptionChannelType.fromCode(subscriptionChannelTypeCode);
|
||||
|
@ -113,10 +107,9 @@ public class SubscriptionActivatingInterceptor {
|
|||
return false;
|
||||
}
|
||||
|
||||
final IPrimitiveType<?> status = myFhirContext.newTerser().getSingleValueOrNull(theSubscription, SubscriptionMatcherInterceptor.SUBSCRIPTION_STATUS, IPrimitiveType.class);
|
||||
String statusString = status.getValueAsString();
|
||||
String statusString = mySubscriptionCanonicalizer.getSubscriptionStatus(theSubscription);
|
||||
|
||||
if (REQUESTED_STATUS.equals(statusString)) {
|
||||
if (SubscriptionConstants.REQUESTED_STATUS.equals(statusString)) {
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
/*
|
||||
* If we're in a transaction, we don't want to try and change the status from
|
||||
|
@ -133,7 +126,7 @@ public class SubscriptionActivatingInterceptor {
|
|||
Future<?> activationFuture = myTaskExecutor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
activateSubscription(ACTIVE_STATUS, theSubscription, REQUESTED_STATUS);
|
||||
activateSubscription(SubscriptionConstants.ACTIVE_STATUS, theSubscription, SubscriptionConstants.REQUESTED_STATUS);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -152,9 +145,9 @@ public class SubscriptionActivatingInterceptor {
|
|||
});
|
||||
return true;
|
||||
} else {
|
||||
return activateSubscription(ACTIVE_STATUS, theSubscription, REQUESTED_STATUS);
|
||||
return activateSubscription(SubscriptionConstants.ACTIVE_STATUS, theSubscription, SubscriptionConstants.REQUESTED_STATUS);
|
||||
}
|
||||
} else if (ACTIVE_STATUS.equals(statusString)) {
|
||||
} else if (SubscriptionConstants.ACTIVE_STATUS.equals(statusString)) {
|
||||
return mySubscriptionRegistry.registerSubscriptionUnlessAlreadyRegistered(theSubscription);
|
||||
} else {
|
||||
// Status isn't "active" or "requested"
|
||||
|
|
|
@ -48,8 +48,6 @@ public class SubscriptionMatcherInterceptor implements IResourceModifiedConsumer
|
|||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionMatcherInterceptor.class);
|
||||
|
||||
private static final String SUBSCRIPTION_MATCHING_CHANNEL_NAME = "subscription-matching";
|
||||
static final String SUBSCRIPTION_STATUS = "Subscription.status";
|
||||
static final String SUBSCRIPTION_TYPE = "Subscription.channel.type";
|
||||
private SubscribableChannel myProcessingChannel;
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -97,6 +97,11 @@
|
|||
<artifactId>jetty-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
|
@ -168,11 +169,13 @@ public class ResourceModifiedMessage implements IResourceMessage {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
String resourceId = myPayloadId;
|
||||
if (resourceId == null) {
|
||||
resourceId = myId;
|
||||
}
|
||||
return "ResourceModified Message { " + myOperationType + ", " + resourceId + "}";
|
||||
return new ToStringBuilder(this)
|
||||
.append("myId", myId)
|
||||
.append("myOperationType", myOperationType)
|
||||
.append("mySubscriptionId", mySubscriptionId)
|
||||
// .append("myPayload", myPayload)
|
||||
.append("myPayloadId", myPayloadId)
|
||||
// .append("myPayloadDecoded", myPayloadDecoded)
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@ import ca.uhn.fhir.model.api.ExtensionDt;
|
|||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -292,4 +292,13 @@ public class SubscriptionCanonicalizer<S extends IBaseResource> {
|
|||
}
|
||||
meta.addTag().setSystem(SubscriptionConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY).setCode(value).setDisplay(display);
|
||||
}
|
||||
|
||||
public String getSubscriptionStatus(IBaseResource theSubscription) {
|
||||
final IPrimitiveType<?> status = myFhirContext.newTerser().getSingleValueOrNull(theSubscription, SubscriptionConstants.SUBSCRIPTION_STATUS, IPrimitiveType.class);
|
||||
if (status == null) {
|
||||
return null;
|
||||
}
|
||||
return status.getValueAsString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ package ca.uhn.fhir.jpa.subscription.module.cache;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.instance.model.Subscription;
|
||||
|
||||
public class SubscriptionConstants {
|
||||
|
||||
/**
|
||||
|
@ -90,4 +92,8 @@ public class SubscriptionConstants {
|
|||
*/
|
||||
|
||||
public static final int DELIVERY_EXECUTOR_QUEUE_SIZE = 1000;
|
||||
public static final String SUBSCRIPTION_STATUS = "Subscription.status";
|
||||
public static final String SUBSCRIPTION_TYPE = "Subscription.channel.type";
|
||||
public static final String REQUESTED_STATUS = Subscription.SubscriptionStatus.REQUESTED.toCode();
|
||||
public static final String ACTIVE_STATUS = Subscription.SubscriptionStatus.ACTIVE.toCode();
|
||||
}
|
||||
|
|
|
@ -87,7 +87,6 @@ public class SubscriptionLoader {
|
|||
ourLog.debug("Starting sync subscriptions");
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(Subscription.SP_STATUS, new TokenOrListParam()
|
||||
// TODO KHS perhaps we should only be requesting ACTIVE subscriptions here?...
|
||||
.addOr(new TokenParam(null, Subscription.SubscriptionStatus.REQUESTED.toCode()))
|
||||
.addOr(new TokenParam(null, Subscription.SubscriptionStatus.ACTIVE.toCode())));
|
||||
map.setLoadSynchronousUpTo(SubscriptionConstants.MAX_SUBSCRIPTION_RESULTS);
|
||||
|
|
|
@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.subscription.module.standalone;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionConstants;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceModifiedJsonMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.SubscriptionMatchingSubscriber;
|
||||
|
@ -46,6 +48,8 @@ public class StandaloneSubscriptionMessageHandler implements MessageHandler {
|
|||
SubscriptionMatchingSubscriber mySubscriptionMatchingSubscriber;
|
||||
@Autowired
|
||||
SubscriptionRegistry mySubscriptionRegistry;
|
||||
@Autowired
|
||||
SubscriptionCanonicalizer mySubscriptionCanonicalizer;
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message<?> theMessage) throws MessagingException {
|
||||
|
@ -61,7 +65,10 @@ public class StandaloneSubscriptionMessageHandler implements MessageHandler {
|
|||
RuntimeResourceDefinition resourceDef = myFhirContext.getResourceDefinition(resource);
|
||||
|
||||
if (resourceDef.getName().equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||
mySubscriptionRegistry.registerSubscriptionUnlessAlreadyRegistered(resource);
|
||||
String status = mySubscriptionCanonicalizer.getSubscriptionStatus(resource);
|
||||
if (SubscriptionConstants.ACTIVE_STATUS.equals(status)) {
|
||||
mySubscriptionRegistry.registerSubscriptionUnlessAlreadyRegistered(resource);
|
||||
}
|
||||
}
|
||||
mySubscriptionMatchingSubscriber.matchActiveSubscriptionsAndDeliver(theResourceModifiedMessage);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.subscription.module.subscriber;
|
|||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
|
@ -54,4 +55,10 @@ public class ResourceDeliveryJsonMessage extends BaseJsonMessage<ResourceDeliver
|
|||
myPayload = thePayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("myPayload", myPayload)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
|
@ -114,4 +115,16 @@ public class ResourceDeliveryMessage implements IResourceMessage {
|
|||
myPayloadId = thePayloadId.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("mySubscription", mySubscription)
|
||||
// .append("mySubscriptionString", mySubscriptionString)
|
||||
.append("myPayloadString", myPayloadString)
|
||||
.append("myPayload", myPayload)
|
||||
.append("myPayloadId", myPayloadId)
|
||||
.append("myOperationType", myOperationType)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
|||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
|
@ -55,4 +56,10 @@ public class ResourceModifiedJsonMessage extends BaseJsonMessage<ResourceModifie
|
|||
myPayload = thePayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("myPayload", myPayload)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.subscription.module;
|
|||
|
||||
import ca.uhn.fhir.jpa.subscription.module.config.TestSubscriptionDstu3Config;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
|
@ -12,6 +13,9 @@ import static org.junit.Assert.fail;
|
|||
|
||||
@ContextConfiguration(classes = {TestSubscriptionDstu3Config.class})
|
||||
public abstract class BaseSubscriptionDstu3Test extends BaseSubscriptionTest {
|
||||
|
||||
private SubscriptionTestHelper mySubscriptionTestHelper = new SubscriptionTestHelper();
|
||||
|
||||
public static void waitForSize(int theTarget, List<?> theList) {
|
||||
StopWatch sw = new StopWatch();
|
||||
while (theList.size() != theTarget && sw.getMillis() <= 16000) {
|
||||
|
@ -37,4 +41,16 @@ public abstract class BaseSubscriptionDstu3Test extends BaseSubscriptionTest {
|
|||
fail("Size " + theList.size() + " is != target " + theTarget + " - Got: " + describeResults);
|
||||
}
|
||||
}
|
||||
|
||||
protected long nextId() {
|
||||
return mySubscriptionTestHelper.nextId();
|
||||
}
|
||||
|
||||
protected Subscription makeActiveSubscription(String theCriteria, String thePayload, String theEndpoint) {
|
||||
return mySubscriptionTestHelper.makeActiveSubscription(theCriteria, thePayload, theEndpoint);
|
||||
}
|
||||
|
||||
protected Subscription makeSubscriptionWithStatus(String theCriteria, String thePayload, String theEndpoint, Subscription.SubscriptionStatus status) {
|
||||
return mySubscriptionTestHelper.makeSubscriptionWithStatus(theCriteria, thePayload, theEndpoint, status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,5 +44,4 @@ public abstract class BaseSubscriptionTest {
|
|||
myMockFhirClientSubscriptionProvider.setBundleProvider(theBundleProvider);
|
||||
mySubscriptionLoader.doSyncSubscriptionsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module;
|
||||
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryJsonMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
@ -11,16 +9,7 @@ public class FhirObjectPrinter implements Function<Object, String> {
|
|||
public String apply(Object object) {
|
||||
if (object instanceof IBaseResource) {
|
||||
IBaseResource resource = (IBaseResource) object;
|
||||
return "Resource " + resource.getIdElement().getValue();
|
||||
} else if (object instanceof ResourceDeliveryMessage) {
|
||||
ResourceDeliveryMessage resourceDeliveryMessage = (ResourceDeliveryMessage) object;
|
||||
// TODO KHS move this to ResourceModifiedMessage.toString()
|
||||
return "ResourceDelivery Message { " + resourceDeliveryMessage.getPayloadId() + "}";
|
||||
} else if (object instanceof ResourceDeliveryJsonMessage) {
|
||||
ResourceDeliveryJsonMessage resourceDeliveryJsonMessage = (ResourceDeliveryJsonMessage) object;
|
||||
// TODO KHS move this to ResourceModifiedMessage.toString()
|
||||
ResourceDeliveryMessage resourceDeliveryMessage = resourceDeliveryJsonMessage.getPayload();
|
||||
return "ResourceDeliveryJsonMessage Message { " + resourceDeliveryMessage.getPayloadId() + "}";
|
||||
return resource.getClass().getSimpleName() + " { " + resource.getIdElement().getValue() + " }";
|
||||
} else {
|
||||
return object.toString();
|
||||
}
|
||||
|
|
|
@ -39,10 +39,10 @@ public class PointcutLatch implements IAnonymousLambdaHook {
|
|||
throw new PointcutLatchException("setExpectedCount() called before previous awaitExpected() completed.");
|
||||
}
|
||||
createLatch(count);
|
||||
ourLog.info("Expecting {} calls to {} latch", count, name);
|
||||
}
|
||||
|
||||
private void createLatch(int count) {
|
||||
ourLog.info("Creating new latch with count {}", count);
|
||||
myFailure = new AtomicReference<>();
|
||||
myCalledWith = new AtomicReference<>(new ArrayList<>());
|
||||
myCountdownLatch = new CountDownLatch(count);
|
||||
|
@ -76,17 +76,17 @@ public class PointcutLatch implements IAnonymousLambdaHook {
|
|||
throw new AssertionError(error);
|
||||
}
|
||||
} finally {
|
||||
destroyLatch();
|
||||
clear();
|
||||
}
|
||||
assertEquals("Concurrency error: Latch switched while waiting.", retval, myCalledWith.get());
|
||||
return retval;
|
||||
}
|
||||
|
||||
public void expectNothing() {
|
||||
destroyLatch();
|
||||
clear();
|
||||
}
|
||||
|
||||
private void destroyLatch() {
|
||||
public void clear() {
|
||||
myCountdownLatch = null;
|
||||
}
|
||||
|
||||
|
@ -115,11 +115,8 @@ public class PointcutLatch implements IAnonymousLambdaHook {
|
|||
if (myCalledWith.get() != null) {
|
||||
myCalledWith.get().add(theArgs);
|
||||
}
|
||||
this.countdown();
|
||||
}
|
||||
ourLog.info("Called {} {} with {}", name, myCountdownLatch, hookParamsToString(theArgs));
|
||||
|
||||
private void countdown() {
|
||||
ourLog.info("{} counting down {}", name, myCountdownLatch);
|
||||
myCountdownLatch.countDown();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class SubscriptionTestHelper {
|
||||
|
||||
protected static AtomicLong idCounter = new AtomicLong();
|
||||
|
||||
|
||||
public Subscription makeActiveSubscription(String theCriteria, String thePayload, String theEndpoint) {
|
||||
return makeSubscriptionWithStatus(theCriteria, thePayload, theEndpoint, Subscription.SubscriptionStatus.ACTIVE);
|
||||
}
|
||||
|
||||
public Subscription makeSubscriptionWithStatus(String theCriteria, String thePayload, String theEndpoint, Subscription.SubscriptionStatus status) {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(status);
|
||||
subscription.setCriteria(theCriteria);
|
||||
IdType id = new IdType("Subscription", nextId());
|
||||
subscription.setId(id);
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setPayload(thePayload);
|
||||
channel.setEndpoint(theEndpoint);
|
||||
subscription.setChannel(channel);
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public long nextId() {
|
||||
return idCounter.incrementAndGet();
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
|
@ -39,7 +38,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends BaseSubscriptionDstu3Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionMatchingSubscriberTest.class);
|
||||
|
@ -67,8 +65,6 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
protected static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||
protected static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||
private static SubscribableChannel ourSubscribableChannel;
|
||||
private List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||
protected static AtomicLong idCounter = new AtomicLong();
|
||||
protected PointcutLatch mySubscriptionMatchingPost = new PointcutLatch(Pointcut.SUBSCRIPTION_AFTER_PERSISTED_RESOURCE_CHECKED);
|
||||
protected PointcutLatch mySubscriptionActivatedPost = new PointcutLatch(Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED);
|
||||
|
||||
|
@ -101,32 +97,16 @@ public abstract class BaseBlockingQueueSubscribableChannelDstu3Test extends Base
|
|||
}
|
||||
|
||||
protected Subscription sendSubscription(String theCriteria, String thePayload, String theEndpoint) throws InterruptedException {
|
||||
Subscription subscription = returnedActiveSubscription(theCriteria, thePayload, theEndpoint);
|
||||
Subscription subscription = makeActiveSubscription(theCriteria, thePayload, theEndpoint);
|
||||
mySubscriptionActivatedPost.setExpectedCount(1);
|
||||
Subscription retval = sendResource(subscription);
|
||||
mySubscriptionActivatedPost.awaitExpected();
|
||||
return retval;
|
||||
}
|
||||
|
||||
protected Subscription returnedActiveSubscription(String theCriteria, String thePayload, String theEndpoint) {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
subscription.setCriteria(theCriteria);
|
||||
IdType id = new IdType("Subscription", idCounter.incrementAndGet());
|
||||
subscription.setId(id);
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setPayload(thePayload);
|
||||
channel.setEndpoint(theEndpoint);
|
||||
subscription.setChannel(channel);
|
||||
return subscription;
|
||||
}
|
||||
|
||||
protected Observation sendObservation(String code, String system) throws InterruptedException {
|
||||
Observation observation = new Observation();
|
||||
IdType id = new IdType("Observation", idCounter.incrementAndGet());
|
||||
IdType id = new IdType("Observation", nextId());
|
||||
observation.setId(id);
|
||||
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module.standalone;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.subscription.module.BaseSubscriptionDstu3Test;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceModifiedJsonMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.SubscriptionMatchingSubscriber;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
public class StandaloneSubscriptionMessageHandlerTest extends BaseSubscriptionDstu3Test {
|
||||
|
||||
@Autowired
|
||||
StandaloneSubscriptionMessageHandler myStandaloneSubscriptionMessageHandler;
|
||||
@Autowired
|
||||
FhirContext myFhirContext;
|
||||
@MockBean
|
||||
SubscriptionMatchingSubscriber mySubscriptionMatchingSubscriber;
|
||||
@MockBean
|
||||
SubscriptionRegistry mySubscriptionRegistry;
|
||||
|
||||
@Test
|
||||
public void activeSubscriptionIsRegistered() {
|
||||
Subscription subscription = makeActiveSubscription("testCriteria", "testPayload", "testEndpoint");
|
||||
ResourceModifiedMessage message = new ResourceModifiedMessage(myFhirContext, subscription, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
ResourceModifiedJsonMessage jsonMessage = new ResourceModifiedJsonMessage(message);
|
||||
myStandaloneSubscriptionMessageHandler.handleMessage(jsonMessage);
|
||||
Mockito.verify(mySubscriptionRegistry).registerSubscriptionUnlessAlreadyRegistered(any());
|
||||
Mockito.verify(mySubscriptionMatchingSubscriber).matchActiveSubscriptionsAndDeliver(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestedSubscriptionNotRegistered() {
|
||||
Subscription subscription = makeSubscriptionWithStatus("testCriteria", "testPayload", "testEndpoint", Subscription.SubscriptionStatus.REQUESTED);
|
||||
ResourceModifiedMessage message = new ResourceModifiedMessage(myFhirContext, subscription, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
ResourceModifiedJsonMessage jsonMessage = new ResourceModifiedJsonMessage(message);
|
||||
myStandaloneSubscriptionMessageHandler.handleMessage(jsonMessage);
|
||||
Mockito.verify(mySubscriptionRegistry, never()).registerSubscriptionUnlessAlreadyRegistered(any());
|
||||
Mockito.verify(mySubscriptionMatchingSubscriber).matchActiveSubscriptionsAndDeliver(any());
|
||||
}
|
||||
}
|
|
@ -12,9 +12,7 @@ import java.util.List;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class SubscriptionLoaderFhirClientTest extends BaseBlockingQueueSubscribableChannelDstu3Test {
|
||||
@Test
|
||||
|
@ -28,8 +26,8 @@ public class SubscriptionLoaderFhirClientTest extends BaseBlockingQueueSubscriba
|
|||
String criteria2 = "Observation?code=SNOMED-CT|" + myCode + "111&_format=xml";
|
||||
|
||||
List<Subscription> subs = new ArrayList<>();
|
||||
subs.add(returnedActiveSubscription(criteria1, payload, ourListenerServerBase));
|
||||
subs.add(returnedActiveSubscription(criteria2, payload, ourListenerServerBase));
|
||||
subs.add(makeActiveSubscription(criteria1, payload, ourListenerServerBase));
|
||||
subs.add(makeActiveSubscription(criteria2, payload, ourListenerServerBase));
|
||||
|
||||
IBundleProvider bundle = new SimpleBundleProvider(new ArrayList<>(subs), "uuid");
|
||||
initSubscriptionLoader(bundle);
|
||||
|
@ -53,8 +51,8 @@ public class SubscriptionLoaderFhirClientTest extends BaseBlockingQueueSubscriba
|
|||
String criteria2 = "Observation?code=SNOMED-CT|" + myCode + "111&_format=xml";
|
||||
|
||||
List<Subscription> subs = new ArrayList<>();
|
||||
subs.add(returnedActiveSubscription(criteria1, payload, ourListenerServerBase).setStatus(Subscription.SubscriptionStatus.REQUESTED));
|
||||
subs.add(returnedActiveSubscription(criteria2, payload, ourListenerServerBase).setStatus(Subscription.SubscriptionStatus.REQUESTED));
|
||||
subs.add(makeActiveSubscription(criteria1, payload, ourListenerServerBase).setStatus(Subscription.SubscriptionStatus.REQUESTED));
|
||||
subs.add(makeActiveSubscription(criteria2, payload, ourListenerServerBase).setStatus(Subscription.SubscriptionStatus.REQUESTED));
|
||||
|
||||
IBundleProvider bundle = new SimpleBundleProvider(new ArrayList<>(subs), "uuid");
|
||||
initSubscriptionLoader(bundle);
|
||||
|
|
|
@ -40,8 +40,8 @@ public class SubscriptionLoaderTest extends BaseBlockingQueueSubscribableChannel
|
|||
String criteria2 = "Observation?code=SNOMED-CT|" + myCode + "111&_format=xml";
|
||||
|
||||
List<Subscription> subs = new ArrayList<>();
|
||||
subs.add(returnedActiveSubscription(criteria1, payload, ourListenerServerBase));
|
||||
subs.add(returnedActiveSubscription(criteria2, payload, ourListenerServerBase));
|
||||
subs.add(makeActiveSubscription(criteria1, payload, ourListenerServerBase));
|
||||
subs.add(makeActiveSubscription(criteria2, payload, ourListenerServerBase));
|
||||
|
||||
IBundleProvider bundle = new SimpleBundleProvider(new ArrayList<>(subs), "uuid");
|
||||
initSubscriptionLoader(bundle);
|
||||
|
|
|
@ -95,7 +95,7 @@ public class SubscriptionCheckingSubscriberTest extends BaseBlockingQueueSubscri
|
|||
|
||||
ourObservationListener.setExpectedCount(1);
|
||||
Observation observation = new Observation();
|
||||
IdType id = new IdType("Observation", idCounter.incrementAndGet());
|
||||
IdType id = new IdType("Observation", nextId());
|
||||
observation.setId(id);
|
||||
|
||||
// Reference has display only!
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<version>${spring_boot_version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<version>${spring_boot_version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<version>${spring_boot_version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<version>${spring_boot_version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -0,0 +1,426 @@
|
|||
package ca.uhn.fhir.parser.jsonlike;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Reference;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.IJsonLikeParser;
|
||||
import ca.uhn.fhir.parser.json.GsonStructure;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeStructure;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeWriter;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class JsonLikeParserDstu3Test {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserDstu3Test.class);
|
||||
|
||||
/**
|
||||
* Test for JSON Parser with user-supplied JSON-like structure (use default GSON)
|
||||
*/
|
||||
@Test
|
||||
public void testJsonLikeParseAndEncodeBundleFromXmlToJson() throws Exception {
|
||||
String content = IOUtils.toString(JsonLikeParserDstu3Test.class.getResourceAsStream("/bundle_with_woven_obs.xml"));
|
||||
|
||||
Bundle parsed = ourCtx.newXmlParser().parseResource(Bundle.class, content);
|
||||
|
||||
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
|
||||
ourLog.info(encoded);
|
||||
|
||||
JsonLikeStructure jsonLikeStructure = new GsonStructure();
|
||||
jsonLikeStructure.load(new StringReader(encoded));
|
||||
|
||||
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
|
||||
Bundle bundle = jsonLikeparser.parseResource(Bundle.class, jsonLikeStructure);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JSON-Like writer using custom stream writer
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testJsonLikeParseWithCustomJSONStreamWriter() throws Exception {
|
||||
String refVal = "http://my.org/FooBar";
|
||||
|
||||
Patient fhirPat = new Patient();
|
||||
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
JsonLikeMapWriter jsonLikeWriter = new JsonLikeMapWriter();
|
||||
|
||||
jsonLikeParser.encodeResourceToJsonLikeWriter(fhirPat, jsonLikeWriter);
|
||||
Map<String,Object> jsonLikeMap = jsonLikeWriter.getResultMap();
|
||||
|
||||
System.out.println("encoded map: " + jsonLikeMap.toString());
|
||||
|
||||
Assert.assertNotNull("Encoded resource missing 'resourceType' element", jsonLikeMap.get("resourceType"));
|
||||
Assert.assertEquals("Expecting 'resourceType'='Patient'; found '"+jsonLikeMap.get("resourceType")+"'", jsonLikeMap.get("resourceType"), "Patient");
|
||||
|
||||
Assert.assertNotNull("Encoded resource missing 'extension' element", jsonLikeMap.get("extension"));
|
||||
Assert.assertTrue("'extension' element is not a List", (jsonLikeMap.get("extension") instanceof List));
|
||||
|
||||
List<Object> extensions = (List<Object>)jsonLikeMap.get("extension");
|
||||
Assert.assertEquals("'extnesion' array has more than one entry", 1, extensions.size());
|
||||
Assert.assertTrue("'extension' array entry is not a Map", (extensions.get(0) instanceof Map));
|
||||
|
||||
Map<String, Object> extension = (Map<String,Object>)extensions.get(0);
|
||||
Assert.assertNotNull("'extension' entry missing 'url' member", extension.get("url"));
|
||||
Assert.assertTrue("'extension' entry 'url' member is not a String", (extension.get("url") instanceof String));
|
||||
Assert.assertEquals("Expecting '/extension[]/url' = 'x1'; found '"+extension.get("url")+"'", "x1", (String)extension.get("url"));
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class JsonLikeMapWriter extends JsonLikeWriter {
|
||||
|
||||
private Map<String,Object> target;
|
||||
|
||||
private static class Block {
|
||||
private BlockType type;
|
||||
private String name;
|
||||
private Map<String,Object> object;
|
||||
private List<Object> array;
|
||||
public Block(BlockType type) {
|
||||
this.type = type;
|
||||
}
|
||||
public BlockType getType() {
|
||||
return type;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String currentName) {
|
||||
this.name = currentName;
|
||||
}
|
||||
public Map<String, Object> getObject() {
|
||||
return object;
|
||||
}
|
||||
public void setObject(Map<String, Object> currentObject) {
|
||||
this.object = currentObject;
|
||||
}
|
||||
public List<Object> getArray() {
|
||||
return array;
|
||||
}
|
||||
public void setArray(List<Object> currentArray) {
|
||||
this.array = currentArray;
|
||||
}
|
||||
}
|
||||
private enum BlockType {
|
||||
NONE, OBJECT, ARRAY
|
||||
}
|
||||
private Block currentBlock = new Block(BlockType.NONE);
|
||||
private Stack<Block> blockStack = new Stack<Block>();
|
||||
|
||||
public JsonLikeMapWriter () {
|
||||
super();
|
||||
}
|
||||
|
||||
public Map<String,Object> getResultMap() {
|
||||
return target;
|
||||
}
|
||||
public void setResultMap(Map<String,Object> target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter init() throws IOException {
|
||||
if (target != null) {
|
||||
target.clear();
|
||||
}
|
||||
currentBlock = new Block(BlockType.NONE);
|
||||
blockStack.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter flush() throws IOException {
|
||||
if (currentBlock.getType() != BlockType.NONE) {
|
||||
throw new IOException("JsonLikeStreamWriter.flush() called but JSON document is not finished");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginObject() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
Map<String,Object> newObject = null;
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
if (null == target) {
|
||||
// for this test, we don't care about ordering of map elements
|
||||
// target = new EntryOrderedMap<String,Object>();
|
||||
target = new HashMap<String,Object>();
|
||||
}
|
||||
newObject = target;
|
||||
} else {
|
||||
// for this test, we don't care about ordering of map elements
|
||||
// newObject = new EntryOrderedMap<String,Object>();
|
||||
newObject = new HashMap<String,Object>();
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.OBJECT);
|
||||
currentBlock.setObject(newObject);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginArray() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
throw new IOException("JsonLikeStreamWriter.beginArray() called but only beginObject() is allowed here.");
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.ARRAY);
|
||||
currentBlock.setArray(new ArrayList<Object>());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginObject(String name) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.OBJECT);
|
||||
currentBlock.setName(name);
|
||||
// for this test, we don't care about ordering of map elements
|
||||
// currentBlock.setObject(new EntryOrderedMap<String,Object>());
|
||||
currentBlock.setObject(new HashMap<String,Object>());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginArray(String name) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.ARRAY);
|
||||
currentBlock.setName(name);
|
||||
currentBlock.setArray(new ArrayList<Object>());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(BigInteger value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(BigDecimal value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(long value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(double value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(Double.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(Boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(Boolean.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter writeNull() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, String value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, BigInteger value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, BigDecimal value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, long value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, double value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, Double.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, Boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, Boolean.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter writeNull(String name) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter endObject() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
ourLog.error("JsonLikeStreamWriter.endObject(); called with no active JSON document");
|
||||
} else {
|
||||
if (currentBlock.getType() != BlockType.OBJECT) {
|
||||
ourLog.error("JsonLikeStreamWriter.endObject(); called outside a JSON object. (Use endArray() instead?)");
|
||||
}
|
||||
endBlock();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter endArray() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
ourLog.error("JsonLikeStreamWriter.endArray(); called with no active JSON document");
|
||||
} else {
|
||||
if (currentBlock.getType() != BlockType.ARRAY) {
|
||||
ourLog.error("JsonLikeStreamWriter.endArray(); called outside a JSON array. (Use endObject() instead?)");
|
||||
}
|
||||
endBlock();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter endBlock() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
|
||||
} else {
|
||||
Object toPut = null;
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
toPut = currentBlock.getArray();
|
||||
} else {
|
||||
toPut = currentBlock.getObject();
|
||||
}
|
||||
Block parentBlock = blockStack.pop();
|
||||
if (parentBlock.getType() == BlockType.OBJECT) {
|
||||
parentBlock.getObject().put(currentBlock.getName(), toPut);
|
||||
} else
|
||||
if (parentBlock.getType() == BlockType.ARRAY) {
|
||||
parentBlock.getArray().add(toPut);
|
||||
}
|
||||
currentBlock = parentBlock;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,732 @@
|
|||
package ca.uhn.fhir.parser.jsonlike;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.Writer;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.IntegerType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IJsonLikeParser;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.parser.json.GsonStructure;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeArray;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeObject;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeStructure;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeValue;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeWriter;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
||||
import ca.uhn.fhir.parser.view.ExtPatient;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class JsonLikeParserTest {
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserTest.class);
|
||||
|
||||
/**
|
||||
* Test for JSON Parser with user-supplied JSON-like structure (use default GSON)
|
||||
*/
|
||||
@Test
|
||||
public void testJsonLikeParseAndEncodeResourceFromXmlToJson() throws Exception {
|
||||
String content = IOUtils.toString(JsonLikeParserTest.class.getResourceAsStream("/extension-on-line.txt"));
|
||||
|
||||
IBaseResource parsed = ourCtx.newJsonParser().parseResource(content);
|
||||
|
||||
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
|
||||
ourLog.info(encoded);
|
||||
|
||||
JsonLikeStructure jsonLikeStructure = new GsonStructure();
|
||||
jsonLikeStructure.load(new StringReader(encoded));
|
||||
|
||||
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
|
||||
IBaseResource resource = jsonLikeparser.parseResource(jsonLikeStructure);
|
||||
Assert.assertEquals("reparsed resource classes not equal", parsed.getClass().getName(), resource.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JSON-Like writer using custom stream writer
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testJsonLikeParseWithCustomJSONStreamWriter() throws Exception {
|
||||
String refVal = "http://my.org/FooBar";
|
||||
|
||||
Patient fhirPat = new Patient();
|
||||
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
JsonLikeMapWriter jsonLikeWriter = new JsonLikeMapWriter();
|
||||
|
||||
jsonLikeParser.encodeResourceToJsonLikeWriter(fhirPat, jsonLikeWriter);
|
||||
Map<String,Object> jsonLikeMap = jsonLikeWriter.getResultMap();
|
||||
|
||||
System.out.println("encoded map: " + jsonLikeMap.toString());
|
||||
|
||||
Assert.assertNotNull("Encoded resource missing 'resourceType' element", jsonLikeMap.get("resourceType"));
|
||||
Assert.assertEquals("Expecting 'resourceType'='Patient'; found '"+jsonLikeMap.get("resourceType")+"'", jsonLikeMap.get("resourceType"), "Patient");
|
||||
|
||||
Assert.assertNotNull("Encoded resource missing 'extension' element", jsonLikeMap.get("extension"));
|
||||
Assert.assertTrue("'extension' element is not a List", (jsonLikeMap.get("extension") instanceof List));
|
||||
|
||||
List<Object> extensions = (List<Object>)jsonLikeMap.get("extension");
|
||||
Assert.assertEquals("'extnesion' array has more than one entry", 1, extensions.size());
|
||||
Assert.assertTrue("'extension' array entry is not a Map", (extensions.get(0) instanceof Map));
|
||||
|
||||
Map<String, Object> extension = (Map<String,Object>)extensions.get(0);
|
||||
Assert.assertNotNull("'extension' entry missing 'url' member", extension.get("url"));
|
||||
Assert.assertTrue("'extension' entry 'url' member is not a String", (extension.get("url") instanceof String));
|
||||
Assert.assertEquals("Expecting '/extension[]/url' = 'x1'; found '"+extension.get("url")+"'", "x1", (String)extension.get("url"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeat the "View" tests with custom JSON-Like structure
|
||||
*/
|
||||
@Test
|
||||
public void testViewJson() throws Exception {
|
||||
|
||||
ExtPatient src = new ExtPatient();
|
||||
src.addIdentifier().setSystem("urn:sys").setValue("id1");
|
||||
src.addIdentifier().setSystem("urn:sys").setValue("id2");
|
||||
src.getExt().setValue(100);
|
||||
src.getModExt().setValue(200);
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
JsonLikeMapWriter jsonLikeWriter = new JsonLikeMapWriter();
|
||||
jsonLikeParser.encodeResourceToJsonLikeWriter(src, jsonLikeWriter);
|
||||
Map<String,Object> jsonLikeMap = jsonLikeWriter.getResultMap();
|
||||
|
||||
|
||||
ourLog.info("encoded: "+jsonLikeMap);
|
||||
|
||||
JsonLikeStructure jsonStructure = new JsonLikeMapStructure(jsonLikeMap);
|
||||
IJsonLikeParser parser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
Patient nonExt = parser.parseResource(Patient.class, jsonStructure);
|
||||
|
||||
Assert.assertEquals(Patient.class, nonExt.getClass());
|
||||
Assert.assertEquals("urn:sys", nonExt.getIdentifier().get(0).getSystem());
|
||||
Assert.assertEquals("id1", nonExt.getIdentifier().get(0).getValue());
|
||||
Assert.assertEquals("urn:sys", nonExt.getIdentifier().get(1).getSystem());
|
||||
Assert.assertEquals("id2", nonExt.getIdentifier().get(1).getValue());
|
||||
|
||||
List<Extension> ext = nonExt.getExtensionsByUrl("urn:ext");
|
||||
Assert.assertEquals(1, ext.size());
|
||||
Assert.assertEquals("urn:ext", ext.get(0).getUrl());
|
||||
Assert.assertEquals(IntegerType.class, ext.get(0).getValueAsPrimitive().getClass());
|
||||
Assert.assertEquals("100", ext.get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
List<Extension> modExt = nonExt.getExtensionsByUrl("urn:modExt");
|
||||
Assert.assertEquals(1, modExt.size());
|
||||
Assert.assertEquals("urn:modExt", modExt.get(0).getUrl());
|
||||
Assert.assertEquals(IntegerType.class, modExt.get(0).getValueAsPrimitive().getClass());
|
||||
Assert.assertEquals("200", modExt.get(0).getValueAsPrimitive().getValueAsString());
|
||||
|
||||
ExtPatient va = ourCtx.newViewGenerator().newView(nonExt, ExtPatient.class);
|
||||
Assert.assertEquals("urn:sys", va.getIdentifier().get(0).getSystem());
|
||||
Assert.assertEquals("id1", va.getIdentifier().get(0).getValue());
|
||||
Assert.assertEquals("urn:sys", va.getIdentifier().get(1).getSystem());
|
||||
Assert.assertEquals("id2", va.getIdentifier().get(1).getValue());
|
||||
Assert.assertEquals(100, va.getExt().getValue().intValue());
|
||||
Assert.assertEquals(200, va.getModExt().getValue().intValue());
|
||||
|
||||
Assert.assertEquals(0, va.getExtension().size());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class JsonLikeMapWriter extends JsonLikeWriter {
|
||||
|
||||
private Map<String,Object> target;
|
||||
|
||||
private static class Block {
|
||||
private BlockType type;
|
||||
private String name;
|
||||
private Map<String,Object> object;
|
||||
private List<Object> array;
|
||||
public Block(BlockType type) {
|
||||
this.type = type;
|
||||
}
|
||||
public BlockType getType() {
|
||||
return type;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String currentName) {
|
||||
this.name = currentName;
|
||||
}
|
||||
public Map<String, Object> getObject() {
|
||||
return object;
|
||||
}
|
||||
public void setObject(Map<String, Object> currentObject) {
|
||||
this.object = currentObject;
|
||||
}
|
||||
public List<Object> getArray() {
|
||||
return array;
|
||||
}
|
||||
public void setArray(List<Object> currentArray) {
|
||||
this.array = currentArray;
|
||||
}
|
||||
}
|
||||
private enum BlockType {
|
||||
NONE, OBJECT, ARRAY
|
||||
}
|
||||
private Block currentBlock = new Block(BlockType.NONE);
|
||||
private Stack<Block> blockStack = new Stack<Block>();
|
||||
|
||||
public JsonLikeMapWriter () {
|
||||
super();
|
||||
}
|
||||
|
||||
public Map<String,Object> getResultMap() {
|
||||
return target;
|
||||
}
|
||||
public void setResultMap(Map<String,Object> target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter init() throws IOException {
|
||||
if (target != null) {
|
||||
target.clear();
|
||||
}
|
||||
currentBlock = new Block(BlockType.NONE);
|
||||
blockStack.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter flush() throws IOException {
|
||||
if (currentBlock.getType() != BlockType.NONE) {
|
||||
throw new IOException("JsonLikeStreamWriter.flush() called but JSON document is not finished");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginObject() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
Map<String,Object> newObject = null;
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
if (null == target) {
|
||||
// for this test, we don't care about ordering of map elements
|
||||
// target = new EntryOrderedMap<String,Object>();
|
||||
target = new HashMap<String,Object>();
|
||||
}
|
||||
newObject = target;
|
||||
} else {
|
||||
// for this test, we don't care about ordering of map elements
|
||||
// newObject = new EntryOrderedMap<String,Object>();
|
||||
newObject = new HashMap<String,Object>();
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.OBJECT);
|
||||
currentBlock.setObject(newObject);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginArray() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
throw new IOException("JsonLikeStreamWriter.beginArray() called but only beginObject() is allowed here.");
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.ARRAY);
|
||||
currentBlock.setArray(new ArrayList<Object>());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginObject(String name) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.OBJECT);
|
||||
currentBlock.setName(name);
|
||||
// for this test, we don't care about ordering of map elements
|
||||
// currentBlock.setObject(new EntryOrderedMap<String,Object>());
|
||||
currentBlock.setObject(new HashMap<String,Object>());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter beginArray(String name) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
blockStack.push(currentBlock);
|
||||
currentBlock = new Block(BlockType.ARRAY);
|
||||
currentBlock.setName(name);
|
||||
currentBlock.setArray(new ArrayList<Object>());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(BigInteger value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(BigDecimal value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(long value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(double value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(Double.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(Boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(Boolean.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter writeNull() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.OBJECT) {
|
||||
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
|
||||
}
|
||||
currentBlock.getArray().add(null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, String value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, BigInteger value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, BigDecimal value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, long value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, double value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, Double.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, Boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter write(String name, boolean value) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, Boolean.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter writeNull(String name) throws IOException {
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
throw new IOException("Named JSON elements can only be created in JSON objects");
|
||||
}
|
||||
currentBlock.getObject().put(name, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter endObject() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
ourLog.error("JsonLikeStreamWriter.endObject(); called with no active JSON document");
|
||||
} else {
|
||||
if (currentBlock.getType() != BlockType.OBJECT) {
|
||||
ourLog.error("JsonLikeStreamWriter.endObject(); called outside a JSON object. (Use endArray() instead?)");
|
||||
}
|
||||
endBlock();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter endArray() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
ourLog.error("JsonLikeStreamWriter.endArray(); called with no active JSON document");
|
||||
} else {
|
||||
if (currentBlock.getType() != BlockType.ARRAY) {
|
||||
ourLog.error("JsonLikeStreamWriter.endArray(); called outside a JSON array. (Use endObject() instead?)");
|
||||
}
|
||||
endBlock();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter endBlock() throws IOException {
|
||||
if (currentBlock.getType() == BlockType.NONE) {
|
||||
ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
|
||||
} else {
|
||||
Object toPut = null;
|
||||
if (currentBlock.getType() == BlockType.ARRAY) {
|
||||
toPut = currentBlock.getArray();
|
||||
} else {
|
||||
toPut = currentBlock.getObject();
|
||||
}
|
||||
Block parentBlock = blockStack.pop();
|
||||
if (parentBlock.getType() == BlockType.OBJECT) {
|
||||
parentBlock.getObject().put(currentBlock.getName(), toPut);
|
||||
} else
|
||||
if (parentBlock.getType() == BlockType.ARRAY) {
|
||||
parentBlock.getArray().add(toPut);
|
||||
}
|
||||
currentBlock = parentBlock;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class JsonLikeMapStructure implements JsonLikeStructure {
|
||||
|
||||
private Map<String,Object> nativeObject;
|
||||
private JsonLikeObject jsonLikeObject = null;
|
||||
private JsonLikeMapWriter jsonLikeWriter = null;
|
||||
|
||||
public JsonLikeMapStructure() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JsonLikeMapStructure (Map<String,Object> json) {
|
||||
super();
|
||||
setNativeObject(json);
|
||||
}
|
||||
|
||||
public void setNativeObject (Map<String,Object> json) {
|
||||
this.nativeObject = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeStructure getInstance() {
|
||||
return new JsonLikeMapStructure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter getJsonLikeWriter (Writer ignored) {
|
||||
return getJsonLikeWriter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeWriter getJsonLikeWriter () {
|
||||
if (null == jsonLikeWriter) {
|
||||
jsonLikeWriter = new JsonLikeMapWriter();
|
||||
}
|
||||
return jsonLikeWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Reader reader) throws DataFormatException {
|
||||
this.load(reader, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Reader theReader, boolean allowArray) throws DataFormatException {
|
||||
throw new DataFormatException("JSON structure loading is not supported for native Java Map structures");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeObject getRootObject() {
|
||||
if (null == jsonLikeObject) {
|
||||
jsonLikeObject = new JsonMapObject(nativeObject);
|
||||
}
|
||||
return jsonLikeObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeArray getRootArray() throws DataFormatException {
|
||||
throw new DataFormatException("JSON document must be an object not an array for native Java Map structures");
|
||||
}
|
||||
|
||||
private class JsonMapObject extends JsonLikeObject {
|
||||
private Map<String,Object> nativeObject;
|
||||
private Map<String,JsonLikeValue> jsonLikeMap = new LinkedHashMap<String,JsonLikeValue>();
|
||||
|
||||
public JsonMapObject (Map<String,Object> json) {
|
||||
this.nativeObject = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return nativeObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return nativeObject.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeValue get(String key) {
|
||||
JsonLikeValue result = null;
|
||||
if (jsonLikeMap.containsKey(key)) {
|
||||
result = jsonLikeMap.get(key);
|
||||
} else {
|
||||
Object child = nativeObject.get(key);
|
||||
if (child != null) {
|
||||
result = new JsonMapValue(child);
|
||||
}
|
||||
jsonLikeMap.put(key, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private class JsonMapArray extends JsonLikeArray {
|
||||
private List<Object> nativeArray;
|
||||
private Map<Integer,JsonLikeValue> jsonLikeMap = new LinkedHashMap<Integer,JsonLikeValue>();
|
||||
|
||||
public JsonMapArray (List<Object> json) {
|
||||
this.nativeArray = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return nativeArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return nativeArray.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeValue get(int index) {
|
||||
Integer key = Integer.valueOf(index);
|
||||
JsonLikeValue result = null;
|
||||
if (jsonLikeMap.containsKey(key)) {
|
||||
result = jsonLikeMap.get(key);
|
||||
} else {
|
||||
Object child = nativeArray.get(index);
|
||||
if (child != null) {
|
||||
result = new JsonMapValue(child);
|
||||
}
|
||||
jsonLikeMap.put(key, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private class JsonMapValue extends JsonLikeValue {
|
||||
private Object nativeValue;
|
||||
private JsonLikeObject jsonLikeObject = null;
|
||||
private JsonLikeArray jsonLikeArray = null;
|
||||
|
||||
public JsonMapValue (Object json) {
|
||||
this.nativeValue = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return nativeValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueType getJsonType() {
|
||||
if (isNull()) {
|
||||
return ValueType.NULL;
|
||||
}
|
||||
if (isObject()) {
|
||||
return ValueType.OBJECT;
|
||||
}
|
||||
if (isArray()) {
|
||||
return ValueType.ARRAY;
|
||||
}
|
||||
return ValueType.SCALAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType getDataType() {
|
||||
if (isString()) {
|
||||
return ScalarType.STRING;
|
||||
}
|
||||
if (isNumber()) {
|
||||
return ScalarType.NUMBER;
|
||||
}
|
||||
if (isBoolean()) {
|
||||
return ScalarType.BOOLEAN;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JsonLikeArray getAsArray() {
|
||||
if (nativeValue != null && isArray()) {
|
||||
if (null == jsonLikeArray) {
|
||||
jsonLikeArray = new JsonMapArray((List<Object>)nativeValue);
|
||||
}
|
||||
}
|
||||
return jsonLikeArray;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JsonLikeObject getAsObject() {
|
||||
if (nativeValue != null && isObject()) {
|
||||
if (null == jsonLikeObject) {
|
||||
jsonLikeObject = new JsonMapObject((Map<String,Object>)nativeValue);
|
||||
}
|
||||
}
|
||||
return jsonLikeObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsString() {
|
||||
String result = null;
|
||||
if (nativeValue != null) {
|
||||
result = nativeValue.toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
if (nativeValue != null && isBoolean()) {
|
||||
return ((Boolean)nativeValue).booleanValue();
|
||||
}
|
||||
return super.getAsBoolean();
|
||||
}
|
||||
|
||||
public boolean isObject () {
|
||||
return (nativeValue != null)
|
||||
&& ( (nativeValue instanceof Map) || Map.class.isAssignableFrom(nativeValue.getClass()) );
|
||||
}
|
||||
|
||||
public boolean isArray () {
|
||||
return (nativeValue != null)
|
||||
&& ( (nativeValue instanceof List) || List.class.isAssignableFrom(nativeValue.getClass()));
|
||||
}
|
||||
|
||||
public boolean isString () {
|
||||
return (nativeValue != null)
|
||||
&& ( (nativeValue instanceof String) || String.class.isAssignableFrom(nativeValue.getClass()));
|
||||
}
|
||||
|
||||
public boolean isNumber () {
|
||||
return (nativeValue != null)
|
||||
&& ( (nativeValue instanceof Number) || Number.class.isAssignableFrom(nativeValue.getClass()) );
|
||||
}
|
||||
|
||||
public boolean isBoolean () {
|
||||
return (nativeValue != null)
|
||||
&& ( (nativeValue instanceof Boolean) || Boolean.class.isAssignableFrom(nativeValue.getClass()) );
|
||||
}
|
||||
|
||||
public boolean isNull () {
|
||||
return (null == nativeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
pom.xml
9
pom.xml
|
@ -563,7 +563,7 @@
|
|||
<slf4j_version>1.7.25</slf4j_version>
|
||||
<spring_version>5.1.3.RELEASE</spring_version>
|
||||
<spring_data_version>2.1.3.RELEASE</spring_data_version>
|
||||
<spring-boot.version>2.1.1.RELEASE</spring-boot.version>
|
||||
<spring_boot_version>2.1.1.RELEASE</spring_boot_version>
|
||||
<spring_retry_version>1.2.2.RELEASE</spring_retry_version>
|
||||
|
||||
<stax2_api_version>3.1.4</stax2_api_version>
|
||||
|
@ -1256,6 +1256,11 @@
|
|||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring_boot_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
|
@ -1334,7 +1339,7 @@
|
|||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<version>${spring_boot_version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
|
|
Loading…
Reference in New Issue