All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.example.consumer1.Consumer Maven / Gradle / Ivy

Go to download

SDCri is a set of Java libraries that implements a network communication framework conforming with the IEEE 11073 SDC specifications. This project implements examples for using the glue package.

There is a newer version: 5.1.1
Show newest version
package com.example.consumer1;

import com.example.Constants;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.google.inject.Injector;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.somda.sdc.biceps.common.CodedValueUtil;
import org.somda.sdc.biceps.common.MdibEntity;
import org.somda.sdc.biceps.common.access.MdibAccess;
import org.somda.sdc.biceps.model.message.Activate;
import org.somda.sdc.biceps.model.message.ActivateResponse;
import org.somda.sdc.biceps.model.message.InvocationState;
import org.somda.sdc.biceps.model.message.OperationInvokedReport;
import org.somda.sdc.biceps.model.message.SetString;
import org.somda.sdc.biceps.model.message.SetStringResponse;
import org.somda.sdc.biceps.model.message.SetValue;
import org.somda.sdc.biceps.model.message.SetValueResponse;
import org.somda.sdc.biceps.model.participant.AbstractContextState;
import org.somda.sdc.biceps.model.participant.AbstractDescriptor;
import org.somda.sdc.biceps.model.participant.ActivateOperationDescriptor;
import org.somda.sdc.biceps.model.participant.CodedValue;
import org.somda.sdc.biceps.model.participant.EnumStringMetricDescriptor;
import org.somda.sdc.biceps.model.participant.LocationContextState;
import org.somda.sdc.biceps.model.participant.MdibVersion;
import org.somda.sdc.biceps.model.participant.PatientContextState;
import org.somda.sdc.biceps.model.participant.SetStringOperationDescriptor;
import org.somda.sdc.biceps.model.participant.SetValueOperationDescriptor;
import org.somda.sdc.dpws.DpwsFramework;
import org.somda.sdc.dpws.client.Client;
import org.somda.sdc.dpws.client.DiscoveredDevice;
import org.somda.sdc.dpws.client.DiscoveryObserver;
import org.somda.sdc.dpws.client.event.ProbedDeviceFoundMessage;
import org.somda.sdc.dpws.service.HostingServiceProxy;
import org.somda.sdc.dpws.soap.exception.TransportException;
import org.somda.sdc.dpws.soap.interception.InterceptorException;
import org.somda.sdc.dpws.wsdl.WsdlRetriever;
import org.somda.sdc.glue.consumer.ConnectConfiguration;
import org.somda.sdc.glue.consumer.PrerequisitesException;
import org.somda.sdc.glue.consumer.SdcDiscoveryFilterBuilder;
import org.somda.sdc.glue.consumer.SdcRemoteDevice;
import org.somda.sdc.glue.consumer.SdcRemoteDevicesConnector;
import org.somda.sdc.glue.consumer.SetServiceAccess;
import org.somda.sdc.glue.consumer.sco.ScoTransaction;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;


/**
 * This is an example consumer which matches {@link com.example.provider1.Provider} in functionality
 * 

* This consumer executes the following steps and prints whether each step was successful * 1. discovery of device with specific endpoint * 2. connect to device with specific endpoint * 3. read mdib of provider * 4. subscribe metrics, alerts, waveforms * 5. check that least one patient context exists * 6. check that at least one location context exists * 7. check that the metric (see above) changes within 30 seconds at least 5 times * 8. check that the alert condition (see above)change within 30 seconds at least 5 times * 9. execute operations (Activate, SetString, SetValue) as specified and check that result is “finished” */ public class Consumer { private static final Logger LOG = LogManager.getLogger(Consumer.class); private static final Duration MAX_WAIT = Duration.ofSeconds(11); private static final long MAX_WAIT_SEC = MAX_WAIT.getSeconds(); private static final long REPORT_TIMEOUT = Duration.ofSeconds(30).toMillis(); private final ConsumerUtil consumerUtil; private final Client client; private final SdcRemoteDevicesConnector connector; private final Injector injector; private final NetworkInterface networkInterface; private DpwsFramework dpwsFramework; /** * Creates an SDC Consumer instance. * * @param consumerUtil utility containing injector and settings * @throws SocketException if network adapter couldn't be bound * @throws UnknownHostException if localhost couldn't be determined */ public Consumer(ConsumerUtil consumerUtil) throws SocketException, UnknownHostException { this.consumerUtil = consumerUtil; this.injector = consumerUtil.getInjector(); this.client = injector.getInstance(Client.class); this.connector = injector.getInstance(SdcRemoteDevicesConnector.class); if (consumerUtil.getIface() != null && !consumerUtil.getIface().isBlank()) { LOG.info("Starting with interface {}", consumerUtil.getIface()); this.networkInterface = NetworkInterface.getByName(consumerUtil.getIface()); } else { if (consumerUtil.getAddress() != null && !consumerUtil.getAddress().isBlank()) { // bind to adapter matching ip LOG.info("Starting with address {}", consumerUtil.getAddress()); this.networkInterface = NetworkInterface.getByInetAddress( InetAddress.getByName(consumerUtil.getAddress()) ); } else { // find loopback interface for fallback networkInterface = NetworkInterface.getByInetAddress(InetAddress.getLoopbackAddress()); LOG.info("Starting with fallback default adapter {}", networkInterface); } } } public Client getClient() { return client; } public SdcRemoteDevicesConnector getConnector() { return connector; } protected void startUp() { // provide the name of your network adapter this.dpwsFramework = injector.getInstance(DpwsFramework.class); this.dpwsFramework.setNetworkInterface(networkInterface); dpwsFramework.startAsync().awaitRunning(); client.startAsync().awaitRunning(); } protected void shutDown() { client.stopAsync().awaitTerminated(); dpwsFramework.stopAsync().awaitTerminated(); } /** * Synchronously invokes an ActivateOperation on a given SetService using the provided handle and arguments * * @param setServiceAccess SetService to call Activate on * @param handle operation handle * @param args activate arguments * @return InvocationState of final OperationInvokedReport * @throws ExecutionException if retrieving the final OperationInvokedReport is aborted * @throws InterruptedException if retrieving the final OperationInvokedReport is interrupted * @throws TimeoutException if retrieving the final OperationInvokedReport times out */ static InvocationState invokeActivate(SetServiceAccess setServiceAccess, String handle, List args) throws ExecutionException, InterruptedException, TimeoutException { LOG.info("Invoking Activate for handle {} with arguments {}", handle, args); Activate activate = new Activate(); List argumentList = args.stream().map(x -> { var arg = new Activate.Argument(); arg.setArgValue(x); return arg; }).collect(Collectors.toList()); activate.setArgument(argumentList); activate.setOperationHandleRef(handle); final ListenableFuture> activateFuture = setServiceAccess .invoke(activate, ActivateResponse.class); ScoTransaction activateResponse = activateFuture.get(MAX_WAIT_SEC, TimeUnit.SECONDS); if (InvocationState.FAIL == activateResponse.getResponse().getInvocationInfo().getInvocationState()) { var err = "Activate operation execution invocation state failed"; throw new ExecutionException(err, new InterruptedException(err)); } List> reportParts = activateResponse.waitForFinalReport(Duration.ofSeconds(5)); // return the final reports invocation state if (!reportParts.isEmpty()) { return reportParts.get(reportParts.size() - 1).getLeft().getInvocationInfo().getInvocationState(); } else { throw new InterruptedException("No report parts received, help."); } } /** * Synchronously invokes a SetValue on a given SetService using the provided handle and argument * * @param setServiceAccess SetService to call Activate on * @param handle operation handle * @param value desired value of operation target * @return InvocationState of final OperationInvokedReport * @throws ExecutionException if retrieving the final OperationInvokedReport is aborted * @throws InterruptedException if retrieving the final OperationInvokedReport is interrupted * @throws TimeoutException if retrieving the final OperationInvokedReport times out */ static InvocationState invokeSetValue(SetServiceAccess setServiceAccess, String handle, BigDecimal value) throws ExecutionException, InterruptedException, TimeoutException { LOG.info("Invoking SetValue for handle {} with value {}", handle, value); SetValue setValue = new SetValue(); setValue.setOperationHandleRef(handle); setValue.setRequestedNumericValue(value); final ListenableFuture> setValueFuture = setServiceAccess .invoke(setValue, SetValueResponse.class); ScoTransaction setValueResponse = setValueFuture.get(MAX_WAIT_SEC, TimeUnit.SECONDS); if (InvocationState.FAIL == setValueResponse.getResponse().getInvocationInfo().getInvocationState()) { var err = "SetValue operation execution invocation state failed"; throw new ExecutionException(err, new InterruptedException(err)); } var reportParts = setValueResponse.waitForFinalReport(Duration.ofSeconds(5)); // return the final reports invocation state if (!reportParts.isEmpty()) { return reportParts.get(reportParts.size() - 1).getLeft().getInvocationInfo().getInvocationState(); } else { throw new InterruptedException("No report parts received, help."); } } /** * Synchronously invokes a SetString on a given SetService using the provided handle and argument * * @param setServiceAccess SetService to call Activate on * @param handle operation handle * @param value desired value of operation target * @return InvocationState of final OperationInvokedReport * @throws ExecutionException if retrieving the final OperationInvokedReport is aborted * @throws InterruptedException if retrieving the final OperationInvokedReport is interrupted * @throws TimeoutException if retrieving the final OperationInvokedReport times out */ static InvocationState invokeSetString(SetServiceAccess setServiceAccess, String handle, String value) throws ExecutionException, InterruptedException, TimeoutException { LOG.info("Invoking SetString for handle {} with value {}", handle, value); SetString setString = new SetString(); setString.setOperationHandleRef(handle); setString.setRequestedStringValue(value); final ListenableFuture> setStringFuture = setServiceAccess .invoke(setString, SetStringResponse.class); ScoTransaction setStringResponse = setStringFuture.get(MAX_WAIT_SEC, TimeUnit.SECONDS); if (InvocationState.FAIL == setStringResponse.getResponse().getInvocationInfo().getInvocationState()) { var err = "SetString operation execution invocation state failed"; throw new ExecutionException(err, new InterruptedException(err)); } var reportParts = setStringResponse.waitForFinalReport(Duration.ofSeconds(5)); // return the final reports invocation state if (!reportParts.isEmpty()) { return reportParts.get(reportParts.size() - 1).getLeft().getInvocationInfo().getInvocationState(); } else { throw new InterruptedException("No report parts received, help."); } } static List getHandleForCodedValue(MdibAccess mdib, CodedValue value, Class type) { // find all applicable entities var entities = mdib.findEntitiesByType(type); // filter by coded value return entities.stream().filter( x -> CodedValueUtil.isEqual(x.getDescriptor().getType(), value) ).map(MdibEntity::getHandle).collect(Collectors.toList()); } static List> getPathToCodedValue(MdibAccess mdib, CodedValue value, Class type) { // find all applicable entities var entities = mdib.findEntitiesByType(type); // filter by coded value var applicableEntities = entities.stream().filter( x -> CodedValueUtil.isEqual(x.getDescriptor().getType(), value) ).toList(); return applicableEntities.stream().map(entity -> { MdibEntity currentEntity = entity; var handles = new ArrayList(); while (currentEntity != null) { var handle = currentEntity.getHandle(); handles.add(0, handle); // get parent entity if (currentEntity.getParent().isPresent()) { currentEntity = mdib.getEntity(currentEntity.getParent().get()).orElse(null); } else { // exit currentEntity = null; } } return handles; }).collect(Collectors.toList()); } public Injector getInjector() { return injector; } public static void main(String[] args) throws SocketException, UnknownHostException, InterceptorException, TransportException, InterruptedException { var settings = new ConsumerUtil(args); var targetEpr = settings.getEpr(); var consumer = new Consumer(settings); consumer.startUp(); // this map is used to track the outcome of each of the nine steps listed for this class Map resultMap = new HashMap<>( Map.of( 1, false, 2, false, 3, false, 4, false, 5, false, 6, false, 7, false, 8, false, 9, false, 10, false ) ); Runtime.getRuntime().addShutdownHook(new Thread(() -> { var keys = new ArrayList<>(resultMap.keySet()); Collections.sort(keys); keys.forEach(key -> System.out.printf("### Test %s ### %s%n", key, resultMap.get(key) ? "passed" : "failed")); })); // see if device using the provided epr address is available LOG.info("Starting discovery for {}", targetEpr); final SettableFuture xAddrs = SettableFuture.create(); DiscoveryObserver obs = new DiscoveryObserver() { @Subscribe void deviceFound(ProbedDeviceFoundMessage message) { DiscoveredDevice payload = message.getPayload(); if (payload.getEprAddress().equals(targetEpr)) { LOG.info("Found device with epr {}", payload.getEprAddress()); xAddrs.set(payload); } else { LOG.info("Found non-matching device with epr {}", payload.getEprAddress()); } } }; consumer.getClient().registerDiscoveryObserver(obs); // filter discovery for SDC devices only SdcDiscoveryFilterBuilder discoveryFilterBuilder = SdcDiscoveryFilterBuilder.create(); consumer.getClient().probe(discoveryFilterBuilder.get()); DiscoveredDevice d = null; try { List targetXAddrs = xAddrs.get(MAX_WAIT_SEC, TimeUnit.SECONDS).getXAddrs(); d = xAddrs.get(); resultMap.put(1, true); } catch (TimeoutException e) { xAddrs.cancel(true); LOG.error("Couldn't find target with EPR {} after {}s", targetEpr, MAX_WAIT_SEC, e); System.exit(1); } catch (InterruptedException | ExecutionException e) { LOG.error("Couldn't find target with EPR {}", targetEpr, e); System.exit(1); } consumer.getClient().unregisterDiscoveryObserver(obs); LOG.info("Connecting to {}", targetEpr); var hostingServiceFuture = consumer.getClient().connect(d); HostingServiceProxy hostingServiceProxy = null; try { hostingServiceProxy = hostingServiceFuture.get(MAX_WAIT_SEC, TimeUnit.SECONDS); resultMap.put(2, true); } catch (TimeoutException e) { xAddrs.cancel(true); LOG.error("Couldn't connect to EPR {} after {}s", targetEpr, MAX_WAIT_SEC, e); System.exit(1); } catch (InterruptedException | ExecutionException e) { LOG.error("Couldn't connect to EPR {}", targetEpr, e); System.exit(1); } // optionally retrieve the wsdl LOG.info("Retrieving device WSDL"); var wsdlRetriever = consumer.getInjector().getInstance(WsdlRetriever.class); try { var wsdls = wsdlRetriever.retrieveWsdls(hostingServiceProxy); LOG.debug("Retrieved WSDLs"); if (LOG.isDebugEnabled()) { wsdls.forEach((service, data) -> LOG.debug("WSDLs for service {}: {}", service, data)); } } catch (IOException e) { LOG.error("Could not retrieve WSDL", e); } LOG.info("Attaching to remote mdib and subscriptions for {}", targetEpr); ListenableFuture remoteDeviceFuture = null; SdcRemoteDevice sdcRemoteDevice = null; try { remoteDeviceFuture = consumer.getConnector() .connect( hostingServiceProxy, ConnectConfiguration.create(ConnectConfiguration.ALL_EPISODIC_AND_WAVEFORM_REPORTS) ); sdcRemoteDevice = remoteDeviceFuture.get(MAX_WAIT_SEC, TimeUnit.SECONDS); resultMap.put(3, true); resultMap.put(4, true); } catch (TimeoutException e) { remoteDeviceFuture.cancel(true); LOG.error("Couldn't attach to remote mdib and subscriptions for {} after {}s", targetEpr, MAX_WAIT_SEC, e); System.exit(1); } catch (PrerequisitesException | InterruptedException | ExecutionException e) { LOG.error("Couldn't attach to remote mdib and subscriptions for {}", targetEpr, e); System.exit(1); } // attach report listener var reportObs = new ConsumerReportProcessor(); sdcRemoteDevice.getMdibAccessObservable().registerObserver(reportObs); // verify that provider has at least one patient and location context attached List contextStates = sdcRemoteDevice.getMdibAccess().getContextStates(); // has patient long numPatientContexts = contextStates.stream() .filter(x -> PatientContextState.class.isAssignableFrom(x.getClass())).count(); resultMap.put(5, numPatientContexts >= 1); // has location context long numLocationContexts = contextStates.stream() .filter(x -> LocationContextState.class.isAssignableFrom(x.getClass())).count(); resultMap.put(6, numLocationContexts >= 1); // wait for incoming reports Thread.sleep(REPORT_TIMEOUT); // expected number of reports given 5 second interval long minNumberReports = (REPORT_TIMEOUT / Duration.ofSeconds(5).toMillis()) - 1; // verify the number of reports for the expected metrics is at least five during the timeout var metricChangesOk = reportObs.getMetricChanges().values().stream().anyMatch(changes -> changes >= minNumberReports); resultMap.put(7, metricChangesOk); if (!metricChangesOk) { LOG.info("Did not see enough metric changes, map: {}", reportObs.getMetricChanges()); } var conditionChangesOk = reportObs.getConditionChanges().values().stream().anyMatch(changes -> changes >= minNumberReports); resultMap.put(8, conditionChangesOk); if (!conditionChangesOk) { LOG.info("Did not see enough alert changes, map: {}", reportObs.getConditionChanges()); } // invoke all target operations var setServiceAccess = sdcRemoteDevice.getSetServiceAccess(); boolean operationFailed = false; // find set string operation handle var setStringHandles = getHandleForCodedValue( sdcRemoteDevice.getMdibAccess(), Constants.HANDLE_SET_STRING_CODE, SetStringOperationDescriptor.class ); LOG.info("Found {} handles matching code {}", setStringHandles.size(), Constants.HANDLE_SET_STRING_CODE); var setStringAnyPass = false; for (final String handle : setStringHandles) { try { LOG.info("Found handle {} and hardcoded handle was {}", handle, Constants.HANDLE_SET_STRING); invokeSetString(setServiceAccess, handle, "SDCri was here"); setStringAnyPass = true; } catch (ExecutionException | TimeoutException | InterruptedException | IndexOutOfBoundsException e) { LOG.error("Could not invoke {}", Constants.HANDLE_SET_STRING, e); } } if (!setStringAnyPass) { operationFailed = true; } // find set string operation handle for enum var paths = getPathToCodedValue( sdcRemoteDevice.getMdibAccess(), Constants.HANDLE_SET_STRING_ENUM_CODE, SetStringOperationDescriptor.class ); LOG.info("Found {} paths matching code {}", paths.size(), Constants.HANDLE_SET_STRING_ENUM_CODE); var setEnumStringAnyPass = false; for (final List path : paths) { try { var handle = path.get(path.size() - 1); LOG.info("Found handle {} and hardcoded handle was {}", handle, Constants.HANDLE_SET_STRING_ENUM); // get an allowed value var opDesc = (SetStringOperationDescriptor) sdcRemoteDevice.getMdibAccess().getDescriptor(handle).get(); var desc = (EnumStringMetricDescriptor) sdcRemoteDevice.getMdibAccess().getDescriptor(opDesc.getOperationTarget()).get(); var value = desc.getAllowedValue().get(0).getValue(); invokeSetString(setServiceAccess, handle, value); setEnumStringAnyPass = true; } catch (ExecutionException | TimeoutException | InterruptedException | IndexOutOfBoundsException e) { operationFailed = true; LOG.error("Could not invoke {}", Constants.HANDLE_SET_STRING_ENUM, e); } } if (!setEnumStringAnyPass) { operationFailed = true; } // find set value operation handle var setValueHandles = getHandleForCodedValue( sdcRemoteDevice.getMdibAccess(), Constants.HANDLE_SET_VALUE_CODE, SetValueOperationDescriptor.class ); LOG.info("Found {} setValueHandles matching code {}", setValueHandles.size(), Constants.HANDLE_SET_VALUE_CODE); var setValueAnyPass = false; for (final String handle : setValueHandles) { try { LOG.info("Found handle {} and hardcoded handle was {}", handle, Constants.HANDLE_SET_VALUE); invokeSetValue(setServiceAccess, handle, BigDecimal.valueOf(20)); setValueAnyPass = true; } catch (ExecutionException | TimeoutException | InterruptedException | IndexOutOfBoundsException e) { LOG.error("Could not invoke {}", Constants.HANDLE_SET_VALUE, e); } } if (!setValueAnyPass) { operationFailed = true; } // find activate operation handle var activatePaths = getPathToCodedValue( sdcRemoteDevice.getMdibAccess(), Constants.HANDLE_ACTIVATE_CODE, ActivateOperationDescriptor.class ); LOG.info("Found {} handles matching code {}", activatePaths.size(), Constants.HANDLE_ACTIVATE_CODE); var activateAnyPass = false; for (final List path : activatePaths) { try { var handle = path.get(path.size() - 1); LOG.info("Found handle {} and hardcoded handle was {}", handle, Constants.HANDLE_ACTIVATE); invokeActivate(setServiceAccess, handle, Collections.emptyList()); activateAnyPass = true; } catch (ExecutionException | TimeoutException | InterruptedException | IndexOutOfBoundsException e) { LOG.error("Could not invoke {}", Constants.HANDLE_ACTIVATE, e); } } if (!activateAnyPass) { operationFailed = true; } resultMap.put(9, !operationFailed); LOG.info("Done, quitting"); sdcRemoteDevice.getMdibAccessObservable().unregisterObserver(reportObs); sdcRemoteDevice.stopAsync().awaitTerminated(); try { var disconnectDone = consumer.getConnector().disconnect(targetEpr).isDone(); consumer.shutDown(); resultMap.put(10, disconnectDone); } catch (Exception e) { LOG.warn("Disconnect failed", e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy