summaryrefslogtreecommitdiffstats
path: root/services/services-engine/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'services/services-engine/src/main')
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessageListener.java364
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessagingService.java107
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/package-info.java26
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEvent.java342
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConsumer.java80
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConverter.java55
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventException.java51
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventList.java32
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProducer.java81
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProtocolConverter.java39
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventReceiver.java46
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventRuntimeException.java51
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexPeriodicEventGenerator.java176
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/PeeredReference.java70
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/SynchronousEventCache.java294
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventConsumerFactory.java83
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProducerFactory.java82
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProtocolFactory.java76
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/Apex2ApexEventConverter.java140
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/ApexEventProtocolParameters.java58
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/package-info.java27
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/ApexEvent2EnEventConverter.java143
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/package-info.java28
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorCarrierTechnologyParameters.java67
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorConsumer.java218
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorProducer.java178
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/package-info.java26
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/FILECarrierTechnologyParameters.java208
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/ApexFileEventConsumer.java247
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/CharacterDelimitedTextBlockReader.java141
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/HeaderDelimitedTextBlockReader.java167
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlock.java78
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReader.java46
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReaderFactory.java80
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/package-info.java27
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/package-info.java27
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/ApexFileEventProducer.java181
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/package-info.java27
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/Apex2JSONEventConverter.java433
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/JSONEventProtocolParameters.java135
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/package-info.java27
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/package-info.java30
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/package-info.java32
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivator.java193
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorException.java51
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorRuntimeException.java52
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexCommandLineArguments.java285
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEngineServiceHandler.java88
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventMarshaller.java232
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventUnmarshaller.java323
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexMain.java169
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/package-info.java27
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/package-info.java28
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/ApexEventListener.java41
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineService.java214
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineServiceEventInterface.java39
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EnEventListenerImpl.java71
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineServiceImpl.java682
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineWorker.java674
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/package-info.java27
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/package-info.java28
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterException.java52
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterHandler.java100
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterRuntimeException.java52
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterValidator.java36
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameters.java357
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParameters.java161
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParametersJSONAdapter.java176
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/package-info.java26
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParameters.java329
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParametersJSONAdapter.java287
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/package-info.java26
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerParameters.java362
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerPeeredMode.java42
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/package-info.java26
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParameters.java123
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParametersJSONAdapter.java172
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextCharDelimitedParameters.java122
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextTokenDelimitedParameters.java95
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/package-info.java26
-rw-r--r--services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/package-info.java29
-rw-r--r--services/services-engine/src/main/resources/version.txt4
82 files changed, 10653 insertions, 0 deletions
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessageListener.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessageListener.java
new file mode 100644
index 000000000..311e3b660
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessageListener.java
@@ -0,0 +1,364 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.engdep;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.TimeUnit;
+
+import org.java_websocket.WebSocket;
+import org.onap.policy.apex.core.infrastructure.messaging.MessageHolder;
+import org.onap.policy.apex.core.infrastructure.messaging.MessageListener;
+import org.onap.policy.apex.core.infrastructure.messaging.impl.ws.messageblock.MessageBlock;
+import org.onap.policy.apex.core.infrastructure.messaging.util.MessagingUtils;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.core.protocols.Message;
+import org.onap.policy.apex.core.protocols.engdep.EngDepAction;
+import org.onap.policy.apex.core.protocols.engdep.messages.EngineServiceInfoResponse;
+import org.onap.policy.apex.core.protocols.engdep.messages.GetEngineInfo;
+import org.onap.policy.apex.core.protocols.engdep.messages.GetEngineServiceInfo;
+import org.onap.policy.apex.core.protocols.engdep.messages.GetEngineStatus;
+import org.onap.policy.apex.core.protocols.engdep.messages.Response;
+import org.onap.policy.apex.core.protocols.engdep.messages.StartEngine;
+import org.onap.policy.apex.core.protocols.engdep.messages.StartPeriodicEvents;
+import org.onap.policy.apex.core.protocols.engdep.messages.StopEngine;
+import org.onap.policy.apex.core.protocols.engdep.messages.StopPeriodicEvents;
+import org.onap.policy.apex.core.protocols.engdep.messages.UpdateModel;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.service.engine.runtime.EngineService;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * The listener interface for receiving engDepMessage events. The class that is interested in
+ * processing a engDepMessage event implements this interface, and the object created with that
+ * class is registered with a component using the component's <code>addEngDepMessageListener</code>
+ * method. When the engDepMessage event occurs, that object's appropriate method is invoked.
+ *
+ * This class uses a queue to buffer incoming messages. When the listener is called, it places the
+ * incoming message on the queue. A thread runs which removes the messages from the queue and
+ * forwards them to the Apex engine.
+ *
+ * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com)
+ */
+public class EngDepMessageListener implements MessageListener<Message>, Runnable {
+ private static final int LISTENER_STOP_WAIT_INTERVAL = 10;
+
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EngDepMessageListener.class);
+
+ // The timeout to wait between queue poll timeouts in milliseconds
+ private static final long QUEUE_POLL_TIMEOUT = 50;
+
+ // The Apex service itself
+ private final EngineService apexService;
+
+ // The message listener thread and stopping flag
+ private Thread messageListenerThread;
+ private boolean stopOrderedFlag = false;
+
+ // The message queue is used to hold messages prior to forwarding to Apex
+ private final BlockingQueue<MessageBlock<Message>> messageQueue = new LinkedBlockingDeque<>();
+
+ /**
+ * Instantiates a new EngDep message listener for listening for messages coming in from the
+ * Deployment client. The <code>apexService</code> is the Apex service to send the messages
+ * onto.
+ *
+ * @param apexService the Apex engine service
+ */
+ protected EngDepMessageListener(final EngineService apexService) {
+ this.apexService = apexService;
+ }
+
+ /**
+ * This method is an implementation of the message listener. It receives a message and places it
+ * on the queue for processing by the message listening thread.
+ *
+ * @param data the data
+ * @see org.onap.policy.apex.core.infrastructure.messaging.MessageListener#onMessage
+ * (org.onap.policy.apex.core.infrastructure.messaging.impl.ws.data.Data)
+ */
+ @Subscribe
+ @Override
+ public void onMessage(final MessageBlock<Message> data) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("message received from client application {} port {}",
+ data.getConnection().getRemoteSocketAddress().getAddress(),
+ data.getConnection().getRemoteSocketAddress().getPort());
+ }
+ messageQueue.add(data);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.core.infrastructure.messaging.MessageListener#onMessage(java.lang.
+ * String)
+ */
+ @Override
+ public void onMessage(final String messageString) {
+ throw new UnsupportedOperationException("String messages are not supported on the EngDep protocol");
+ }
+
+ /**
+ * This method gets a new message listening thread from the thread factory and starts it.
+ */
+ public void startProcessorThread() {
+ LOGGER.entry();
+ messageListenerThread = new Thread(this);
+ messageListenerThread.setDaemon(true);
+ messageListenerThread.start();
+ LOGGER.exit();
+ }
+
+ /**
+ * Stops the message listening threads.
+ */
+ public void stopProcessorThreads() {
+ LOGGER.entry();
+ stopOrderedFlag = true;
+
+ while (messageListenerThread.isAlive()) {
+ ThreadUtilities.sleep(LISTENER_STOP_WAIT_INTERVAL);
+ }
+ LOGGER.exit();
+ }
+
+ /**
+ * Runs the message listening thread. Here, the messages come in on the message queue and are
+ * processed one by one
+ */
+ @Override
+ public void run() {
+ // Take messages off the queue and forward them to the Apex engine
+ while (messageListenerThread.isAlive() && !stopOrderedFlag) {
+ try {
+ final MessageBlock<Message> data = messageQueue.poll(QUEUE_POLL_TIMEOUT, TimeUnit.MILLISECONDS);
+ if (data != null) {
+ final List<Message> messages = data.getMessages();
+ for (final Message message : messages) {
+ handleMessage(message, data.getConnection());
+ }
+ }
+ } catch (final InterruptedException e) {
+ LOGGER.debug("message listener execution has been interrupted");
+ break;
+ }
+ }
+ }
+
+ /**
+ * This method handles EngDep messages as they come in. It uses the inevitable switch statement
+ * to handle the messages.
+ *
+ * @param message the incoming EngDep message
+ * @param webSocket the web socket on which the message came in
+ */
+ private void handleMessage(final Message message, final WebSocket webSocket) {
+ LOGGER.entry(webSocket.getRemoteSocketAddress().toString());
+ if (message.getAction() == null) {
+ // This is a response message
+ return;
+ }
+
+ try {
+ LOGGER.debug("Manager action {} being applied to engine", message.getAction());
+
+ // Get and check the incoming action for validity
+ EngDepAction enDepAction = null;
+ if (message.getAction() instanceof EngDepAction) {
+ enDepAction = (EngDepAction) message.getAction();
+ } else {
+ throw new ApexException(message.getAction().getClass().getName()
+ + "action on received message invalid, action must be of type \"EnDepAction\"");
+ }
+
+ // Handle each incoming message using the inevitable switch statement for the EngDep
+ // protocol
+ switch (enDepAction) {
+ case GET_ENGINE_SERVICE_INFO:
+ final GetEngineServiceInfo engineServiceInformationMessage = (GetEngineServiceInfo) message;
+ LOGGER.debug("getting engine service information for engine service " + apexService.getKey().getID()
+ + " . . .");
+ // Send a reply with the engine service information
+ sendServiceInfoReply(webSocket, engineServiceInformationMessage, apexService.getKey(),
+ apexService.getEngineKeys(), apexService.getApexModelKey());
+ LOGGER.debug(
+ "returned engine service information for engine service " + apexService.getKey().getID());
+ break;
+
+ case UPDATE_MODEL:
+ final UpdateModel updateModelMessage = (UpdateModel) message;
+ LOGGER.debug("updating model in engine {} . . .", updateModelMessage.getTarget().getID());
+ // Update the model
+ apexService.updateModel(updateModelMessage.getTarget(), updateModelMessage.getMessageData(),
+ updateModelMessage.isForceInstall());
+ // Send a reply indicating the message action worked
+ sendReply(webSocket, updateModelMessage, true,
+ "updated model in engine " + updateModelMessage.getTarget().getID());
+ LOGGER.debug("updated model in engine service {}", updateModelMessage.getTarget().getID());
+ break;
+
+ case START_ENGINE:
+ final StartEngine startEngineMessage = (StartEngine) message;
+ LOGGER.debug("starting engine {} . . .", startEngineMessage.getTarget().getID());
+ // Start the engine
+ apexService.start(startEngineMessage.getTarget());
+ // Send a reply indicating the message action worked
+ sendReply(webSocket, startEngineMessage, true,
+ "started engine " + startEngineMessage.getTarget().getID());
+ LOGGER.debug("started engine {}", startEngineMessage.getTarget().getID());
+ break;
+
+ case STOP_ENGINE:
+ final StopEngine stopEngineMessage = (StopEngine) message;
+ LOGGER.debug("stopping engine {} . . .", stopEngineMessage.getTarget().getID());
+ // Stop the engine
+ apexService.stop(stopEngineMessage.getTarget());
+ // Send a reply indicating the message action worked
+ sendReply(webSocket, stopEngineMessage, true,
+ "stopped engine " + stopEngineMessage.getTarget().getID());
+ LOGGER.debug("stopping engine {}", stopEngineMessage.getTarget().getID());
+ break;
+
+ case START_PERIODIC_EVENTS:
+ final StartPeriodicEvents startPeriodicEventsMessage = (StartPeriodicEvents) message;
+ LOGGER.debug("starting periodic events on engine {} . . .",
+ startPeriodicEventsMessage.getTarget().getID());
+ // Start periodic events with the period specified in the message
+ final Long period = Long.parseLong(startPeriodicEventsMessage.getMessageData());
+ apexService.startPeriodicEvents(period);
+ // Send a reply indicating the message action worked
+ sendReply(webSocket, startPeriodicEventsMessage, true, "started periodic events on engine "
+ + startPeriodicEventsMessage.getTarget().getID() + " with period " + period);
+ LOGGER.debug("started periodic events on engine " + startPeriodicEventsMessage.getTarget().getID()
+ + " with period " + period);
+ break;
+
+ case STOP_PERIODIC_EVENTS:
+ final StopPeriodicEvents stopPeriodicEventsMessage = (StopPeriodicEvents) message;
+ LOGGER.debug("stopping periodic events on engine {} . . .",
+ stopPeriodicEventsMessage.getTarget().getID());
+ // Stop periodic events
+ apexService.stopPeriodicEvents();
+ // Send a reply indicating the message action worked
+ sendReply(webSocket, stopPeriodicEventsMessage, true,
+ "stopped periodic events on engine " + stopPeriodicEventsMessage.getTarget().getID());
+ LOGGER.debug("stopped periodic events on engine " + stopPeriodicEventsMessage.getTarget().getID());
+ break;
+
+ case GET_ENGINE_STATUS:
+ final GetEngineStatus getEngineStatusMessage = (GetEngineStatus) message;
+ LOGGER.debug("getting status for engine{} . . .", getEngineStatusMessage.getTarget().getID());
+ // Send a reply with the engine status
+ sendReply(webSocket, getEngineStatusMessage, true,
+ apexService.getStatus(getEngineStatusMessage.getTarget()));
+ LOGGER.debug("returned status for engine {}", getEngineStatusMessage.getTarget().getID());
+ break;
+
+ case GET_ENGINE_INFO:
+ final GetEngineInfo getEngineInfo = (GetEngineInfo) message;
+ LOGGER.debug("getting runtime information for engine {} . . .", getEngineInfo.getTarget().getID());
+ // Send a reply with the engine runtime information
+ sendReply(webSocket, getEngineInfo, true, apexService.getRuntimeInfo(getEngineInfo.getTarget()));
+ LOGGER.debug("returned runtime information for engine {}", getEngineInfo.getTarget().getID());
+ break;
+ case RESPONSE:
+ throw new ApexException("RESPONSE action on received message not handled by engine");
+
+ default:
+ break;
+ }
+ } catch (final ApexException e) {
+ LOGGER.warn("apex failed to execute message", e);
+ sendReply(webSocket, message, false, e.getCascadedMessage());
+ } catch (final Exception e) {
+ LOGGER.warn("system failure executing message", e);
+ sendReply(webSocket, message, false, e.getMessage());
+ }
+ LOGGER.exit();
+ }
+
+ /**
+ * Send the Response message to the client.
+ *
+ * @param client the client to which to send the response message
+ * @param requestMessage the message to which we are responding
+ * @param result the result indicating success or failure
+ * @param messageData the message data
+ */
+ private void sendReply(final WebSocket client, final Message requestMessage, final boolean result,
+ final String messageData) {
+ LOGGER.entry(result, messageData);
+
+ if (client == null || !client.isOpen()) {
+ LOGGER.debug("error sending reply {}, client has disconnected", requestMessage.getAction());
+ return;
+ }
+
+ LOGGER.debug("sending {} to web socket {}", requestMessage.getAction(),
+ client.getRemoteSocketAddress().toString());
+
+ final Response responseMessage = new Response(requestMessage.getTarget(), result, requestMessage);
+ responseMessage.setMessageData(messageData);
+
+ final MessageHolder<Message> messageHolder = new MessageHolder<>(MessagingUtils.getHost());
+ messageHolder.addMessage(responseMessage);
+ client.send(MessagingUtils.serializeObject(messageHolder));
+
+ LOGGER.exit();
+ }
+
+ /**
+ * Send the EngineServiceInfoResponse message to the client.
+ *
+ * @param client the client to which to send the response message
+ * @param requestMessage the message to which we are responding
+ * @param engineServiceKey The key of this engine service
+ * @param engineKeyCollection The keys of the engines in this engine service
+ * @param apexModelKey the apex model key
+ */
+ private void sendServiceInfoReply(final WebSocket client, final Message requestMessage,
+ final AxArtifactKey engineServiceKey, final Collection<AxArtifactKey> engineKeyCollection,
+ final AxArtifactKey apexModelKey) {
+ LOGGER.entry();
+ LOGGER.debug("sending {} to web socket {}", requestMessage.getAction(),
+ client.getRemoteSocketAddress().toString());
+
+ final EngineServiceInfoResponse responseMessage =
+ new EngineServiceInfoResponse(requestMessage.getTarget(), true, requestMessage);
+ responseMessage.setMessageData("engine service information");
+ responseMessage.setEngineServiceKey(engineServiceKey);
+ responseMessage.setEngineKeyArray(engineKeyCollection);
+ responseMessage.setApexModelKey(apexModelKey);
+
+ final MessageHolder<Message> messageHolder = new MessageHolder<>(MessagingUtils.getHost());
+ messageHolder.addMessage(responseMessage);
+ client.send(MessagingUtils.serializeObject(messageHolder));
+
+ LOGGER.exit();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessagingService.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessagingService.java
new file mode 100644
index 000000000..86589ac81
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/EngDepMessagingService.java
@@ -0,0 +1,107 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.engdep;
+
+import java.net.InetSocketAddress;
+
+import org.onap.policy.apex.service.engine.runtime.EngineService;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import org.onap.policy.apex.core.infrastructure.messaging.MessagingService;
+import org.onap.policy.apex.core.infrastructure.messaging.MessagingServiceFactory;
+import org.onap.policy.apex.core.infrastructure.messaging.util.MessagingUtils;
+import org.onap.policy.apex.core.protocols.Message;
+
+/**
+ * The Class EngDepMessagingService is used to encapsulate the server side of EngDep communication.
+ * This class allows users to create and start an EngDep server.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EngDepMessagingService {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EngDepMessagingService.class);
+
+ // Messaging service is used to transmit and receive messages over a communication protocol
+ private static MessagingServiceFactory<Message> messageServiceFactory = new MessagingServiceFactory<>();
+ private final MessagingService<Message> messageService;
+
+ // The listener that is listening for messages coming in on the EngDep protocol from clients
+ private final EngDepMessageListener messageListener;
+
+ /**
+ * Instantiates a new EngDep messaging service. It creates the message service instance, a
+ * listener for incoming messages, and starts the message listener thread for handling incoming
+ * messages.
+ *
+ * @param service the Apex engine service that this EngDep service is running for
+ * @param port the port The port to use for EngDep communication
+ */
+ public EngDepMessagingService(final EngineService service, final int port) {
+ LOGGER.entry(service);
+
+ // Create the service and listener and add the listener.
+ messageService = messageServiceFactory.createServer(new InetSocketAddress(MessagingUtils.checkPort(port)));
+ messageListener = new EngDepMessageListener(service);
+ messageService.addMessageListener(messageListener);
+
+ // Start incoming message processing on the listener
+ messageListener.startProcessorThread();
+ LOGGER.exit();
+ }
+
+ /**
+ * Start the server, open the communication mechanism for connections.
+ */
+ public void start() {
+ LOGGER.info("engine<-->deployment messaging starting . . .");
+ messageService.startConnection();
+ LOGGER.info("engine<-->deployment messaging started");
+ }
+
+ /**
+ * Start the server, close the communication mechanism.
+ */
+ public void stop() {
+ LOGGER.info("engine<-->deployment messaging stopping . . .");
+ messageService.stopConnection();
+ messageListener.stopProcessorThreads();
+ LOGGER.info("engine<-->deployment messaging stopped");
+ }
+
+ /**
+ * Is the server started?.
+ *
+ * @return true, if checks if is started
+ */
+ public boolean isStarted() {
+ return messageService.isStarted();
+ }
+
+ /**
+ * Is the server stopped?.
+ *
+ * @return true, if checks if is stopped
+ */
+ public boolean isStopped() {
+ return !messageService.isStarted();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/package-info.java
new file mode 100644
index 000000000..41f644465
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/engdep/package-info.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Gives access to the APEX EngDep protocol for APEX engine management at runtime over a Java API.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.engdep;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEvent.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEvent.java
new file mode 100644
index 000000000..552f949a2
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEvent.java
@@ -0,0 +1,342 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The Class ApexEvent is an event class that external systems use to send events to and receive events from Apex engines. The event itself is a hash map of
+ * string keys and object values, used to pass data.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexEvent extends HashMap<String, Object> implements Serializable {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexEvent.class);
+
+ private static final long serialVersionUID = -4451918242101961685L;
+
+ // Holds the next identifier for event execution.
+ private static AtomicLong nextExecutionID = new AtomicLong(0L);
+
+ /** The name of the Apex event, a mandatory field. All Apex events must have a name so that the event can be looked up in the Apex policy model. */
+ public static final String NAME_HEADER_FIELD = "name";
+
+ /**
+ * The version of the Apex event, an optional field. If a version is specified on an Apex event, the definition of that version of the event is taken from
+ * the Apex policy model. If no version is specified, the latest version of the event is used.
+ */
+ public static final String VERSION_HEADER_FIELD = "version";
+
+ /**
+ * The name space of the Apex event, an optional field. If a name space is specified on an Apex event it must match the name space on the event definition
+ * taken from the Apex policy model. If no name space is specified, the name space from the event definition in the Apex policy model is used.
+ */
+ public static final String NAMESPACE_HEADER_FIELD = "nameSpace";
+
+ /**
+ * The source of the Apex event, an optional field. It specifies where the Apex event has come from and its use is reserved for now. If no source is
+ * specified, the source from the event definition in the Apex policy model is used.
+ */
+ public static final String SOURCE_HEADER_FIELD = "source";
+
+ /**
+ * The target of the Apex event, an optional field. It specifies where the Apex event is going to and its use is reserved for now. If no target is
+ * specified, the target from the event definition in the Apex policy model is used.
+ */
+ public static final String TARGET_HEADER_FIELD = "target";
+
+ /**
+ * The exception message field of an Apex event is an exception message indicating that an event failed.
+ */
+ public static final String EXCEPTION_MESSAGE_HEADER_FIELD = "exceptionMessage";
+
+ /** The name of an Apex event must match this regular expression. */
+ public static final String NAME_REGEXP = "[A-Za-z0-9\\-_.]+";
+
+ /** The version of an Apex event must match this regular expression. */
+ public static final String VERSION_REGEXP = "[A-Za-z0-9.]+";
+
+ /** The name space of an Apex event must match this regular expression. */
+ public static final String NAMESPACE_REGEXP = "([a-zA_Z_][\\.\\w]*)";
+
+ /** The source of an Apex event must match this regular expression. */
+ public static final String SOURCE_REGEXP = "^$|[A-Za-z0-9\\.\\-_:]+";
+
+ /** The target of an Apex event must match this regular expression. */
+ public static final String TARGET_REGEXP = "^$|[A-Za-z0-9\\.\\-_:]+";
+
+ // The fields of the event
+ // @formatter:off
+ private final String name;
+ private final String version;
+ private final String nameSpace;
+ private final String source;
+ private final String target;
+ // @formatter:on
+
+ // An identifier for the current event execution. The default value here will always be unique in a single JVM
+ private long executionID = ApexEvent.getNextExecutionID();
+
+ // A string holding a message that indicates why processing of this event threw an exception
+ private String exceptionMessage;
+
+ /**
+ * Private utility to get the next candidate value for a Execution ID. This value will always be unique in a single JVM
+ *
+ * @return the next candidate value for a Execution ID
+ */
+ private static synchronized long getNextExecutionID() {
+ return nextExecutionID.getAndIncrement();
+ }
+
+ /**
+ * Instantiates a new apex event.
+ *
+ * @param name the name of the event
+ * @param version the version of the event
+ * @param nameSpace the name space (java package) of the event
+ * @param source the source of the event
+ * @param target the target of the event
+ * @throws ApexEventException thrown on validation errors on event names and versions
+ */
+ public ApexEvent(final String name, final String version, final String nameSpace, final String source, final String target) throws ApexEventException {
+ // @formatter:off
+ this.name = validateField("name", name, NAME_REGEXP);
+ this.version = validateField("version", version, VERSION_REGEXP);
+ this.nameSpace = validateField("nameSpace", nameSpace, NAMESPACE_REGEXP);
+ this.source = validateField("source", source, SOURCE_REGEXP);
+ this.target = validateField("target", target, TARGET_REGEXP);
+ // @formatter:on
+ }
+
+ /**
+ * Check that a field of the event is valid.
+ *
+ * @param fieldName the name of the field to check
+ * @param fieldValue the value of the field to check
+ * @param fieldRegexp the regular expression to check the field against
+ * @return the validated field value
+ * @throws ApexEventException thrown if the field is invalid
+ */
+ private String validateField(final String fieldName, final String fieldValue, final String fieldRegexp) throws ApexEventException {
+ if (fieldValue.matches(fieldRegexp)) {
+ return fieldValue;
+ }
+ else {
+ LOGGER.warn("event \"" + name + ": field \"" + fieldName + "=" + fieldValue + "\" is illegal. It doesn't match regex '" + fieldRegexp + "'");
+ throw new ApexEventException("event \"" + name + ": field \"" + fieldName + "=" + fieldValue + "\" is illegal");
+ }
+ }
+
+ /**
+ * Check that the key of an event is valid.
+ *
+ * @param key the key
+ * @return the string
+ * @throws ApexEventException the apex event exception
+ */
+ private String validKey(final String key) throws ApexEventException {
+ if (key.matches(NAME_REGEXP)) {
+ return key;
+ }
+ else {
+ LOGGER.warn("event \"" + name + ": key \"" + key + "\" is illegal");
+ throw new ApexEventException("event \"" + name + ": key \"" + key + "\" is illegal");
+ }
+ }
+
+ /**
+ * Gets the name.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the version.
+ *
+ * @return the version
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Gets the name space.
+ *
+ * @return the name space
+ */
+ public String getNameSpace() {
+ return nameSpace;
+ }
+
+ /**
+ * Gets the source.
+ *
+ * @return the source
+ */
+ public String getSource() {
+ return source;
+ }
+
+ /**
+ * Gets the target.
+ *
+ * @return the target
+ */
+ public String getTarget() {
+ return target;
+ }
+
+ /**
+ * Gets the pass-thru executionID for this event.
+ *
+ * @return the executionID
+ */
+ public long getExecutionID() {
+ return executionID;
+ }
+
+ /**
+ * Sets the pass-thru executionID for this event. The default value for executionID will be be unique in the current JVM. For some applications/deployments
+ * this executionID may need to globally unique
+ *
+ * @param executionID the executionID
+ */
+ public void setExecutionID(final long executionID) {
+ this.executionID = executionID;
+ }
+
+ /**
+ * Gets the exception message explaining why processing of this event to fail.
+ *
+ * @return the exception message
+ */
+ public String getExceptionMessage() {
+ return exceptionMessage;
+ }
+
+ /**
+ * Sets the exception message explaining why processing of this event to fail.
+ *
+ * @param exceptionMessage the exception message
+ */
+ public void setExceptionMessage(final String exceptionMessage) {
+ this.exceptionMessage = exceptionMessage;
+ }
+
+ /*
+ * Map overrides from here
+ */
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#put(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public Object put(final String key, final Object value) {
+ // Check if the key is valid
+ try {
+ return super.put(validKey(key), value);
+ }
+ catch (final ApexEventException e) {
+ return null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#putAll(java.util.Map)
+ */
+ @Override
+ public void putAll(final Map<? extends String, ? extends Object> incomingMap) {
+ // Check the keys are valid
+ try {
+ for (final String key : incomingMap.keySet()) {
+ validKey(key);
+ }
+ }
+ catch (final ApexEventException e) {
+ // One of the keys is invalid
+ return;
+ }
+
+ // Go ahead and put everything
+ super.putAll(incomingMap);
+ }
+
+ /*
+ * Object overrides from here
+ */
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("name=");
+ builder.append(name);
+ builder.append(",version=");
+ builder.append(version);
+ builder.append(",nameSpace=");
+ builder.append(nameSpace);
+ builder.append(",source=");
+ builder.append(source);
+ builder.append(",target=");
+ builder.append(target);
+ builder.append(",executionID=");
+ builder.append(executionID);
+ builder.append(",exceptionMessage=");
+ builder.append(exceptionMessage);
+ builder.append(",");
+ builder.append("[");
+
+ boolean firstData = true;
+ for (final Map.Entry<String, Object> dataEntry : this.entrySet()) {
+ if (firstData) {
+ firstData = false;
+ }
+ else {
+ builder.append(',');
+ }
+
+ builder.append(dataEntry.getKey());
+ builder.append('=');
+ builder.append(dataEntry.getValue());
+ }
+
+ builder.append("]");
+ return builder.toString();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConsumer.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConsumer.java
new file mode 100644
index 000000000..53f11dd61
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConsumer.java
@@ -0,0 +1,80 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+
+/**
+ * This interface is used by technology specific consumers and listeners that are are listening for
+ * or collecting events for input into Apex. Users specify the consumer technology to use in the
+ * Apex configuration and Apex uses a factory to start the appropriate consumer plugin that
+ * implements this interface for its input. The technology specific implementation details are
+ * hidden behind this interface.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public interface ApexEventConsumer {
+ /**
+ * Initialize the consumer.
+ *
+ * @param name a name for this consumer
+ * @param consumerParameters the parameters to initialize this consumer
+ * @param apexEventReceiver the apex event receiver that should be used to pass events received
+ * by the consumer into Apex
+ * @throws ApexEventException container exception on errors initializing event handling
+ */
+ void init(String name, EventHandlerParameters consumerParameters, ApexEventReceiver apexEventReceiver)
+ throws ApexEventException;
+
+ /**
+ * Start the consumer, start input of events into Apex.
+ */
+ void start();
+
+ /**
+ * Get the peered reference object for this consumer.
+ *
+ * @param peeredMode the peered mode for which to return the reference
+ * @return the peered reference object for this consumer
+ */
+ PeeredReference getPeeredReference(EventHandlerPeeredMode peeredMode);
+
+ /**
+ * Set the peered reference object for this consumer.
+ *
+ * @param peeredMode the peered mode for which to return the reference
+ * @param peeredReference the peered reference object for this consumer
+ */
+ void setPeeredReference(EventHandlerPeeredMode peeredMode, PeeredReference peeredReference);
+
+ /**
+ * Get the name of this event consumer.
+ *
+ * @return the event consumer name
+ */
+ String getName();
+
+ /**
+ * Stop the event consumer.
+ */
+ void stop();
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConverter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConverter.java
new file mode 100644
index 000000000..11f005ddf
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventConverter.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import java.util.List;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+
+/**
+ * The Interface ApexEventConverter is used for applications that want to convert arbitrary event
+ * types to and from Apex events. Application implement this interface to convert their events to
+ * and from Apex events.The Apex service can then use this interface to transparently transfer
+ * events into and out of an Apex system.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public interface ApexEventConverter {
+
+ /**
+ * Convert an event of arbitrary type into an Apex event.
+ *
+ * @param name the name of the incoming event
+ * @param eventOfOtherType the event of some other type to convert
+ * @return the apex event
+ * @throws ApexException thrown on conversion errors
+ */
+ List<ApexEvent> toApexEvent(String name, Object eventOfOtherType) throws ApexException;
+
+ /**
+ * Convert an Apex event into an event of arbitrary type {@code OTHER_EVENT_TYPE}.
+ *
+ * @param apexEvent the apex event to convert
+ * @return the event converted into the other type
+ * @throws ApexException thrown on conversion errors
+ */
+ Object fromApexEvent(ApexEvent apexEvent) throws ApexException;
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventException.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventException.java
new file mode 100644
index 000000000..24f57d741
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventException.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+
+/**
+ * This class will be called if an error occurs in handling Apex events.
+ *
+ * @author eeilfn
+ */
+public class ApexEventException extends ApexException {
+ private static final long serialVersionUID = -4245694568321686450L;
+
+ /**
+ * Instantiates a new apex event exception.
+ *
+ * @param message the message
+ */
+ public ApexEventException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex event exception.
+ *
+ * @param message the message
+ * @param e the e
+ */
+ public ApexEventException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventList.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventList.java
new file mode 100644
index 000000000..9fe03ef47
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventList.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import java.util.ArrayList;
+
+/**
+ * The Class ApexEventList holds a list of APEX events.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexEventList extends ArrayList<ApexEvent> {
+ private static final long serialVersionUID = -8496211897512202896L;
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProducer.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProducer.java
new file mode 100644
index 000000000..414fbc9e3
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProducer.java
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+
+/**
+ * This interface is used by technology specific producers and publishers that are handling events
+ * output by Apex. Users specify the producer technology to use in the Apex configuration and Apex
+ * uses a factory to start the appropriate producer plugin that implements this interface for its
+ * output. The technology specific implementation details are hidden behind this interface.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public interface ApexEventProducer {
+
+ /**
+ * Initialize the producer.
+ *
+ * @param name a name for this producer
+ * @param producerParameters the parameters to initialise this producer
+ * @throws ApexEventException exception on errors initializing an event producer
+ */
+ void init(String name, EventHandlerParameters producerParameters) throws ApexEventException;
+
+ /**
+ * Get the peered reference object for this producer.
+ *
+ * @param peeredMode the peered mode for which to return the reference
+ * @return the peered reference object for this producer
+ */
+ PeeredReference getPeeredReference(EventHandlerPeeredMode peeredMode);
+
+ /**
+ * Set the peered reference object for this producer.
+ *
+ * @param peeredMode the peered mode for which to return the reference
+ * @param peeredReference the peered reference object for this producer
+ */
+ void setPeeredReference(EventHandlerPeeredMode peeredMode, PeeredReference peeredReference);
+
+ /**
+ * Send an event to the producer.
+ *
+ * @param executionId the unique ID that produced this event
+ * @param eventName The name of the event
+ * @param event The converted event as an object
+ */
+ void sendEvent(long executionId, String eventName, Object event);
+
+ /**
+ * Get the name of this event producer.
+ *
+ * @return the event producer name
+ */
+ String getName();
+
+ /**
+ * Stop the event producer.
+ */
+ void stop();
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProtocolConverter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProtocolConverter.java
new file mode 100644
index 000000000..ec19e65c3
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventProtocolConverter.java
@@ -0,0 +1,39 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+
+/**
+ * The Interface ApexEventProtocolConverter extends ApexEventConverter to allow
+ * EventProtocolParameters conversion parameters to be passed to the converter.
+ *
+ * @author John Keeney (john.keeney@ericsson.com)
+ */
+public interface ApexEventProtocolConverter extends ApexEventConverter {
+
+ /**
+ * Initialise the converter instance with the parameters for the EventProtocol.
+ *
+ * @param parameters the parameters for the EventProtocol
+ */
+ void init(EventProtocolParameters parameters);
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventReceiver.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventReceiver.java
new file mode 100644
index 000000000..8d7e7bae5
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventReceiver.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+/**
+ * This interface is used by an Apex event consumer {@link ApexEventConsumer} consumer to pass a
+ * received event to Apex.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public interface ApexEventReceiver {
+ /**
+ * Receive an event from a consumer for processing.
+ *
+ * @param executionId the unique ID for execution of this event
+ * @param event the event to receive
+ * @throws ApexEventException on exceptions receiving an event into Apex
+ */
+ void receiveEvent(long executionId, Object event) throws ApexEventException;
+
+ /**
+ * Receive an event from a consumer for processing.
+ *
+ * @param event the event to receive
+ * @throws ApexEventException on exceptions receiving an event into Apex
+ */
+ void receiveEvent(Object event) throws ApexEventException;
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventRuntimeException.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventRuntimeException.java
new file mode 100644
index 000000000..1a624face
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexEventRuntimeException.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexRuntimeException;
+
+/**
+ * This exception will be called if a runtime error occurs in Apex event handling.
+ *
+ * @author Liam Fallon
+ */
+public class ApexEventRuntimeException extends ApexRuntimeException {
+ private static final long serialVersionUID = -8507246953751956974L;
+
+ /**
+ * Instantiates a new apex runtime event exception with a message.
+ *
+ * @param message the message
+ */
+ public ApexEventRuntimeException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex runtime event exception with a message and a caused by exception.
+ *
+ * @param message the message
+ * @param e the exception that caused this exception to be thrown
+ */
+ public ApexEventRuntimeException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexPeriodicEventGenerator.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexPeriodicEventGenerator.java
new file mode 100644
index 000000000..62663b9f1
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/ApexPeriodicEventGenerator.java
@@ -0,0 +1,176 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.onap.policy.apex.service.engine.runtime.EngineServiceEventInterface;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class is used to generate periodic events into an Apex engine service. It is used to trigger
+ * policies that perform housekeeping operations.
+ *
+ * @author eeilfn
+ */
+public class ApexPeriodicEventGenerator extends TimerTask {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexPeriodicEventGenerator.class);
+
+ /** The name of the periodic event. */
+ public static final String PERIODIC_EVENT_NAME = "PERIODIC_EVENT";
+
+ /** The version of the periodic event. */
+ public static final String PERIODIC_EVENT_VERSION = "0.0.1";
+
+ /** The name space of the periodic event. */
+ public static final String PERIODIC_EVENT_NAMESPACE = "com.ericsson.apex.service.engine.event";
+
+ /** The source of the periodic event. */
+ public static final String PERIODIC_EVENT_SOURCE = "internal";
+
+ /** The target of the periodic event. */
+ public static final String PERIODIC_EVENT_TARGET = "internal";
+
+ /**
+ * The field name in the periodic event for the delay between occurrences of the periodic event.
+ */
+ public static final String PERIODIC_DELAY = "PERIODIC_DELAY";
+
+ /**
+ * The field name in the periodic event for the time at which the first periodic event will
+ * occur.
+ */
+ public static final String PERIODIC_FIRST_TIME = "PERIODIC_FIRST_TIME";
+
+ /**
+ * The field name in the periodic event for the time at which the last periodic event will
+ * occur.
+ */
+ public static final String PERIODIC_LAST_TIME = "PERIODIC_LAST_TIME";
+
+ /** The field name in the periodic event for the time at which the event was sent. */
+ public static final String PERIODIC_CURRENT_TIME = "PERIODIC_CURRENT_TIME";
+
+ /**
+ * The field name in the periodic event for the number of occurrences of this event that have
+ * been sent to date, this is a sequence number for the periodic event.
+ */
+ public static final String PERIODIC_EVENT_COUNT = "PERIODIC_EVENT_COUNT";
+
+ // The Java timer used to send periodic events
+ private Timer timer = null;
+
+ // The engine service interface we'll send periodic events to
+ private final EngineServiceEventInterface engineServiceEventInterface;
+
+ // Timing information
+ private long period = 0;
+ private long firstEventTime = 0;
+ private long lastEventTime = 0;
+ private long eventCount = 0;
+
+ /**
+ * Constructor, save a reference to the event stream handler.
+ *
+ * @param engineServiceEventInterface the engine service event interface on which to send
+ * periodic events
+ * @param period The period in milliseconds between events
+ */
+ public ApexPeriodicEventGenerator(final EngineServiceEventInterface engineServiceEventInterface,
+ final long period) {
+ // Save the engine service reference and delay
+ this.engineServiceEventInterface = engineServiceEventInterface;
+ this.period = period;
+
+ timer = new Timer(ApexPeriodicEventGenerator.class.getSimpleName(), true);
+ timer.schedule(this, period, period);
+ }
+
+ /**
+ * Output the metrics for stream loading.
+ */
+ @Override
+ public void run() {
+ final Map<String, Object> periodicEventMap = new HashMap<>();
+
+ // Record the current event time
+ final long currentEventTime = System.currentTimeMillis();
+
+ // Check if this is the first periodic event
+ if (firstEventTime == 0) {
+ firstEventTime = currentEventTime;
+ lastEventTime = currentEventTime;
+ }
+
+ // Increment the event counter
+ eventCount++;
+
+ // Set the fields in the periodic event
+ periodicEventMap.put(PERIODIC_DELAY, period);
+ periodicEventMap.put(PERIODIC_FIRST_TIME, firstEventTime);
+ periodicEventMap.put(PERIODIC_LAST_TIME, lastEventTime);
+ periodicEventMap.put(PERIODIC_CURRENT_TIME, currentEventTime);
+ periodicEventMap.put(PERIODIC_EVENT_COUNT, eventCount);
+
+ // Send the periodic event
+ try {
+ final ApexEvent periodicEvent = new ApexEvent(PERIODIC_EVENT_NAME, PERIODIC_EVENT_VERSION,
+ PERIODIC_EVENT_NAMESPACE, PERIODIC_EVENT_SOURCE, PERIODIC_EVENT_TARGET);
+ periodicEvent.putAll(periodicEventMap);
+ engineServiceEventInterface.sendEvent(periodicEvent);
+ } catch (final ApexEventException e) {
+ LOGGER.warn("could not send Apex periodic event " + PERIODIC_EVENT_NAME + ":" + PERIODIC_EVENT_VERSION, e);
+ return;
+ }
+
+ // Save the current time as the last time
+ lastEventTime = currentEventTime;
+ }
+
+ /**
+ * Cancel the timer.
+ *
+ * @return true, if cancel
+ */
+ @Override
+ public boolean cancel() {
+ // Cancel the timer
+ if (timer != null) {
+ timer.cancel();
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "ApexPeriodicEventGenerator [period=" + period + ", firstEventTime=" + firstEventTime
+ + ", lastEventTime=" + lastEventTime + ", eventCount=" + eventCount + "]";
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/PeeredReference.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/PeeredReference.java
new file mode 100644
index 000000000..9560a834c
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/PeeredReference.java
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+
+/**
+ * This class holds a reference to an event consumer and producer that have been peered.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class PeeredReference {
+ // The consumer putting events into APEX
+ private final ApexEventConsumer peeredConsumer;
+
+ // The synchronous producer taking events out of APEX
+ private final ApexEventProducer peeredProducer;
+
+ /**
+ * Create a peered consumer/producer reference
+ *
+ * @param peeredMode the peered mode for which to return the reference
+ * @param consumer the consumer that is receiving event
+ * @param producer the producer that is sending events
+ */
+ public PeeredReference(final EventHandlerPeeredMode peeredMode, final ApexEventConsumer consumer, final ApexEventProducer producer) {
+ this.peeredConsumer = consumer;
+ this.peeredProducer = producer;
+
+ // Set the peered reference on the producer and consumer
+ peeredConsumer.setPeeredReference(peeredMode, this);
+ peeredProducer.setPeeredReference(peeredMode, this);
+ }
+
+ /**
+ * Gets the synchronous consumer putting events into the cache.
+ *
+ * @return the source synchronous consumer
+ */
+ public ApexEventConsumer getPeeredConsumer() {
+ return peeredConsumer;
+ }
+
+ /**
+ * Gets the synchronous producer taking events from the cache.
+ *
+ * @return the synchronous producer that is taking events from the cache
+ */
+ public ApexEventProducer getPeeredProducer() {
+ return peeredProducer;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/SynchronousEventCache.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/SynchronousEventCache.java
new file mode 100644
index 000000000..25f92d843
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/SynchronousEventCache.java
@@ -0,0 +1,294 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class holds a cache of the synchronous events sent into Apex and that have not yet been replied to. It runs a thread to time out events that have not
+ * been replied to in the specified timeout.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class SynchronousEventCache extends PeeredReference implements Runnable {
+ // Get a reference to the logger
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(SynchronousEventCache.class);
+
+ // The default amount of time to wait for a synchronous event to be replied to is 1 second
+ private static final long DEFAULT_SYNCHRONOUS_EVENT_TIMEOUT = 1000;
+
+ // The timeout to wait between event polls in milliseconds and the time to wait for the thread to stop
+ private static final long OUTSTANDING_EVENT_POLL_TIMEOUT = 50;
+ private static final long CACHE_STOP_WAIT_INTERVAL = 10;
+
+ // The time in milliseconds to wait for the reply to a sent synchronous event
+ private long synchronousEventTimeout = DEFAULT_SYNCHRONOUS_EVENT_TIMEOUT;
+
+ // Map holding outstanding synchronous events
+ private final Map<Long, SimpleEntry<Long, Object>> toApexEventMap = new HashMap<Long, SimpleEntry<Long, Object>>();
+
+ // Map holding reply events
+ private final Map<Long, SimpleEntry<Long, Object>> fromApexEventMap = new HashMap<Long, SimpleEntry<Long, Object>>();
+
+ // The message listener thread and stopping flag
+ private final Thread synchronousEventCacheThread;
+ private boolean stopOrderedFlag = false;
+
+ /**
+ * Create a synchronous event cache that caches outstanding synchronous Apex events.
+ *
+ * @param peeredMode the peered mode for which to return the reference
+ * @param consumer the consumer that is populating the cache
+ * @param producer the producer that is emptying the cache
+ * @param synchronousEventTimeout the time in milliseconds to wait for the reply to a sent synchronous event
+ */
+ public SynchronousEventCache(final EventHandlerPeeredMode peeredMode, final ApexEventConsumer consumer, final ApexEventProducer producer, final long synchronousEventTimeout) {
+ super(peeredMode, consumer, producer);
+
+ if (synchronousEventTimeout != 0) {
+ this.synchronousEventTimeout = synchronousEventTimeout;
+ }
+ else {
+ this.synchronousEventTimeout = DEFAULT_SYNCHRONOUS_EVENT_TIMEOUT;
+ }
+
+ // Start scanning the outstanding events
+ synchronousEventCacheThread = new Thread(this);
+ synchronousEventCacheThread.setDaemon(true);
+ synchronousEventCacheThread.start();
+ }
+
+ /**
+ * Gets the timeout value for synchronous events.
+ *
+ * @return the synchronous event timeout
+ */
+ public long getSynchronousEventTimeout() {
+ return synchronousEventTimeout;
+ }
+
+ /**
+ * Cache a synchronized event sent into Apex in the event cache.
+ *
+ * @param executionId the execution ID that was assigned to the event
+ * @param event the apex event
+ */
+ public void cacheSynchronizedEventToApex(final long executionId, final Object event) {
+ // Add the event to the map
+ synchronized (toApexEventMap) {
+ cacheSynchronizedEvent(toApexEventMap, executionId, event);
+ }
+ }
+
+ /**
+ * Remove the record of an event sent to Apex if it exists in the cache.
+ *
+ * @param executionId the execution ID of the event
+ * @return The removed event
+ */
+ public Object removeCachedEventToApexIfExists(final long executionId) {
+ synchronized (toApexEventMap) {
+ return removeCachedEventIfExists(toApexEventMap, executionId);
+ }
+ }
+
+ /**
+ * Check if an event exists in the to apex cache.
+ *
+ * @param executionId the execution ID of the event
+ * @return true if the event exists, false otherwise
+ */
+ public boolean existsEventToApex(final long executionId) {
+ synchronized (toApexEventMap) {
+ return toApexEventMap.containsKey(executionId);
+ }
+ }
+
+ /**
+ * Cache synchronized event received from Apex in the event cache.
+ *
+ * @param executionId the execution ID of the event
+ * @param event the apex event
+ */
+ public void cacheSynchronizedEventFromApex(final long executionId, final Object event) {
+ // Add the event to the map
+ synchronized (fromApexEventMap) {
+ cacheSynchronizedEvent(fromApexEventMap, executionId, event);
+ }
+ }
+
+ /**
+ * Remove the record of an event received from Apex if it exists in the cache.
+ *
+ * @param executionId the execution ID of the event
+ * @return The removed event
+ */
+ public Object removeCachedEventFromApexIfExists(final long executionId) {
+ synchronized (fromApexEventMap) {
+ return removeCachedEventIfExists(fromApexEventMap, executionId);
+ }
+ }
+
+ /**
+ * Check if an event exists in the from apex cache.
+ *
+ * @param executionId the execution ID of the event
+ * @return true if the event exists, false otherwise
+ */
+ public boolean existsEventFromApex(final long executionId) {
+ synchronized (fromApexEventMap) {
+ return fromApexEventMap.containsKey(executionId);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ LOGGER.entry();
+
+ // Periodic scan of outstanding events
+ while (synchronousEventCacheThread.isAlive() && !stopOrderedFlag) {
+ ThreadUtilities.sleep(OUTSTANDING_EVENT_POLL_TIMEOUT);
+
+ // Check for timeouts on events
+ synchronized (toApexEventMap) {
+ timeoutEventsOnCache(toApexEventMap);
+ }
+ synchronized (fromApexEventMap) {
+ timeoutEventsOnCache(fromApexEventMap);
+ }
+ }
+
+ LOGGER.exit();
+ }
+
+ /**
+ * Stops the scanning thread and clears the cache.
+ */
+ public synchronized void stop() {
+ LOGGER.entry();
+ stopOrderedFlag = true;
+
+ while (synchronousEventCacheThread.isAlive()) {
+ ThreadUtilities.sleep(CACHE_STOP_WAIT_INTERVAL);
+ }
+
+ // Check if there are any unprocessed events
+ if (!toApexEventMap.isEmpty()) {
+ LOGGER.warn(toApexEventMap.size() + " synchronous events dropped due to system shutdown");
+ }
+
+ toApexEventMap.clear();
+ LOGGER.exit();
+ }
+
+ /**
+ * Cache a synchronized event sent in an event cache.
+ * @param eventCacheMap the map to cache the event on
+ * @param executionId the execution ID of the event
+ * @param event the event to cache
+ */
+ private void cacheSynchronizedEvent(final Map<Long, SimpleEntry<Long, Object>> eventCacheMap, final long executionId, final Object event) {
+ LOGGER.entry("Adding event with execution ID: " + executionId);
+
+ // Check if the event is already in the cache
+ if (eventCacheMap.containsKey(executionId)) {
+ // If there was no sent event then the event timed out or some unexpected event was received
+ final String errorMessage = "an event with ID " + executionId
+ + " already exists in the synchronous event cache, execution IDs must be unique in the system";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+
+ // Add the event to the map
+ eventCacheMap.put(executionId, new SimpleEntry<Long, Object>(System.currentTimeMillis(), event));
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("event has been cached:" + event);
+ }
+
+ LOGGER.exit("Added: " + executionId);
+ }
+
+ /**
+ * Remove the record of an event if it exists in the cache.
+ *
+ * @param eventCacheMap the map to remove the event from
+ * @param executionId the execution ID of the event
+ * @return The removed event
+ */
+ private Object removeCachedEventIfExists(final Map<Long, SimpleEntry<Long, Object>> eventCacheMap, final long executionId) {
+ LOGGER.entry("Removing: " + executionId);
+
+ final SimpleEntry<Long, Object> removedEventEntry = eventCacheMap.remove(executionId);
+
+ if (removedEventEntry != null) {
+ LOGGER.exit("Removed: " + executionId);
+ return removedEventEntry.getValue();
+ }
+ else {
+ // The event may not be one of the events in our cache, so we just ignore removal failures
+ return null;
+ }
+ }
+
+ /**
+ * Time out events on an event cache map. Events that have a timeout longer than the configured timeout are timed out.
+ * @param eventCacheMap the event cache to operate on
+ */
+ private void timeoutEventsOnCache(final Map<Long, SimpleEntry<Long, Object>> eventCacheMap) {
+ // Use a set to keep track of the events that have timed out
+ final Set<Long> timedOutEventSet = new HashSet<>();
+
+ for (final Entry<Long, SimpleEntry<Long, Object>> cachedEventEntry : eventCacheMap.entrySet()) {
+ // The amount of time we are waiting for the event reply
+ final long eventWaitTime = System.currentTimeMillis() - cachedEventEntry.getValue().getKey();
+
+ // Have we a timeout?
+ if (eventWaitTime > synchronousEventTimeout) {
+ timedOutEventSet.add(cachedEventEntry.getKey());
+ }
+ }
+
+ // Remove timed out events from the map
+ for (final long timedoutEventExecutionID : timedOutEventSet) {
+ // Remove the map entry and issue a warning
+ final SimpleEntry<Long, Object> timedOutEventEntry = eventCacheMap.remove(timedoutEventExecutionID);
+
+ LOGGER.warn("synchronous event timed out, reply not received in " + synchronousEventTimeout + " milliseconds on event "
+ + timedOutEventEntry.getValue());
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventConsumerFactory.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventConsumerFactory.java
new file mode 100644
index 000000000..8f54c049b
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventConsumerFactory.java
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl;
+
+import org.onap.policy.apex.service.engine.event.ApexEventConsumer;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This factory class creates event consumers of various technology types for Apex engines.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EventConsumerFactory {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EventConsumerFactory.class);
+
+ /**
+ * Empty constructor with no generic overloading.
+ */
+ public EventConsumerFactory() {}
+
+ /**
+ * Create an event consumer of the required type for the specified consumer technology.
+ *
+ * @param name the name of the consumer
+ * @param consumerParameters The parameters for the Apex engine, we use the technology type of
+ * the required consumer
+ * @return the event consumer
+ * @throws ApexEventException on errors creating the Apex event consumer
+ */
+ public ApexEventConsumer createConsumer(final String name, final EventHandlerParameters consumerParameters)
+ throws ApexEventException {
+ // Get the carrier technology parameters
+ final CarrierTechnologyParameters technologyParameters = consumerParameters.getCarrierTechnologyParameters();
+
+ // Get the class for the event consumer using reflection
+ final String consumerPluginClass = technologyParameters.getEventConsumerPluginClass();
+ Object consumerPluginObject = null;
+ try {
+ consumerPluginObject = Class.forName(consumerPluginClass).newInstance();
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ final String errorMessage = "could not create an Apex event consumer for \"" + name
+ + "\" for the carrier technology \"" + technologyParameters.getLabel()
+ + "\", specified event consumer plugin class \"" + consumerPluginClass + "\" not found";
+ LOGGER.error(errorMessage, e);
+ throw new ApexEventException(errorMessage, e);
+ }
+
+ // Check the class is an event consumer
+ if (!(consumerPluginObject instanceof ApexEventConsumer)) {
+ final String errorMessage = "could not create an Apex event consumer \"" + name
+ + "\" for the carrier technology \"" + technologyParameters.getLabel()
+ + "\", specified event consumer plugin class \"" + consumerPluginClass
+ + "\" is not an instance of \"" + ApexEventConsumer.class.getCanonicalName() + "\"";
+ LOGGER.error(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+
+ return (ApexEventConsumer) consumerPluginObject;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProducerFactory.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProducerFactory.java
new file mode 100644
index 000000000..9bbbad362
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProducerFactory.java
@@ -0,0 +1,82 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl;
+
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventProducer;
+import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This factory class creates event producers for the defined technology type for Apex engines.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EventProducerFactory {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EventProducerFactory.class);
+
+ /**
+ * Empty constructor with no generic overloading.
+ */
+ public EventProducerFactory() {}
+
+ /**
+ * Create an event producer of the required type for the specified producer technology.
+ *
+ * @param name the name of the producer
+ * @param producerParameters The Apex parameters containing the configuration for the producer
+ * @return the event producer
+ * @throws ApexEventException on errors creating the Apex event producer
+ */
+ public ApexEventProducer createProducer(final String name, final EventHandlerParameters producerParameters)
+ throws ApexEventException {
+ // Get the carrier technology parameters
+ final CarrierTechnologyParameters technologyParameters = producerParameters.getCarrierTechnologyParameters();
+
+ // Get the class for the event producer using reflection
+ final String producerPluginClass = technologyParameters.getEventProducerPluginClass();
+ Object producerPluginObject = null;
+ try {
+ producerPluginObject = Class.forName(producerPluginClass).newInstance();
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ final String errorMessage = "could not create an Apex event producer for Producer \"" + name
+ + "\" for the carrier technology \"" + technologyParameters.getLabel()
+ + "\", specified event producer plugin class \"" + producerPluginClass + "\" not found";
+ LOGGER.error(errorMessage, e);
+ throw new ApexEventException(errorMessage, e);
+ }
+
+ // Check the class is an event producer
+ if (!(producerPluginObject instanceof ApexEventProducer)) {
+ final String errorMessage = "could not create an Apex event producer for Producer \"" + name
+ + "\" for the carrier technology \"" + technologyParameters.getLabel()
+ + "\", specified event producer plugin class \"" + producerPluginClass
+ + "\" is not an instance of \"" + ApexEventProducer.class.getCanonicalName() + "\"";
+ LOGGER.error(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+
+ return (ApexEventProducer) producerPluginObject;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProtocolFactory.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProtocolFactory.java
new file mode 100644
index 000000000..85c5bf03f
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/EventProtocolFactory.java
@@ -0,0 +1,76 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl;
+
+import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
+import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This factory class uses the Apex event protocol parameters to create and return an instance of
+ * the correct Apex event protocol converter plugin for the specified event protocol.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EventProtocolFactory {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EventProtocolFactory.class);
+
+ /**
+ * Create an event converter that converts between an
+ * {@link org.onap.policy.apex.service.engine.event.ApexEvent} and the specified event protocol.
+ *
+ * @param name the name of the event protocol
+ * @param eventProtocolParameters the event protocol parameters defining what to convert from
+ * and to
+ * @return The event converter for converting events to and from Apex format
+ */
+ public ApexEventProtocolConverter createConverter(final String name,
+ final EventProtocolParameters eventProtocolParameters) {
+ // Get the class for the event protocol plugin using reflection
+ final String eventProtocolPluginClass = eventProtocolParameters.getEventProtocolPluginClass();
+ Object eventProtocolPluginObject = null;
+ try {
+ eventProtocolPluginObject = Class.forName(eventProtocolPluginClass).newInstance();
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ final String errorMessage = "could not create an Apex event protocol converter for \"" + name
+ + "\" for the protocol \"" + eventProtocolParameters.getLabel()
+ + "\", specified event protocol converter plugin class \"" + eventProtocolPluginClass
+ + "\" not found";
+ LOGGER.error(errorMessage, e);
+ throw new ApexEventRuntimeException(errorMessage, e);
+ }
+
+ // Check the class is an event consumer
+ if (!(eventProtocolPluginObject instanceof ApexEventProtocolConverter)) {
+ final String errorMessage = "could not create an Apex event protocol converter for \"" + name
+ + "\" for the protocol \"" + eventProtocolParameters.getLabel()
+ + "\", specified event protocol converter plugin class \"" + eventProtocolPluginClass
+ + "\" is not an instance of \"" + ApexEventProtocolConverter.class.getCanonicalName() + "\"";
+ LOGGER.error(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+ ((ApexEventProtocolConverter) eventProtocolPluginObject).init(eventProtocolParameters);
+ return (ApexEventProtocolConverter) eventProtocolPluginObject;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/Apex2ApexEventConverter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/Apex2ApexEventConverter.java
new file mode 100644
index 000000000..b73aeb567
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/Apex2ApexEventConverter.java
@@ -0,0 +1,140 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.apexprotocolplugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventList;
+import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
+import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The Class Apex2ApexEventConverter passes through {@link ApexEvent} instances. It is used for
+ * transferring Apex events directly as POJOs between APEX producers and consumers.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class Apex2ApexEventConverter implements ApexEventProtocolConverter {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(Apex2ApexEventConverter.class);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter#init(org.onap.policy.
+ * apex. service.parameters.eventprotocol.EventProtocolParameters)
+ */
+ @Override
+ public void init(final EventProtocolParameters parameters) {
+ // Check and get the APEX parameters
+ if (!(parameters instanceof ApexEventProtocolParameters)) {
+ final String errorMessage = "specified consumer properties are not applicable to the APEX event protocol";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventConverter#toApexEvent(java.lang.String,
+ * java.lang.Object)
+ */
+ @Override
+ public List<ApexEvent> toApexEvent(final String eventName, final Object eventObject) throws ApexEventException {
+ // Check the event eventObject
+ if (eventObject == null) {
+ LOGGER.warn("event processing failed, event is null");
+ throw new ApexEventException("event processing failed, event is null");
+ }
+
+ // The list of events we will return
+ final List<ApexEvent> eventList = new ArrayList<>();
+
+ try {
+ // Check if its a single APEX event
+ if (!(eventObject instanceof ApexEvent)) {
+ throw new ApexEventException("incoming event (" + eventObject + ") is not an ApexEvent");
+ }
+
+ final ApexEvent event = (ApexEvent) eventObject;
+
+ // Check whether we have any ApexEventList fields, if so this is an event of events and
+ // all fields should be of type ApexEventList
+ boolean foundEventListFields = false;
+ boolean foundOtherFields = false;
+ for (final Object fieldObject : event.values()) {
+ if (fieldObject instanceof ApexEventList) {
+ foundEventListFields = true;
+
+ // Add the events to the event list
+ eventList.addAll((ApexEventList) fieldObject);
+ } else {
+ foundOtherFields = true;
+ }
+ }
+
+ // If we found both event list fields and other fields we're in trouble
+ if (foundEventListFields && foundOtherFields) {
+ throw new ApexEventException("incoming event (" + eventObject
+ + ") has both event list fields and other fields, it cannot be processed");
+ }
+
+ // Check if the incoming event just has other fields, if so it's just a regular event
+ // and we add it to the event list as the only event there
+ if (foundOtherFields) {
+ eventList.add(event);
+ }
+ } catch (final Exception e) {
+ final String errorString = "Failed to unmarshal APEX event: " + e.getMessage() + ", event=" + eventObject;
+ LOGGER.warn(errorString, e);
+ throw new ApexEventException(errorString, e);
+ }
+
+ // Return the list of events we have unmarshalled
+ return eventList;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventConverter#fromApexEvent(org.onap.policy.
+ * apex.service.engine.event.ApexEvent)
+ */
+ @Override
+ public Object fromApexEvent(final ApexEvent apexEvent) throws ApexEventException {
+ // Check the Apex event
+ if (apexEvent == null) {
+ LOGGER.warn("event processing failed, Apex event is null");
+ throw new ApexEventException("event processing failed, Apex event is null");
+ }
+
+ return apexEvent;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/ApexEventProtocolParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/ApexEventProtocolParameters.java
new file mode 100644
index 000000000..10cd58eb7
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/ApexEventProtocolParameters.java
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.apexprotocolplugin;
+
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+
+/**
+ * Event protocol parameters for JSON as an event protocol, there are no user defined parameters.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexEventProtocolParameters extends EventProtocolParameters {
+ /** The label of this event protocol. */
+ public static final String APEX_EVENT_PROTOCOL_LABEL = "APEX";
+
+ /**
+ * Constructor to create a JSON event protocol parameter instance and register the instance with
+ * the parameter service.
+ */
+ public ApexEventProtocolParameters() {
+ this(ApexEventProtocolParameters.class.getCanonicalName(), APEX_EVENT_PROTOCOL_LABEL);
+ }
+
+ /**
+ * Constructor to create an event protocol parameters instance with the name of a sub class of
+ * this class.
+ *
+ * @param parameterClassName the class name of a sub class of this class
+ * @param eventProtocolLabel the name of the event protocol for this plugin
+ */
+ public ApexEventProtocolParameters(final String parameterClassName, final String eventProtocolLabel) {
+ super(parameterClassName);
+
+ // Set the event protocol properties for the JSON event protocol
+ this.setLabel(eventProtocolLabel);
+
+ // Set the event protocol plugin class
+ this.setEventProtocolPluginClass(Apex2ApexEventConverter.class.getCanonicalName());
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/package-info.java
new file mode 100644
index 000000000..a3c7d0d79
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/apexprotocolplugin/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains the implementation of the APEX event protocol converter plugin for events in Json
+ * format.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl.apexprotocolplugin;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/ApexEvent2EnEventConverter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/ApexEvent2EnEventConverter.java
new file mode 100644
index 000000000..90a19fff2
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/ApexEvent2EnEventConverter.java
@@ -0,0 +1,143 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.enevent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.ApexEventConverter;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import org.onap.policy.apex.core.engine.engine.ApexEngine;
+import org.onap.policy.apex.core.engine.event.EnEvent;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.basicmodel.service.ModelService;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
+
+/**
+ * The Class ApexEvent2EnEventConverter converts externally facing {@link ApexEvent} instances to
+ * and from instances of {@link EnEvent} that are used internally in the Apex engine core.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public final class ApexEvent2EnEventConverter implements ApexEventConverter {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexEvent2EnEventConverter.class);
+
+ // The Apex engine with its event definitions
+ private final ApexEngine apexEngine;
+
+ /**
+ * Set up the event converter.
+ *
+ * @param apexEngine The engine to use to create events to be converted
+ */
+ public ApexEvent2EnEventConverter(final ApexEngine apexEngine) {
+ this.apexEngine = apexEngine;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventConverter#toApexEvent(java.lang.String,
+ * java.lang.Object)
+ */
+ @Override
+ public List<ApexEvent> toApexEvent(final String eventName, final Object event) throws ApexException {
+ // Check the Engine event
+ if (event == null) {
+ LOGGER.warn("event processing failed, engine event is null");
+ throw new ApexEventException("event processing failed, engine event is null");
+ }
+
+ // Cast the event to an Engine event event, if our conversion is correctly configured, this
+ // cast should always work
+ EnEvent enEvent = null;
+ try {
+ enEvent = (EnEvent) event;
+ } catch (final Exception e) {
+ final String errorMessage = "error transferring event \"" + event + "\" to the Apex engine";
+ LOGGER.debug(errorMessage, e);
+ throw new ApexEventRuntimeException(errorMessage, e);
+ }
+
+ // Create the Apex event
+ final AxEvent axEvent = enEvent.getAxEvent();
+ final ApexEvent apexEvent = new ApexEvent(axEvent.getKey().getName(), axEvent.getKey().getVersion(),
+ axEvent.getNameSpace(), axEvent.getSource(), axEvent.getTarget());
+
+ // Copy the ExecutionID from the EnEvent into the ApexEvent
+ apexEvent.setExecutionID(enEvent.getExecutionID());
+
+ // Copy he exception message to the Apex event if it is set
+ if (enEvent.getExceptionMessage() != null) {
+ apexEvent.setExceptionMessage(enEvent.getExceptionMessage());
+ }
+
+ // Set the data on the apex event
+ apexEvent.putAll(enEvent);
+
+ // Return the event in a single element
+ final ArrayList<ApexEvent> eventList = new ArrayList<ApexEvent>();
+ eventList.add(apexEvent);
+ return eventList;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventConverter#fromApexEvent(org.onap.policy.
+ * apex.service.engine.event.ApexEvent)
+ */
+ @Override
+ public EnEvent fromApexEvent(final ApexEvent apexEvent) throws ApexException {
+ // Check the Apex model
+ if (apexEngine == null) {
+ LOGGER.warn("event processing failed, apex engine is null");
+ throw new ApexEventException("event processing failed, apex engine is null");
+ }
+
+ // Get the event definition
+ final AxEvent eventDefinition = ModelService.getModel(AxEvents.class).get(apexEvent.getName());
+ if (eventDefinition == null) {
+ LOGGER.warn("event processing failed, event \"" + apexEvent.getName() + "\" not found in apex model");
+ throw new ApexEventException(
+ "event processing failed, event \"" + apexEvent.getName() + "\" not found in apex model");
+ }
+
+ // Create the internal engine event
+ final EnEvent enEvent = apexEngine.createEvent(eventDefinition.getKey());
+
+ // Set the data on the engine event
+ enEvent.putAll(apexEvent);
+
+ // copy the ExecutionID from the ApexEvent into the EnEvent
+ enEvent.setExecutionID(apexEvent.getExecutionID());
+
+ return enEvent;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/package-info.java
new file mode 100644
index 000000000..6bc6bc2b3
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/enevent/package-info.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides conversion between externally facing
+ * {@link org.onap.policy.apex.service.engine.event.ApexEvent} instances and internal
+ * {@link org.onap.policy.apex.core.engine.event.EnEvent} instances.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl.enevent;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorCarrierTechnologyParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorCarrierTechnologyParameters.java
new file mode 100644
index 000000000..fb722ea2f
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorCarrierTechnologyParameters.java
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.eventrequestor;
+
+import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters;
+
+/**
+ * This class holds the parameters that allows an output event to to be sent back into APEX as one
+ * or multiple input events, there are no user defined parameters.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EventRequestorCarrierTechnologyParameters extends CarrierTechnologyParameters {
+ // @formatter:off
+ /** The label of this carrier technology. */
+ public static final String EVENT_REQUESTOR_CARRIER_TECHNOLOGY_LABEL = "EVENT_REQUESTOR";
+
+ /** The producer plugin class for the EVENT_REQUESTOR carrier technology. */
+ public static final String EVENT_REQUESTOR_EVENT_PRODUCER_PLUGIN_CLASS =
+ EventRequestorProducer.class.getCanonicalName();
+
+ /** The consumer plugin class for the EVENT_REQUESTOR carrier technology. */
+ public static final String EVENT_REQUESTOR_EVENT_CONSUMER_PLUGIN_CLASS =
+ EventRequestorConsumer.class.getCanonicalName();
+ // @formatter:on
+
+ /**
+ * Constructor to create an event requestor carrier technology parameters instance and register
+ * the instance with the parameter service.
+ */
+ public EventRequestorCarrierTechnologyParameters() {
+ super(EventRequestorCarrierTechnologyParameters.class.getCanonicalName());
+
+ // Set the carrier technology properties for the EVENT_REQUESTOR carrier technology
+ this.setLabel(EVENT_REQUESTOR_CARRIER_TECHNOLOGY_LABEL);
+ this.setEventProducerPluginClass(EVENT_REQUESTOR_EVENT_PRODUCER_PLUGIN_CLASS);
+ this.setEventConsumerPluginClass(EVENT_REQUESTOR_EVENT_CONSUMER_PLUGIN_CLASS);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ return "";
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorConsumer.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorConsumer.java
new file mode 100644
index 000000000..b472cc9c7
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorConsumer.java
@@ -0,0 +1,218 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.eventrequestor;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.service.engine.event.ApexEventConsumer;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventReceiver;
+import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
+import org.onap.policy.apex.service.engine.event.PeeredReference;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements an Apex event consumer that receives events from its peered event requestor
+ * producer.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EventRequestorConsumer implements ApexEventConsumer, Runnable {
+ // Get a reference to the logger
+ private static final Logger LOGGER = LoggerFactory.getLogger(EventRequestorConsumer.class);
+
+ // The amount of time to wait in milliseconds between checks that the consumer thread has
+ // stopped
+ private static final long EVENT_REQUESTOR_WAIT_SLEEP_TIME = 50;
+
+ // The event receiver that will receive events from this consumer
+ private ApexEventReceiver eventReceiver;
+
+ // The name for this consumer
+ private String name = null;
+
+ // The peer references for this event handler
+ private final Map<EventHandlerPeeredMode, PeeredReference> peerReferenceMap =
+ new EnumMap<>(EventHandlerPeeredMode.class);
+
+ // Temporary request holder for incoming event send requests
+ private final BlockingQueue<Object> incomingEventRequestQueue = new LinkedBlockingQueue<>();
+
+ // The consumer thread and stopping flag
+ private Thread consumerThread;
+ private boolean stopOrderedFlag = false;
+
+ // The number of events received to date
+ private int eventsReceived = 0;
+
+ @Override
+ public void init(final String consumerName, final EventHandlerParameters consumerParameters,
+ final ApexEventReceiver incomingEventReceiver) throws ApexEventException {
+ this.eventReceiver = incomingEventReceiver;
+ this.name = consumerName;
+
+ // Check and get the event requestor consumer properties
+ if (!(consumerParameters
+ .getCarrierTechnologyParameters() instanceof EventRequestorCarrierTechnologyParameters)) {
+ final String errorMessage =
+ "specified consumer properties are not applicable to event Requestor consumer (" + this.name + ")";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+
+ // Check if we are in peered mode
+ if (!consumerParameters.isPeeredMode(EventHandlerPeeredMode.REQUESTOR)) {
+ final String errorMessage = "event Requestor consumer (" + this.name
+ + ") must run in peered requestor mode with a event Requestor producer";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+
+ }
+
+ /**
+ * Receive an incoming event send request from the peered event Requestor producer and queue it
+ *
+ * @param eventObject the incoming event to process
+ * @throws ApexEventRuntimeException on queueing errors
+ */
+ public void processEvent(final Object eventObject) {
+ // Push the event onto the queue for handling
+ try {
+ incomingEventRequestQueue.add(eventObject);
+ } catch (final Exception e) {
+ final String errorMessage =
+ "could not queue request \"" + eventObject + "\" on event Requestor consumer (" + this.name + ")";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#start()
+ */
+ @Override
+ public void start() {
+ // Configure and start the event reception thread
+ final String threadName = this.getClass().getName() + ":" + this.name;
+ consumerThread = new ApplicationThreadFactory(threadName).newThread(this);
+ consumerThread.setDaemon(true);
+ consumerThread.start();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#getName()
+ */
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the number of events received to date
+ *
+ * @return the number of events received
+ */
+ public int getEventsReceived() {
+ return eventsReceived;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#getPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode)
+ */
+ @Override
+ public PeeredReference getPeeredReference(final EventHandlerPeeredMode peeredMode) {
+ return peerReferenceMap.get(peeredMode);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#setPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode,
+ * org.onap.policy.apex.service.engine.event.PeeredReference)
+ */
+ @Override
+ public void setPeeredReference(final EventHandlerPeeredMode peeredMode, final PeeredReference peeredReference) {
+ peerReferenceMap.put(peeredMode, peeredReference);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ // The endless loop that receives events using REST calls
+ while (consumerThread.isAlive() && !stopOrderedFlag) {
+ try {
+ // Take the next event from the queue
+ final Object eventObject =
+ incomingEventRequestQueue.poll(EVENT_REQUESTOR_WAIT_SLEEP_TIME, TimeUnit.MILLISECONDS);
+ if (eventObject == null) {
+ // Poll timed out, wait again
+ continue;
+ }
+
+ // Send the event into Apex
+ eventReceiver.receiveEvent(eventObject);
+
+ eventsReceived++;
+ } catch (final InterruptedException e) {
+ LOGGER.debug("Thread interrupted, Reason {}", e.getMessage());
+ Thread.currentThread().interrupt();
+ } catch (final Exception e) {
+ LOGGER.warn("error receiving events on thread {}", consumerThread.getName(), e);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.producer.ApexEventConsumer#stop()
+ */
+ @Override
+ public void stop() {
+ stopOrderedFlag = true;
+
+ while (consumerThread.isAlive()) {
+ ThreadUtilities.sleep(EVENT_REQUESTOR_WAIT_SLEEP_TIME);
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorProducer.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorProducer.java
new file mode 100644
index 000000000..4a972f2ce
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/EventRequestorProducer.java
@@ -0,0 +1,178 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.eventrequestor;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+import org.onap.policy.apex.service.engine.event.ApexEventConsumer;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventProducer;
+import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
+import org.onap.policy.apex.service.engine.event.PeeredReference;
+import org.onap.policy.apex.service.engine.event.SynchronousEventCache;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Concrete implementation of an Apex event producer that sends one or more events to its peered
+ * event requestor consumer.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ *
+ */
+public class EventRequestorProducer implements ApexEventProducer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(EventRequestorProducer.class);
+
+ // The name for this producer
+ private String name = null;
+
+ // The peer references for this event handler
+ private final Map<EventHandlerPeeredMode, PeeredReference> peerReferenceMap =
+ new EnumMap<>(EventHandlerPeeredMode.class);
+
+ // The number of events sent
+ private int eventsSent = 0;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#init(java.lang.String,
+ * org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters)
+ */
+ @Override
+ public void init(final String producerName, final EventHandlerParameters producerParameters)
+ throws ApexEventException {
+ this.name = producerName;
+
+ // Check and get the producer Properties
+ if (!(producerParameters
+ .getCarrierTechnologyParameters() instanceof EventRequestorCarrierTechnologyParameters)) {
+ final String errorMessage =
+ "specified consumer properties are not applicable to event requestor producer (" + this.name + ")";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+
+ // Check if we are in peered mode
+ if (!producerParameters.isPeeredMode(EventHandlerPeeredMode.REQUESTOR)) {
+ final String errorMessage = "Event Requestor producer (" + this.name
+ + ") must run in peered requestor mode with a Event Requestor consumer";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#getName()
+ */
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the number of events sent to date
+ *
+ * @return the number of events received
+ */
+ public int getEventsSent() {
+ return eventsSent;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#getPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode)
+ */
+ @Override
+ public PeeredReference getPeeredReference(final EventHandlerPeeredMode peeredMode) {
+ return peerReferenceMap.get(peeredMode);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#setPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode,
+ * org.onap.policy.apex.service.engine.event.PeeredReference)
+ */
+ @Override
+ public void setPeeredReference(final EventHandlerPeeredMode peeredMode, final PeeredReference peeredReference) {
+ peerReferenceMap.put(peeredMode, peeredReference);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#sendEvent(long, java.lang.
+ * String, java.lang.Object)
+ */
+ @Override
+ public void sendEvent(final long executionId, final String eventName, final Object eventObject) {
+ // Check if this is a synchronized event, if so we have received a reply
+ final SynchronousEventCache synchronousEventCache =
+ (SynchronousEventCache) peerReferenceMap.get(EventHandlerPeeredMode.SYNCHRONOUS);
+ if (synchronousEventCache != null) {
+ synchronousEventCache.removeCachedEventToApexIfExists(executionId);
+ }
+
+ // Find the peered consumer for this producer
+ final PeeredReference peeredRequestorReference = peerReferenceMap.get(EventHandlerPeeredMode.REQUESTOR);
+ if (peeredRequestorReference != null) {
+ // Find the event Response Consumer that will handle this request
+ final ApexEventConsumer consumer = peeredRequestorReference.getPeeredConsumer();
+ if (!(consumer instanceof EventRequestorConsumer)) {
+ final String errorMessage = "send of event to event consumer \""
+ + peeredRequestorReference.getPeeredConsumer() + "\" failed,"
+ + " event response consumer is not an instance of EventRequestorConsumer\n" + eventObject;
+ LOGGER.warn(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+
+ // Use the consumer to handle this event
+ final EventRequestorConsumer eventRequstConsumer = (EventRequestorConsumer) consumer;
+ eventRequstConsumer.processEvent(eventObject);
+
+ eventsSent++;
+ } else {
+ // No peered consumer defined
+ final String errorMessage = "send of event failed, event response consumer is not defined\n" + eventObject;
+ LOGGER.warn(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#stop()
+ */
+ @Override
+ public void stop() {
+ // For event requestor, all the implementation is in the consumer
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/package-info.java
new file mode 100644
index 000000000..3b6da08a4
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/eventrequestor/package-info.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Implements the Event Requestor carrier technology for multiple event input from an output event.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl.eventrequestor;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/FILECarrierTechnologyParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/FILECarrierTechnologyParameters.java
new file mode 100644
index 000000000..f7f25cb9e
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/FILECarrierTechnologyParameters.java
@@ -0,0 +1,208 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin;
+
+import org.onap.policy.apex.model.utilities.ResourceUtils;
+import org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer.ApexFileEventConsumer;
+import org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.producer.ApexFileEventProducer;
+import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters;
+
+/**
+ * This class holds the parameters that allows transport of events into and out of Apex using files
+ * and standard input and output.
+ *
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>fileName: The full path to the file from which to read events or to which to write events.
+ * <li>standardIO: If this flag is set to true, then standard input is used to read events in or
+ * standard output is used to write events and the fileName parameter is ignored if present
+ * <li>standardError: If this flag is set to true, then standard error is used to write events
+ * <li>streamingMode: If this flag is set to true, then streaming mode is set for reading events and
+ * event handling will wait on the input stream for events until the stream is closed. If streaming
+ * model is off, then event reading completes when the end of input is detected.
+ * <li>startDelay: The amount of milliseconds to wait at startup startup before processing the first
+ * event.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class FILECarrierTechnologyParameters extends CarrierTechnologyParameters {
+ // @formatter:off
+ /** The label of this carrier technology. */
+ public static final String FILE_CARRIER_TECHNOLOGY_LABEL = "FILE";
+
+ /** The producer plugin class for the FILE carrier technology. */
+ public static final String FILE_EVENT_PRODUCER_PLUGIN_CLASS = ApexFileEventProducer.class.getCanonicalName();
+
+ /** The consumer plugin class for the FILE carrier technology. */
+ public static final String FILE_EVENT_CONSUMER_PLUGIN_CLASS = ApexFileEventConsumer.class.getCanonicalName();
+
+ private String fileName;
+ private boolean standardIO = false;
+ private boolean standardError = false;
+ private boolean streamingMode = false;
+ private long startDelay = 0;
+ // @formatter:on
+
+ /**
+ * Constructor to create a file carrier technology parameters instance and register the instance
+ * with the parameter service.
+ */
+ public FILECarrierTechnologyParameters() {
+ super(FILECarrierTechnologyParameters.class.getCanonicalName());
+
+ // Set the carrier technology properties for the FILE carrier technology
+ this.setLabel(FILE_CARRIER_TECHNOLOGY_LABEL);
+ this.setEventProducerPluginClass(FILE_EVENT_PRODUCER_PLUGIN_CLASS);
+ this.setEventConsumerPluginClass(FILE_EVENT_CONSUMER_PLUGIN_CLASS);
+ }
+
+ /**
+ * Gets the file name from which to read or to which to write events.
+ *
+ * @return the file name from which to read or to which to write events
+ */
+ public String getFileName() {
+ return ResourceUtils.getFilePath4Resource(fileName);
+ }
+
+ /**
+ * Checks if is standard IO should be used for input or output.
+ *
+ * @return true, if standard IO should be used for input or output
+ */
+ public boolean isStandardIO() {
+ return standardIO;
+ }
+
+ /**
+ * Checks if is standard error should be used for output.
+ *
+ * @return true, if standard error should be used for output
+ */
+ public boolean isStandardError() {
+ return standardError;
+ }
+
+ /**
+ * Checks if is streaming mode is on.
+ *
+ * @return true, if streaming mode is on
+ */
+ public boolean isStreamingMode() {
+ return streamingMode;
+ }
+
+ /**
+ * Sets the file name from which to read or to which to write events.
+ *
+ * @param fileName the file name from which to read or to which to write events
+ */
+ public void setFileName(final String fileName) {
+ this.fileName = fileName;
+ }
+
+ /**
+ * Sets if standard IO should be used for event input or output.
+ *
+ * @param standardIO if standard IO should be used for event input or output
+ */
+ public void setStandardIO(final boolean standardIO) {
+ this.standardIO = standardIO;
+ }
+
+ /**
+ * Sets if standard error should be used for event output.
+ *
+ * @param standardError if standard error should be used for event output
+ */
+ public void setStandardError(final boolean standardError) {
+ this.standardError = standardError;
+ }
+
+ /**
+ * Sets streaming mode.
+ *
+ * @param streamingMode the streaming mode value
+ */
+ public void setStreamingMode(final boolean streamingMode) {
+ this.streamingMode = streamingMode;
+ }
+
+ /**
+ * Gets the delay in milliseconds before the plugin starts processing
+ *
+ * @return the delay
+ */
+ public long getStartDelay() {
+ return startDelay;
+ }
+
+ /**
+ * Sets the delay in milliseconds before the plugin starts processing
+ *
+ * @param startDelay the delay
+ */
+ public void setStartDelay(final long startDelay) {
+ this.startDelay = startDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters#
+ * toString()
+ */
+ @Override
+ public String toString() {
+ return "FILECarrierTechnologyParameters [fileName=" + fileName + ", standardIO=" + standardIO
+ + ", standardError=" + standardError + ", streamingMode=" + streamingMode + ", startDelay=" + startDelay
+ + "]";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ errorMessageBuilder.append(super.validate());
+
+ if (!standardIO && !standardError && (fileName == null || fileName.trim().length() == 0)) {
+ errorMessageBuilder.append(
+ " fileName not specified or is blank or null, it must be specified as a valid file location\n");
+ }
+
+ if (standardIO || standardError) {
+ streamingMode = true;
+ }
+
+ if (startDelay < 0) {
+ errorMessageBuilder.append(" startDelay must be zero or a positive number of milliseconds\n");
+ }
+
+ return errorMessageBuilder.toString();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/ApexFileEventConsumer.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/ApexFileEventConsumer.java
new file mode 100644
index 000000000..7521c3a08
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/ApexFileEventConsumer.java
@@ -0,0 +1,247 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.service.engine.event.ApexEventConsumer;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventReceiver;
+import org.onap.policy.apex.service.engine.event.PeeredReference;
+import org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.FILECarrierTechnologyParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Concrete implementation an Apex event consumer that reads events from a file. This consumer also
+ * implements ApexEventProducer and therefore can be used as a synchronous consumer.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexFileEventConsumer implements ApexEventConsumer, Runnable {
+
+ // Get a reference to the logger
+ private static final Logger LOGGER = LoggerFactory.getLogger(ApexFileEventConsumer.class);
+
+ // The input stream to read events from
+ private InputStream eventInputStream;
+
+ // The text block reader that will read text blocks from the contents of the file
+ private TextBlockReader textBlockReader;
+
+ // The event receiver that will receive asynchronous events from this consumer
+ private ApexEventReceiver eventReceiver = null;
+
+ // The consumer thread and stopping flag
+ private Thread consumerThread;
+
+ // The name for this consumer
+ private String consumerName = null;
+
+ // The specific carrier technology parameters for this consumer
+ private FILECarrierTechnologyParameters fileCarrierTechnologyParameters;
+
+ // The peer references for this event handler
+ private final Map<EventHandlerPeeredMode, PeeredReference> peerReferenceMap =
+ new EnumMap<>(EventHandlerPeeredMode.class);
+
+ // Holds the next identifier for event execution.
+ private static AtomicLong nextExecutionID = new AtomicLong(0L);
+
+ /**
+ * Private utility to get the next candidate value for a Execution ID. This value will always be
+ * unique in a single JVM
+ *
+ * @return the next candidate value for a Execution ID
+ */
+ private static synchronized long getNextExecutionID() {
+ return nextExecutionID.getAndIncrement();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.apps.uservice.consumer.ApexEventConsumer#init(org.onap.policy.apex.apps.
+ * uservice.consumer.ApexEventReceiver)
+ */
+ @Override
+ public void init(final String name, final EventHandlerParameters consumerParameters,
+ final ApexEventReceiver incomingEventReceiver) throws ApexEventException {
+ this.eventReceiver = incomingEventReceiver;
+ this.consumerName = name;
+
+ // Get and check the Apex parameters from the parameter service
+ if (consumerParameters == null) {
+ final String errorMessage = "Consumer parameters for ApexFileConsumer \"" + consumerName + "\" is null";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+
+ // Check and get the file Properties
+ if (!(consumerParameters.getCarrierTechnologyParameters() instanceof FILECarrierTechnologyParameters)) {
+ final String errorMessage = "specified consumer properties for ApexFileConsumer \"" + consumerName
+ + "\" are not applicable to a File consumer";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+ fileCarrierTechnologyParameters =
+ (FILECarrierTechnologyParameters) consumerParameters.getCarrierTechnologyParameters();
+
+ // Open the file producing events
+ try {
+ if (fileCarrierTechnologyParameters.isStandardIO()) {
+ eventInputStream = System.in;
+ } else {
+ eventInputStream = new FileInputStream(fileCarrierTechnologyParameters.getFileName());
+ }
+
+ // Get an event composer for our event source
+ textBlockReader = new TextBlockReaderFactory().getTaggedReader(eventInputStream,
+ consumerParameters.getEventProtocolParameters());
+ } catch (final IOException e) {
+ final String errorMessage = "ApexFileConsumer \"" + consumerName + "\" failed to open file for reading: \""
+ + fileCarrierTechnologyParameters.getFileName() + "\"";
+ LOGGER.warn(errorMessage, e);
+ throw new ApexEventException(errorMessage, e);
+ }
+
+ if (fileCarrierTechnologyParameters.getStartDelay() > 0) {
+ ThreadUtilities.sleep(fileCarrierTechnologyParameters.getStartDelay());
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#getName()
+ */
+ @Override
+ public String getName() {
+ return consumerName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#getPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode)
+ */
+ @Override
+ public PeeredReference getPeeredReference(final EventHandlerPeeredMode peeredMode) {
+ return peerReferenceMap.get(peeredMode);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#setPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode,
+ * org.onap.policy.apex.service.engine.event.PeeredReference)
+ */
+ @Override
+ public void setPeeredReference(final EventHandlerPeeredMode peeredMode, final PeeredReference peeredReference) {
+ peerReferenceMap.put(peeredMode, peeredReference);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventConsumer#start()
+ */
+ @Override
+ public void start() {
+ // Configure and start the event reception thread
+ final String threadName = this.getClass().getName() + " : " + consumerName;
+ consumerThread = new ApplicationThreadFactory(threadName).newThread(this);
+ consumerThread.setDaemon(true);
+ consumerThread.start();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ // Check that we have been initialized in async or sync mode
+ if (eventReceiver == null) {
+ LOGGER.warn("\"{}\" has not been initilaized for either asynchronous or synchronous event handling",
+ consumerName);
+ return;
+ }
+
+ // Read the events from the file while there are still events in the file
+ try {
+ // Read all the text blocks
+ TextBlock textBlock;
+ do {
+ // Read the text block
+ textBlock = textBlockReader.readTextBlock();
+
+ // Process the event from the text block if there is one there
+ if (textBlock.getText() != null) {
+ eventReceiver.receiveEvent(getNextExecutionID(), textBlock.getText());
+ }
+ } while (!textBlock.isEndOfText());
+ } catch (final Exception e) {
+ LOGGER.warn("\"" + consumerName + "\" failed to read event from file: \""
+ + fileCarrierTechnologyParameters.getFileName() + "\"", e);
+ } finally {
+ try {
+ eventInputStream.close();
+ } catch (final IOException e) {
+ LOGGER.warn("ApexFileConsumer \"" + consumerName + "\" failed to close file: \""
+ + fileCarrierTechnologyParameters.getFileName() + "\"", e);
+ }
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.producer.ApexEventProducer#stop()
+ */
+ @Override
+ public void stop() {
+ try {
+ eventInputStream.close();
+ } catch (final IOException e) {
+ LOGGER.warn("ApexFileConsumer \"" + consumerName + "\" failed to close file for reading: \""
+ + fileCarrierTechnologyParameters.getFileName() + "\"", e);
+ }
+
+ if (consumerThread.isAlive() && !consumerThread.isInterrupted()) {
+ consumerThread.interrupt();
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/CharacterDelimitedTextBlockReader.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/CharacterDelimitedTextBlockReader.java
new file mode 100644
index 000000000..b286f8afe
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/CharacterDelimitedTextBlockReader.java
@@ -0,0 +1,141 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolTextCharDelimitedParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The class CharacterDelimitedTextBlockReader reads the next block of text between two character
+ * tags from an input stream.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class CharacterDelimitedTextBlockReader implements TextBlockReader {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(CharacterDelimitedTextBlockReader.class);
+
+ // The character tags
+ private final char startTagChar;
+ private final char endTagChar;
+
+ // The input stream for text
+ private InputStream inputStream;
+
+ // Flag indicating we have seen EOF on the stream
+ private boolean eofOnInputStream = false;
+
+ /**
+ * Constructor, set the delimiters.
+ *
+ * @param startTagChar The start tag for text blocks
+ * @param endTagChar The end tag for text blocks
+ */
+ public CharacterDelimitedTextBlockReader(final char startTagChar, final char endTagChar) {
+ this.startTagChar = startTagChar;
+ this.endTagChar = endTagChar;
+ }
+
+ /**
+ * Constructor, set the delimiters from a character delimited event protocol parameter class.
+ *
+ * @param charDelimitedParameters the character delimited event protocol parameter class
+ */
+ public CharacterDelimitedTextBlockReader(final EventProtocolTextCharDelimitedParameters charDelimitedParameters) {
+ this.startTagChar = charDelimitedParameters.getStartChar();
+ this.endTagChar = charDelimitedParameters.getEndChar();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer.TextBlockReader#init(
+ * java.io.InputStream)
+ */
+ @Override
+ public void init(final InputStream incomingInputStream) {
+ this.inputStream = incomingInputStream;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer.TextBlockReader#
+ * readTextBlock()
+ */
+ @Override
+ public TextBlock readTextBlock() throws IOException {
+ // Check if there was a previous end of a text block with a non-empty text block returned
+ if (eofOnInputStream) {
+ return new TextBlock(eofOnInputStream, null);
+ }
+
+ // The initial nesting level of incoming text blocks is always zero
+ int nestingLevel = 0;
+
+ // Holder for the text block
+ final StringBuilder textBlockBuilder = new StringBuilder();
+
+ // Read the next text block
+ while (true) {
+ final char nextChar = (char) inputStream.read();
+
+ // Check for EOF
+ if (nextChar == (char) -1) {
+ eofOnInputStream = true;
+ break;
+ }
+
+ if (nextChar == startTagChar) {
+ nestingLevel++;
+ } else if (nestingLevel == 0 && !Character.isWhitespace(nextChar)) {
+ LOGGER.warn("invalid input on consumer: " + nextChar);
+ continue;
+ }
+
+ textBlockBuilder.append(nextChar);
+
+ // Check for end of the text block, we have come back to level 0
+ if (nextChar == endTagChar) {
+ if (nestingLevel > 0) {
+ nestingLevel--;
+ }
+
+ if (nestingLevel == 0) {
+ break;
+ }
+ }
+ }
+
+ // Condition the text block and return it
+ final String textBlock = textBlockBuilder.toString().trim();
+ if (textBlock.length() > 0) {
+ return new TextBlock(eofOnInputStream, textBlock);
+ } else {
+ return new TextBlock(eofOnInputStream, null);
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/HeaderDelimitedTextBlockReader.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/HeaderDelimitedTextBlockReader.java
new file mode 100644
index 000000000..e40bc756c
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/HeaderDelimitedTextBlockReader.java
@@ -0,0 +1,167 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolTextTokenDelimitedParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The Class TextBlockReader reads the next block of text from an input stream.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class HeaderDelimitedTextBlockReader implements TextBlockReader, Runnable {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(HeaderDelimitedTextBlockReader.class);
+
+ // The amount of time to wait for input on the text block reader
+ private static final long TEXT_BLOCK_DELAY = 250;
+
+ // Tag for the start of a text block
+ private final String blockStartToken;
+
+ // The input stream for text
+ private InputStream inputStream;
+
+ // The lines of input read from the input stream
+ private final Queue<String> textLineQueue = new LinkedBlockingQueue<>();
+
+ // The thread used to read text from the input stream
+ private Thread textConsumputionThread;
+
+ // True while EOF has not been seen on input
+ private boolean eofOnInputStream = false;
+
+ /**
+ * Constructor, initialize the text block reader.
+ *
+ * @param blockStartToken the block start token for the start of a text block
+ */
+ public HeaderDelimitedTextBlockReader(final String blockStartToken) {
+ this.blockStartToken = blockStartToken;
+ }
+
+ /**
+ * Constructor, initialize the text block reader using token delimited event protocol
+ * parameters.
+ *
+ * @param tokenDelimitedParameters the token delimited event protocol parameters
+ */
+ public HeaderDelimitedTextBlockReader(final EventProtocolTextTokenDelimitedParameters tokenDelimitedParameters) {
+ this.blockStartToken = tokenDelimitedParameters.getDelimiterToken();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer.TextBlockReader#
+ * init( java.io.InputStream)
+ */
+ @Override
+ public void init(final InputStream incomingInputStream) {
+ this.inputStream = incomingInputStream;
+
+ // Configure and start the text reading thread
+ textConsumputionThread = new ApplicationThreadFactory(this.getClass().getName()).newThread(this);
+ textConsumputionThread.setDaemon(true);
+ textConsumputionThread.start();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer.TextBlockReader#
+ * readTextBlock()
+ */
+ @Override
+ public TextBlock readTextBlock() throws IOException {
+ // Holder for the current text block
+ final StringBuilder textBlockBuilder = new StringBuilder();
+
+ // Wait for the timeout period if there is no input
+ if (!eofOnInputStream && textLineQueue.size() == 0) {
+ ThreadUtilities.sleep(TEXT_BLOCK_DELAY);
+ }
+
+ // Scan the lines in the queue
+ while (textLineQueue.size() > 0) {
+ // Scroll down in the available lines looking for the start of the text block
+ if (textLineQueue.peek().startsWith(blockStartToken)) {
+ // Process the input line header
+ textBlockBuilder.append(textLineQueue.remove());
+ textBlockBuilder.append('\n');
+ break;
+ } else {
+ LOGGER.warn("invalid input on consumer: " + textLineQueue.remove());
+ }
+ }
+
+ // Get the rest of the text document
+ while (textLineQueue.size() > 0 && !textLineQueue.peek().startsWith(blockStartToken)) {
+ textBlockBuilder.append(textLineQueue.remove());
+ textBlockBuilder.append('\n');
+ }
+
+ // Condition the text block and return it
+ final String textBlock = textBlockBuilder.toString().trim();
+ final boolean endOfText = (eofOnInputStream && textLineQueue.size() == 0 ? true : false);
+
+ if (textBlock.length() > 0) {
+ return new TextBlock(endOfText, textBlock);
+ } else {
+ return new TextBlock(endOfText, null);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ final BufferedReader textReader = new BufferedReader(new InputStreamReader(inputStream));
+
+ try {
+ // Read the input line by line until we see end of file on the stream
+ String line;
+ while ((line = textReader.readLine()) != null) {
+ textLineQueue.add(line);
+ }
+ } catch (final IOException e) {
+ LOGGER.warn("I/O exception on text input on consumer: ", e);
+ } finally {
+ eofOnInputStream = true;
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlock.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlock.java
new file mode 100644
index 000000000..526d9c318
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlock.java
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer;
+
+/**
+ * This class is a bean that holds a block of text read from an incoming text file.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TextBlock {
+ private boolean endOfText = false;
+ private String text;
+
+ /**
+ * Constructor to initiate the text block.
+ *
+ * @param endOfText the end of text
+ * @param text the text
+ */
+ public TextBlock(final boolean endOfText, final String text) {
+ this.endOfText = endOfText;
+ this.text = text;
+ }
+
+ /**
+ * Checks if is end of text.
+ *
+ * @return true, if checks if is end of text
+ */
+ public boolean isEndOfText() {
+ return endOfText;
+ }
+
+ /**
+ * Sets whether end of text has been reached.
+ *
+ * @param endOfText the end of text flag value
+ */
+ public void setEndOfText(final boolean endOfText) {
+ this.endOfText = endOfText;
+ }
+
+ /**
+ * Gets the text of the text block.
+ *
+ * @return the text of the text block
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Sets the text of the text block.
+ *
+ * @param text the text of the text block
+ */
+ public void setText(final String text) {
+ this.text = text;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReader.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReader.java
new file mode 100644
index 000000000..627718402
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReader.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Implementers of the interface TextBlockReader read the next block of text from an input stream.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public interface TextBlockReader {
+ /**
+ * Initialize the text block reader reader.
+ *
+ * @param inputStream The stream to read from
+ */
+ void init(InputStream inputStream);
+
+ /**
+ * Read a block of text between two delimiters.
+ *
+ * @return The text block
+ * @throws IOException On reading errors
+ */
+ TextBlock readTextBlock() throws IOException;
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReaderFactory.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReaderFactory.java
new file mode 100644
index 000000000..e48266634
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/TextBlockReaderFactory.java
@@ -0,0 +1,80 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer;
+
+import java.io.InputStream;
+
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolTextCharDelimitedParameters;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolTextTokenDelimitedParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This factory creates text block readers for breaking character streams into blocks of text.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class TextBlockReaderFactory {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(TextBlockReaderFactory.class);
+
+ /**
+ * Get a text block reader for the given event protocol.
+ *
+ * @param inputStream the input stream that will be used for reading
+ * @param eventProtocolParameters the parameters that have been specified for event protocols
+ * @return the tagged reader
+ * @throws ApexEventException On an unsupported event protocol
+ */
+ public TextBlockReader getTaggedReader(final InputStream inputStream,
+ final EventProtocolParameters eventProtocolParameters) throws ApexEventException {
+ // Check the type of event protocol we have
+ if (eventProtocolParameters instanceof EventProtocolTextCharDelimitedParameters) {
+ // We have character delimited textual input
+ final EventProtocolTextCharDelimitedParameters charDelimitedParameters =
+ (EventProtocolTextCharDelimitedParameters) eventProtocolParameters;
+
+ // Create the text block reader
+ final TextBlockReader characterDelimitedTextBlockReader =
+ new CharacterDelimitedTextBlockReader(charDelimitedParameters);
+ characterDelimitedTextBlockReader.init(inputStream);
+ return characterDelimitedTextBlockReader;
+ } else if (eventProtocolParameters instanceof EventProtocolTextTokenDelimitedParameters) {
+ // We have token delimited textual input
+ final EventProtocolTextTokenDelimitedParameters tokenDelimitedParameters =
+ (EventProtocolTextTokenDelimitedParameters) eventProtocolParameters;
+
+ // Create the text block reader
+ final HeaderDelimitedTextBlockReader headerDelimitedTextBlockReader =
+ new HeaderDelimitedTextBlockReader(tokenDelimitedParameters);
+ headerDelimitedTextBlockReader.init(inputStream);
+ return headerDelimitedTextBlockReader;
+ } else {
+ final String errorMessage =
+ "could not create text block reader for a textual event protocol, the required type "
+ + eventProtocolParameters.getLabel() + " is not supported";
+ LOGGER.error(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/package-info.java
new file mode 100644
index 000000000..05833ac7c
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/consumer/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Implements the FILE carrier technology consumer that sends events to APEX from files, standard IO
+ * or named pipes.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.consumer;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/package-info.java
new file mode 100644
index 000000000..de0b1b56e
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Implements the FILE carrier technology for event input and output to and from Apex using files,
+ * named pipes, and standard IO.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/ApexFileEventProducer.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/ApexFileEventProducer.java
new file mode 100644
index 000000000..d5f9ff1b2
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/ApexFileEventProducer.java
@@ -0,0 +1,181 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.producer;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.EnumMap;
+import java.util.Map;
+
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventProducer;
+import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
+import org.onap.policy.apex.service.engine.event.PeeredReference;
+import org.onap.policy.apex.service.engine.event.SynchronousEventCache;
+import org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.FILECarrierTechnologyParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Concrete implementation of an Apex event producer that sends events to a file.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexFileEventProducer implements ApexEventProducer {
+ // Get a reference to the logger
+ private static final Logger LOGGER = LoggerFactory.getLogger(ApexFileEventProducer.class);
+
+ // The name for this producer
+ private String producerName = null;
+
+ // The output stream to write events to
+ private PrintStream eventOutputStream;
+
+ // The peer references for this event handler
+ private final Map<EventHandlerPeeredMode, PeeredReference> peerReferenceMap =
+ new EnumMap<>(EventHandlerPeeredMode.class);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.producer.ApexEventProducer#init()
+ */
+ @Override
+ public void init(final String name, final EventHandlerParameters producerParameters) throws ApexEventException {
+ producerName = name;
+
+ // Get and check the Apex parameters from the parameter service
+ if (producerParameters == null) {
+ final String errorMessage = "Producer parameters for ApexFileProducer \"" + producerName + "\" is null";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+
+ // Check and get the file Properties
+ if (!(producerParameters.getCarrierTechnologyParameters() instanceof FILECarrierTechnologyParameters)) {
+ final String errorMessage = "specified producer properties for ApexFileProducer \"" + producerName
+ + "\" are not applicable to a FILE producer";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+ final FILECarrierTechnologyParameters fileCarrierTechnologyParameters =
+ (FILECarrierTechnologyParameters) producerParameters.getCarrierTechnologyParameters();
+
+ // Now we create a writer for events
+ try {
+ if (fileCarrierTechnologyParameters.isStandardError()) {
+ eventOutputStream = System.err;
+ } else if (fileCarrierTechnologyParameters.isStandardIO()) {
+ eventOutputStream = System.out;
+ } else {
+ eventOutputStream =
+ new PrintStream(new FileOutputStream(fileCarrierTechnologyParameters.getFileName()), true);
+ }
+ } catch (final IOException e) {
+ final String errorMessage = "ApexFileProducer \"" + producerName + "\" failed to open file for writing: \""
+ + fileCarrierTechnologyParameters.getFileName() + "\"";
+ LOGGER.warn(errorMessage, e);
+ throw new ApexEventException(errorMessage, e);
+ }
+
+ if (fileCarrierTechnologyParameters.getStartDelay() > 0) {
+ ThreadUtilities.sleep(fileCarrierTechnologyParameters.getStartDelay());
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#getName()
+ */
+ @Override
+ public String getName() {
+ return producerName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#getPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode)
+ */
+ @Override
+ public PeeredReference getPeeredReference(final EventHandlerPeeredMode peeredMode) {
+ return peerReferenceMap.get(peeredMode);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#setPeeredReference(org.onap.
+ * policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode,
+ * org.onap.policy.apex.service.engine.event.PeeredReference)
+ */
+ @Override
+ public void setPeeredReference(final EventHandlerPeeredMode peeredMode, final PeeredReference peeredReference) {
+ peerReferenceMap.put(peeredMode, peeredReference);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventProducer#sendEvent(long,
+ * java.lang.String, java.lang.Object)
+ */
+ @Override
+ public void sendEvent(final long executionId, final String eventName, final Object event) {
+ // Check if this is a synchronized event, if so we have received a reply
+ final SynchronousEventCache synchronousEventCache =
+ (SynchronousEventCache) peerReferenceMap.get(EventHandlerPeeredMode.SYNCHRONOUS);
+ if (synchronousEventCache != null) {
+ synchronousEventCache.removeCachedEventToApexIfExists(executionId);
+ }
+
+ // Cast the event to a string, if our conversion is correctly configured, this cast should
+ // always work
+ String stringEvent = null;
+ try {
+ stringEvent = (String) event;
+ } catch (final Exception e) {
+ final String errorMessage = "error in ApexFileProducer \"" + producerName + "\" while transferring event \""
+ + event + "\" to the output stream";
+ LOGGER.debug(errorMessage, e);
+ throw new ApexEventRuntimeException(errorMessage, e);
+ }
+
+ eventOutputStream.println(stringEvent);
+ eventOutputStream.flush();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.producer.ApexEventProducer#stop()
+ */
+ @Override
+ public void stop() {
+ eventOutputStream.close();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/package-info.java
new file mode 100644
index 000000000..f7d7cbfbd
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/filecarrierplugin/producer/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Implements the FILE carrier technology producer that outputs events from APEX to files, standard
+ * IO or named pipes.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.producer;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/Apex2JSONEventConverter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/Apex2JSONEventConverter.java
new file mode 100644
index 000000000..3b21a29ca
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/Apex2JSONEventConverter.java
@@ -0,0 +1,433 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.jsonprotocolplugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.policy.apex.context.SchemaHelper;
+import org.onap.policy.apex.context.impl.schema.SchemaHelperFactory;
+import org.onap.policy.apex.model.basicmodel.service.ModelService;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
+import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+/**
+ * The Class Apex2JSONEventConverter converts {@link ApexEvent} instances to and from JSON string
+ * representations of Apex events.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class Apex2JSONEventConverter implements ApexEventProtocolConverter {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(Apex2JSONEventConverter.class);
+
+ // The parameters for the JSON event protocol
+ private JSONEventProtocolParameters jsonPars;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter#init(org.onap.policy.
+ * apex.service.parameters.eventprotocol.EventProtocolParameters)
+ */
+ @Override
+ public void init(final EventProtocolParameters parameters) {
+ // Check and get the JSON parameters
+ if (!(parameters instanceof JSONEventProtocolParameters)) {
+ final String errorMessage = "specified consumer properties are not applicable to the JSON event protocol";
+ LOGGER.warn(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+
+ jsonPars = (JSONEventProtocolParameters) parameters;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventConverter#toApexEvent(java.lang.String,
+ * java.lang.Object)
+ */
+ @Override
+ public List<ApexEvent> toApexEvent(final String eventName, final Object eventObject) throws ApexEventException {
+ // Check the event eventObject
+ if (eventObject == null) {
+ LOGGER.warn("event processing failed, event is null");
+ throw new ApexEventException("event processing failed, event is null");
+ }
+
+ // Cast the event to a string, if our conversion is correctly configured, this cast should
+ // always work
+ String jsonEventString = null;
+ try {
+ jsonEventString = (String) eventObject;
+ } catch (final Exception e) {
+ final String errorMessage = "error converting event \"" + eventObject + "\" to a string";
+ LOGGER.debug(errorMessage, e);
+ throw new ApexEventRuntimeException(errorMessage, e);
+ }
+
+ // The list of events we will return
+ final List<ApexEvent> eventList = new ArrayList<ApexEvent>();
+
+ try {
+ // We may have a single JSON object with a single event or an array of JSON objects
+ final Object decodedJsonObject =
+ new GsonBuilder().serializeNulls().create().fromJson(jsonEventString, Object.class);
+
+ // Check if we have a list of objects
+ if (decodedJsonObject instanceof List) {
+ // Check if it's a list of JSON objects or a list of strings
+ @SuppressWarnings("unchecked")
+ final List<Object> decodedJsonList = (List<Object>) decodedJsonObject;
+
+ // Decode each of the list elements in sequence
+ for (final Object jsonListObject : decodedJsonList) {
+ if (jsonListObject instanceof String) {
+ eventList.add(jsonStringApexEvent(eventName, (String) jsonListObject));
+ } else if (jsonListObject instanceof JsonObject) {
+ eventList.add(jsonObject2ApexEvent(eventName, (JsonObject) jsonListObject));
+ } else {
+ throw new ApexEventException("incoming event (" + jsonEventString
+ + ") is a JSON object array containing an invalid object " + jsonListObject);
+ }
+ }
+ } else {
+ eventList.add(jsonStringApexEvent(eventName, jsonEventString));
+ }
+ } catch (final Exception e) {
+ final String errorString =
+ "Failed to unmarshal JSON event: " + e.getMessage() + ", event=" + jsonEventString;
+ LOGGER.warn(errorString, e);
+ throw new ApexEventException(errorString, e);
+ }
+
+ // Return the list of events we have unmarshalled
+ return eventList;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventConverter#fromApexEvent(org.onap.policy.
+ * apex.service.engine.event.ApexEvent)
+ */
+ @Override
+ public Object fromApexEvent(final ApexEvent apexEvent) throws ApexEventException {
+ // Check the Apex event
+ if (apexEvent == null) {
+ LOGGER.warn("event processing failed, Apex event is null");
+ throw new ApexEventException("event processing failed, Apex event is null");
+ }
+
+ // Get the event definition for the event from the model service
+ final AxEvent eventDefinition =
+ ModelService.getModel(AxEvents.class).get(apexEvent.getName(), apexEvent.getVersion());
+
+ // Use a GSON Json object to marshal the Apex event to JSON
+ final Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
+ final JsonObject jsonObject = new JsonObject();
+
+ jsonObject.addProperty(ApexEvent.NAME_HEADER_FIELD, apexEvent.getName());
+ jsonObject.addProperty(ApexEvent.VERSION_HEADER_FIELD, apexEvent.getVersion());
+ jsonObject.addProperty(ApexEvent.NAMESPACE_HEADER_FIELD, apexEvent.getNameSpace());
+ jsonObject.addProperty(ApexEvent.SOURCE_HEADER_FIELD, apexEvent.getSource());
+ jsonObject.addProperty(ApexEvent.TARGET_HEADER_FIELD, apexEvent.getTarget());
+
+ if (apexEvent.getExceptionMessage() != null) {
+ jsonObject.addProperty(ApexEvent.EXCEPTION_MESSAGE_HEADER_FIELD, apexEvent.getExceptionMessage());
+ }
+
+ for (final AxField eventField : eventDefinition.getFields()) {
+ final String fieldName = eventField.getKey().getLocalName();
+
+ if (!apexEvent.containsKey(fieldName)) {
+ if (!eventField.getOptional()) {
+ final String errorMessage = "error parsing " + eventDefinition.getID() + " event to Json. "
+ + "Field \"" + fieldName + "\" is missing, but is mandatory. Fields: " + apexEvent;
+ LOGGER.debug(errorMessage);
+ throw new ApexEventRuntimeException(errorMessage);
+ }
+ continue;
+ }
+
+ final Object fieldValue = apexEvent.get(fieldName);
+
+ // Get the schema helper
+ final SchemaHelper fieldSchemaHelper =
+ new SchemaHelperFactory().createSchemaHelper(eventField.getKey(), eventField.getSchema());
+ jsonObject.add(fieldName, fieldSchemaHelper.marshal2JsonElement(fieldValue));
+ }
+
+ // Output JSON string in a pretty format
+ return gson.toJson(jsonObject);
+ }
+
+ /**
+ * This method converts a JSON object into an Apex event.
+ *
+ * @param eventName the name of the event
+ * @param jsonEventString the JSON string that holds the event
+ * @return the apex event that we have converted the JSON object into
+ * @throws ApexEventException thrown on unmarshaling exceptions
+ */
+ private ApexEvent jsonStringApexEvent(final String eventName, final String jsonEventString)
+ throws ApexEventException {
+ // Use GSON to read the event string
+ final JsonObject jsonObject =
+ new GsonBuilder().serializeNulls().create().fromJson(jsonEventString, JsonObject.class);
+
+ if (jsonObject == null || !jsonObject.isJsonObject()) {
+ throw new ApexEventException(
+ "incoming event (" + jsonEventString + ") is not a JSON object or an JSON object array");
+ }
+
+ return jsonObject2ApexEvent(eventName, jsonObject);
+ }
+
+ /**
+ * This method converts a JSON object into an Apex event.
+ *
+ * @param eventName the name of the event
+ * @param jsonObject the JSON object that holds the event
+ * @return the apex event that we have converted the JSON object into
+ * @throws ApexEventException thrown on unmarshaling exceptions
+ */
+ private ApexEvent jsonObject2ApexEvent(final String eventName, final JsonObject jsonObject)
+ throws ApexEventException {
+ // Process the mandatory Apex header
+ final ApexEvent apexEvent = processApexEventHeader(eventName, jsonObject);
+
+ // Get the event definition for the event from the model service
+ final AxEvent eventDefinition =
+ ModelService.getModel(AxEvents.class).get(apexEvent.getName(), apexEvent.getVersion());
+
+ // Iterate over the input fields in the event
+ for (final AxField eventField : eventDefinition.getFields()) {
+ final String fieldName = eventField.getKey().getLocalName();
+ if (!hasJSONField(jsonObject, fieldName)) {
+ if (!eventField.getOptional()) {
+ final String errorMessage = "error parsing " + eventDefinition.getID() + " event from Json. "
+ + "Field \"" + fieldName + "\" is missing, but is mandatory.";
+ LOGGER.debug(errorMessage);
+ throw new ApexEventException(errorMessage);
+ }
+ continue;
+ }
+
+ final JsonElement fieldValue = getJSONField(jsonObject, fieldName, null, !eventField.getOptional());
+
+ if (fieldValue != null && !fieldValue.isJsonNull()) {
+ // Get the schema helper
+ final SchemaHelper fieldSchemaHelper =
+ new SchemaHelperFactory().createSchemaHelper(eventField.getKey(), eventField.getSchema());
+ apexEvent.put(fieldName, fieldSchemaHelper.createNewInstance(fieldValue));
+ } else {
+ apexEvent.put(fieldName, null);
+ }
+ }
+ return apexEvent;
+
+ }
+
+ /**
+ * This method processes the event header of an Apex event.
+ *
+ * @param eventName the name of the event
+ * @param jsonObject the JSON object containing the JSON representation of the incoming event
+ * @return an apex event constructed using the header fields of the event
+ * @throws ApexEventRuntimeException the apex event runtime exception
+ * @throws ApexEventException on invalid events with missing header fields
+ */
+ private ApexEvent processApexEventHeader(final String eventName, final JsonObject jsonObject)
+ throws ApexEventRuntimeException, ApexEventException {
+ // Get the event header fields
+ // @formatter:off
+ String name = getJSONStringField(jsonObject, ApexEvent.NAME_HEADER_FIELD, jsonPars.getNameAlias(), ApexEvent.NAME_REGEXP, false);
+ String version = getJSONStringField(jsonObject, ApexEvent.VERSION_HEADER_FIELD, jsonPars.getVersionAlias(), ApexEvent.VERSION_REGEXP, false);
+ String namespace = getJSONStringField(jsonObject, ApexEvent.NAMESPACE_HEADER_FIELD, jsonPars.getNameSpaceAlias(), ApexEvent.NAMESPACE_REGEXP, false);
+ String source = getJSONStringField(jsonObject, ApexEvent.SOURCE_HEADER_FIELD, jsonPars.getSourceAlias(), ApexEvent.SOURCE_REGEXP, false);
+ String target = getJSONStringField(jsonObject, ApexEvent.TARGET_HEADER_FIELD, jsonPars.getTargetAlias(), ApexEvent.TARGET_REGEXP, false);
+ // @formatter:on
+
+ // Check if an event name was specified on the event parameters
+ if (eventName != null) {
+ if (name != null && !eventName.equals(name)) {
+ LOGGER.warn("The incoming event name \"" + name + "\" does not match the configured event name \""
+ + eventName + "\", using configured event name");
+ }
+ name = eventName;
+ } else {
+ if (name == null) {
+ throw new ApexEventRuntimeException(
+ "event received without mandatory parameter \"name\" on configuration or on event");
+ }
+ }
+
+ // Now, find the event definition in the model service. If version is null, the newest event
+ // definition in the model service is used
+ final AxEvent eventDefinition = ModelService.getModel(AxEvents.class).get(name, version);
+ if (eventDefinition == null) {
+ if (version == null) {
+ throw new ApexEventRuntimeException(
+ "an event definition for an event named \"" + name + "\" not found in Apex model");
+ } else {
+ throw new ApexEventRuntimeException("an event definition for an event named \"" + name
+ + "\" with version \"" + version + "\" not found in Apex model");
+ }
+ }
+
+ // Use the defined event version if no version is specified on the incoming fields
+ if (version == null) {
+ version = eventDefinition.getKey().getVersion();
+ }
+
+ // Check the name space is OK if it is defined, if not, use the name space from the model
+ if (namespace != null) {
+ if (!namespace.equals(eventDefinition.getNameSpace())) {
+ throw new ApexEventRuntimeException(
+ "namespace \"" + namespace + "\" on event \"" + name + "\" does not match namespace \""
+ + eventDefinition.getNameSpace() + "\" for that event in the Apex model");
+ }
+ } else {
+ namespace = eventDefinition.getNameSpace();
+ }
+
+ // For source, use the defined source only if the source is not found on the incoming event
+ if (source == null) {
+ source = eventDefinition.getSource();
+ }
+
+ // For target, use the defined source only if the source is not found on the incoming event
+ if (target == null) {
+ target = eventDefinition.getTarget();
+ }
+
+ return new ApexEvent(name, version, namespace, source, target);
+ }
+
+ /**
+ * This method gets an event string field from a JSON object.
+ *
+ * @param jsonObject the JSON object containing the JSON representation of the incoming event
+ * @param fieldName the field name to find in the event
+ * @param fieldAlias the alias for the field to find in the event, overrides the field name if
+ * it is not null
+ * @param fieldRE the regular expression to check the field against for validity
+ * @param mandatory true if the field is mandatory
+ * @return the value of the field in the JSON object or null if the field is optional
+ * @throws ApexEventRuntimeException the apex event runtime exception
+ */
+ private String getJSONStringField(final JsonObject jsonObject, final String fieldName, final String fieldAlias,
+ final String fieldRE, final boolean mandatory) throws ApexEventRuntimeException {
+ // Get the JSON field for the string field
+ final JsonElement jsonField = getJSONField(jsonObject, fieldName, fieldAlias, mandatory);
+
+ // Null strings are allowed
+ if (jsonField == null || jsonField.isJsonNull()) {
+ return null;
+ }
+
+ // Check if this is a string field
+ String fieldValueString = null;
+ try {
+ fieldValueString = jsonField.getAsString();
+ } catch (final Exception e) {
+ // The element is not a string so throw an error
+ throw new ApexEventRuntimeException("field \"" + fieldName + "\" with type \""
+ + jsonField.getClass().getCanonicalName() + "\" is not a string value");
+ }
+
+ // Is regular expression checking required
+ if (fieldRE == null) {
+ return fieldValueString;
+ }
+
+ // Check the event field against its regular expression
+ if (!fieldValueString.matches(fieldRE)) {
+ throw new ApexEventRuntimeException(
+ "field \"" + fieldName + "\" with value \"" + fieldValueString + "\" is invalid");
+ }
+
+ return fieldValueString;
+ }
+
+ /**
+ * This method gets an event field from a JSON object.
+ *
+ * @param jsonObject the JSON object containing the JSON representation of the incoming event
+ * @param fieldName the field name to find in the event
+ * @param fieldAlias the alias for the field to find in the event, overrides the field name if
+ * it is not null
+ * @param mandatory true if the field is mandatory
+ * @return the value of the field in the JSON object or null if the field is optional
+ * @throws ApexEventRuntimeException the apex event runtime exception
+ */
+ private JsonElement getJSONField(final JsonObject jsonObject, final String fieldName, final String fieldAlias,
+ final boolean mandatory) throws ApexEventRuntimeException {
+
+ // Check if we should use the alias for this field
+ String fieldToFind = fieldName;
+ if (fieldAlias != null) {
+ fieldToFind = fieldAlias;
+ }
+
+ // Get the event field
+ final JsonElement eventElement = jsonObject.get(fieldToFind);
+ if (eventElement == null) {
+ if (!mandatory) {
+ return null;
+ } else {
+ throw new ApexEventRuntimeException("mandatory field \"" + fieldToFind + "\" is missing");
+ }
+ }
+
+ return eventElement;
+ }
+
+ /**
+ * This method if a JSON object has a named field.
+ *
+ * @param jsonObject the JSON object containing the JSON representation of the incoming event
+ * @param fieldName the field name to find in the event
+ * @return true if the field is present
+ * @throws ApexEventRuntimeException the apex event runtime exception
+ */
+ private boolean hasJSONField(final JsonObject jsonObject, final String fieldName) throws ApexEventRuntimeException {
+ // check for the field
+ return jsonObject.has(fieldName);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/JSONEventProtocolParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/JSONEventProtocolParameters.java
new file mode 100644
index 000000000..b4a4055d7
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/JSONEventProtocolParameters.java
@@ -0,0 +1,135 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.event.impl.jsonprotocolplugin;
+
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolTextCharDelimitedParameters;
+
+/**
+ * Event protocol parameters for JSON as an event protocol.
+ *
+ * The parameters for this plugin are:
+ * <ol>
+ * <li>nameAlias: The field in a JSON event to use as an alias for the event name. This parameter is
+ * optional.
+ * <li>versionAlias: The field in a JSON event to use as an alias for the event version. This
+ * parameter is optional.
+ * <li>nameSpaceAlias: The field in a JSON event to use as an alias for the event name space. This
+ * parameter is optional.
+ * <li>sourceAlias: The field in a JSON event to use as an alias for the event source. This
+ * parameter is optional.
+ * <li>targetAlias: The field in a JSON event to use as an alias for the event target. This
+ * parameter is optional.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class JSONEventProtocolParameters extends EventProtocolTextCharDelimitedParameters {
+ /** The label of this event protocol. */
+ public static final String JSON_EVENT_PROTOCOL_LABEL = "JSON";
+
+ // Constants for text block delimiters
+ private static final char JSON_TEXT_BLOCK_START_DELIMITER = '{';
+ private static final char JSON_TEXT_BLOCK_END_DELIMITER = '}';
+
+ // Aliases for Apex event header fields
+ // @formatter:off
+ private final String nameAlias = null;
+ private final String versionAlias = null;
+ private final String nameSpaceAlias = null;
+ private final String sourceAlias = null;
+ private final String targetAlias = null;
+ // @formatter:on
+
+ /**
+ * Constructor to create a JSON event protocol parameter instance and register the instance with
+ * the parameter service.
+ */
+ public JSONEventProtocolParameters() {
+ this(JSONEventProtocolParameters.class.getCanonicalName(), JSON_EVENT_PROTOCOL_LABEL);
+ }
+
+ /**
+ * Constructor to create an event protocol parameters instance with the name of a sub class of
+ * this class.
+ *
+ * @param parameterClassName the class name of a sub class of this class
+ * @param eventProtocolLabel the name of the event protocol for this plugin
+ */
+ public JSONEventProtocolParameters(final String parameterClassName, final String eventProtocolLabel) {
+ super(parameterClassName);
+
+ // Set the event protocol properties for the JSON event protocol
+ this.setLabel(eventProtocolLabel);
+
+ // Set the starting and ending delimiters for text blocks of JSON events
+ this.setStartChar(JSON_TEXT_BLOCK_START_DELIMITER);
+ this.setEndChar(JSON_TEXT_BLOCK_END_DELIMITER);
+
+ // Set the event protocol plugin class
+ this.setEventProtocolPluginClass(Apex2JSONEventConverter.class.getCanonicalName());
+ }
+
+ /**
+ * Gets the name alias.
+ *
+ * @return the name alias
+ */
+ public String getNameAlias() {
+ return nameAlias;
+ }
+
+ /**
+ * Gets the version alias.
+ *
+ * @return the version alias
+ */
+ public String getVersionAlias() {
+ return versionAlias;
+ }
+
+ /**
+ * Gets the name space alias.
+ *
+ * @return the name space alias
+ */
+ public String getNameSpaceAlias() {
+ return nameSpaceAlias;
+ }
+
+ /**
+ * Gets the source alias.
+ *
+ * @return the source alias
+ */
+ public String getSourceAlias() {
+ return sourceAlias;
+ }
+
+ /**
+ * Gets the target alias.
+ *
+ * @return the target alias
+ */
+ public String getTargetAlias() {
+ return targetAlias;
+ }
+
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/package-info.java
new file mode 100644
index 000000000..65f4831ec
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/jsonprotocolplugin/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains the implementation of the APEX event protocol cinverter plugin for events in Json
+ * format.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl.jsonprotocolplugin;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/package-info.java
new file mode 100644
index 000000000..ae2d58701
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/impl/package-info.java
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Contains implementations for conversion between externally facing
+ * {@link org.onap.policy.apex.service.engine.event.ApexEvent} instances and internal APEX engine
+ * {@link org.onap.policy.apex.core.engine.event.EnEvent} instances. It also contains the
+ * implementation of the default APEX File carrier technology plugin as well as the protocol plugins
+ * for XML and JSON event protocols.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event.impl;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/package-info.java
new file mode 100644
index 000000000..75404137e
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/event/package-info.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides a generic externally-facing {@link ApexEvent} class that can be sent into an APEX engine
+ * and processed by an APEX engine. It provides the producer {@link ApexEventProducer} producer and
+ * {@link ApexEventConsumer} consumer interfaces that APEX uses to send events to and receive events
+ * from other systems. It also provides the {@link ApexEventConverter} interface that can be
+ * implemented by plugins that wish to convert some external event format into the APEX event
+ * format. It also provides a periodic event generator that can be used to send periodic events into
+ * an APEX engine for triggering of policies to carry out housekeeping tasks.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.event;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivator.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivator.java
new file mode 100644
index 000000000..20af31496
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivator.java
@@ -0,0 +1,193 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.utilities.TextFileUtils;
+import org.onap.policy.apex.service.engine.engdep.EngDepMessagingService;
+import org.onap.policy.apex.service.engine.runtime.EngineService;
+import org.onap.policy.apex.service.engine.runtime.impl.EngineServiceImpl;
+import org.onap.policy.apex.service.parameters.ApexParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class wraps an Apex engine so that it can be activated as a complete service together with
+ * all its context, executor, and event plugins.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexActivator {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexActivator.class);
+
+ // The parameters of this Apex activator
+ private final ApexParameters apexParameters;
+
+ // Event unmarshalers are used to receive events asynchronously into Apex
+ private final Map<String, ApexEventUnmarshaller> unmarshallerMap = new LinkedHashMap<>();
+
+ // Event marshalers are used to send events asynchronously from Apex
+ private final Map<String, ApexEventMarshaller> marshallerMap = new LinkedHashMap<>();
+
+ // The engine service handler holds the references to the engine and its EngDep deployment
+ // interface. It also acts as a receiver for asynchronous
+ // and synchronous events from the engine.
+ private ApexEngineServiceHandler engineServiceHandler = null;
+
+ /**
+ * Instantiate the activator for the Apex engine as a complete service.
+ *
+ * @param parameters the apex parameters for the Apex service
+ */
+ public ApexActivator(final ApexParameters parameters) {
+ apexParameters = parameters;
+ }
+
+ /**
+ * Initialize the Apex engine as a complete service.
+ *
+ * @throws ApexActivatorException on errors in initializing the engine
+ */
+ public void initialize() throws ApexActivatorException {
+ LOGGER.debug("Apex engine starting as a service . . .");
+
+ try {
+ // Create engine with specified thread count
+ LOGGER.debug("starting apex engine service . . .");
+ final EngineService apexEngineService =
+ EngineServiceImpl.create(apexParameters.getEngineServiceParameters());
+
+ // Instantiate and start the messaging service for Deployment
+ LOGGER.debug("starting apex deployment service . . .");
+ final EngDepMessagingService engDepService = new EngDepMessagingService(apexEngineService,
+ apexParameters.getEngineServiceParameters().getDeploymentPort());
+ engDepService.start();
+
+ // Create the engine holder to hold the engine's references and act as an event receiver
+ engineServiceHandler = new ApexEngineServiceHandler(apexEngineService, engDepService);
+
+ // Check if a policy model file has been specified
+ if (apexParameters.getEngineServiceParameters().getPolicyModelFileName() != null) {
+ LOGGER.debug("deploying policy model in \""
+ + apexParameters.getEngineServiceParameters().getPolicyModelFileName()
+ + "\" to the apex engines . . .");
+
+ // Set the policy model in the engine
+ final String policyModelString = TextFileUtils
+ .getTextFileAsString(apexParameters.getEngineServiceParameters().getPolicyModelFileName());
+ apexEngineService.updateModel(apexParameters.getEngineServiceParameters().getEngineKey(),
+ policyModelString, true);
+ apexEngineService.startAll();
+ }
+
+ // Producer parameters specify what event marshalers to handle events leaving Apex are
+ // set up and how they are set up
+ for (final Entry<String, EventHandlerParameters> outputParameters : apexParameters
+ .getEventOutputParameters().entrySet()) {
+ final ApexEventMarshaller marshaller = new ApexEventMarshaller(outputParameters.getKey(),
+ apexParameters.getEngineServiceParameters(), outputParameters.getValue());
+ marshaller.init();
+ apexEngineService.registerActionListener(outputParameters.getKey(), marshaller);
+ marshallerMap.put(outputParameters.getKey(), marshaller);
+ }
+
+ // Consumer parameters specify what event unmarshalers to handle events coming into Apex
+ // are set up and how they are set up
+ for (final Entry<String, EventHandlerParameters> inputParameters : apexParameters.getEventInputParameters()
+ .entrySet()) {
+ final ApexEventUnmarshaller unmarshaller = new ApexEventUnmarshaller(inputParameters.getKey(),
+ apexParameters.getEngineServiceParameters(), inputParameters.getValue());
+ unmarshallerMap.put(inputParameters.getKey(), unmarshaller);
+ unmarshaller.init(engineServiceHandler);
+ }
+
+ // Set up unmarshaler/marshaler pairing for synchronized event handling. We only need to
+ // traverse the unmarshalers because the
+ // unmarshalers and marshalers are paired one to one uniquely so if we find a
+ // synchronized unmarshaler we'll also find its
+ // paired marshaler
+ for (final Entry<String, EventHandlerParameters> inputParameters : apexParameters.getEventInputParameters()
+ .entrySet()) {
+ final ApexEventUnmarshaller unmarshaller = unmarshallerMap.get(inputParameters.getKey());
+
+ // Pair up peered unmarshalers and marshalers
+ for (final EventHandlerPeeredMode peeredMode : EventHandlerPeeredMode.values()) {
+ // Check if the unmarshaler is synchronized with a marshaler
+ if (inputParameters.getValue().isPeeredMode(peeredMode)) {
+ // Find the unmarshaler and marshaler
+ final ApexEventMarshaller peeredMarshaler =
+ marshallerMap.get(inputParameters.getValue().getPeer(peeredMode));
+
+ // Connect the unmarshaler and marshaler
+ unmarshaller.connectMarshaler(peeredMode, peeredMarshaler);
+ }
+ }
+ // Now let's get events flowing
+ unmarshaller.start();
+ }
+ } catch (final Exception e) {
+ LOGGER.debug("Apex engine failed to start as a service", e);
+ throw new ApexActivatorException("Apex engine failed to start as a service", e);
+ }
+
+ LOGGER.debug("Apex engine started as a service");
+ }
+
+ /**
+ * Terminate the Apex engine.
+ *
+ * @throws ApexException on termination errors
+ */
+ public void terminate() throws ApexException {
+ // Shut down all marshalers and unmarshalers
+ for (final ApexEventMarshaller marshaller : marshallerMap.values()) {
+ marshaller.stop();
+ }
+ marshallerMap.clear();
+
+ for (final ApexEventUnmarshaller unmarshaller : unmarshallerMap.values()) {
+ unmarshaller.stop();
+ }
+ unmarshallerMap.clear();
+
+ // Check if the engine service handler has been shut down already
+ if (engineServiceHandler != null) {
+ engineServiceHandler.terminate();
+ engineServiceHandler = null;
+ }
+ }
+
+ /**
+ * Get the parameters used by the adapter.
+ *
+ * @return the parameters of the adapter
+ */
+ public ApexParameters getApexParameters() {
+ return apexParameters;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorException.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorException.java
new file mode 100644
index 000000000..371a3a882
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorException.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+
+/**
+ * This exception will be called if an error occurs when running Apex as a complete service.
+ *
+ * @author Liam Fallon
+ */
+public class ApexActivatorException extends ApexException {
+ private static final long serialVersionUID = -8507246953751956974L;
+
+ /**
+ * Instantiates a new apex activator exception with a message.
+ *
+ * @param message the message
+ */
+ public ApexActivatorException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex activator exception with a message and a caused by exception.
+ *
+ * @param message the message
+ * @param e the exception that caused this exception to be thrown
+ */
+ public ApexActivatorException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorRuntimeException.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorRuntimeException.java
new file mode 100644
index 000000000..cf1842dbe
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexActivatorRuntimeException.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexRuntimeException;
+
+/**
+ * This runtime exception will be called if a runtime error occurs when running Apex as a complete
+ * service.
+ *
+ * @author Liam Fallon
+ */
+public class ApexActivatorRuntimeException extends ApexRuntimeException {
+ private static final long serialVersionUID = -8507246953751956974L;
+
+ /**
+ * Instantiates a new apex activator exception with a message.
+ *
+ * @param message the message
+ */
+ public ApexActivatorRuntimeException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex activator exception with a message and a caused by exception.
+ *
+ * @param message the message
+ * @param e the exception that caused this exception to be thrown
+ */
+ public ApexActivatorRuntimeException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexCommandLineArguments.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexCommandLineArguments.java
new file mode 100644
index 000000000..02dc248b4
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexCommandLineArguments.java
@@ -0,0 +1,285 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Arrays;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexRuntimeException;
+import org.onap.policy.apex.model.utilities.ResourceUtils;
+
+/**
+ * This class reads and handles command line parameters for the Apex main program.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexCommandLineArguments {
+ private static final int HELP_LINE_LENGTH = 120;
+
+ // Apache Commons CLI options
+ private final Options options;
+
+ // The command line options
+ private String modelFilePath = null;
+ private String configurationFilePath = null;
+
+ /**
+ * Construct the options for the CLI editor.
+ */
+ public ApexCommandLineArguments() {
+ //@formatter:off
+ options = new Options();
+ options.addOption(Option.builder("h")
+ .longOpt("help")
+ .desc("outputs the usage of this command")
+ .required(false)
+ .type(Boolean.class)
+ .build());
+ options.addOption(Option.builder("v")
+ .longOpt("version")
+ .desc("outputs the version of Apex")
+ .required(false)
+ .type(Boolean.class)
+ .build());
+ options.addOption(Option.builder("c")
+ .longOpt("config-file")
+ .desc("the full path to the configuration file to use, the configuration file must be a Json file containing the Apex configuration parameters")
+ .hasArg()
+ .argName("CONFIG_FILE")
+ .required(false)
+ .type(String.class)
+ .build());
+ options.addOption(Option.builder("m").longOpt("model-file")
+ .desc("the full path to the model file to use, if set it overrides the model file set in the configuration file").hasArg().argName("MODEL_FILE")
+ .required(false)
+ .type(String.class).build());
+ //@formatter:on
+ }
+
+ /**
+ * Construct the options for the CLI editor and parse in the given arguments.
+ *
+ * @param args The command line arguments
+ */
+ public ApexCommandLineArguments(final String[] args) {
+ // Set up the options with the default constructor
+ this();
+
+ // Parse the arguments
+ try {
+ parse(args);
+ } catch (final ApexException e) {
+ throw new ApexRuntimeException("parse error on Apex parameters");
+ }
+ }
+
+ /**
+ * Parse the command line options.
+ *
+ * @param args The command line arguments
+ * @return a string with a message for help and version, or null if there is no message
+ * @throws ApexException on command argument errors
+ */
+ public String parse(final String[] args) throws ApexException {
+ // Clear all our arguments
+ setConfigurationFilePath(null);
+ setModelFilePath(null);
+
+ CommandLine commandLine = null;
+ try {
+ commandLine = new DefaultParser().parse(options, args);
+ } catch (final ParseException e) {
+ throw new ApexException("invalid command line arguments specified : " + e.getMessage());
+ }
+
+ // Arguments left over after Commons CLI does its stuff
+ final String[] remainingArgs = commandLine.getArgs();
+
+ if (remainingArgs.length > 0 && commandLine.hasOption('c') || remainingArgs.length > 1) {
+ throw new ApexException("too many command line arguments specified : " + Arrays.toString(args));
+ }
+
+ if (remainingArgs.length == 1) {
+ configurationFilePath = remainingArgs[0];
+ }
+
+ if (commandLine.hasOption('h')) {
+ return help(ApexMain.class.getCanonicalName());
+ }
+
+ if (commandLine.hasOption('v')) {
+ return version();
+ }
+
+ if (commandLine.hasOption('c')) {
+ setConfigurationFilePath(commandLine.getOptionValue('c'));
+ }
+
+ if (commandLine.hasOption('m')) {
+ setModelFilePath(commandLine.getOptionValue('m'));
+ }
+
+ return null;
+ }
+
+ /**
+ * Validate the command line options.
+ *
+ * @throws ApexException on command argument validation errors
+ */
+ public void validate() throws ApexException {
+ validateReadableFile("Apex configuration", configurationFilePath);
+
+ if (checkSetModelFilePath()) {
+ validateReadableFile("Apex model", modelFilePath);
+ }
+ }
+
+ /**
+ * Print version information for Apex.
+ *
+ * @return the version string
+ */
+ public String version() {
+ return ResourceUtils.getResourceAsString("version.txt");
+ }
+
+ /**
+ * Print help information for Apex.
+ *
+ * @param mainClassName the main class name
+ * @return the help string
+ */
+ public String help(final String mainClassName) {
+ final HelpFormatter helpFormatter = new HelpFormatter();
+ final StringWriter stringWriter = new StringWriter();
+ final PrintWriter stringPW = new PrintWriter(stringWriter);
+
+ helpFormatter.printHelp(stringPW, HELP_LINE_LENGTH, mainClassName + " [options...]", "options", options, 0, 0,
+ "");
+
+ return stringWriter.toString();
+ }
+
+ /**
+ * Gets the model file path.
+ *
+ * @return the model file path
+ */
+ public String getModelFilePath() {
+ return ResourceUtils.getFilePath4Resource(modelFilePath);
+ }
+
+ /**
+ * Sets the model file path.
+ *
+ * @param modelFilePath the model file path
+ */
+ public void setModelFilePath(final String modelFilePath) {
+ this.modelFilePath = modelFilePath;
+ }
+
+ /**
+ * Check set model file path.
+ *
+ * @return true, if check set model file path
+ */
+ public boolean checkSetModelFilePath() {
+ return modelFilePath != null && modelFilePath.length() > 0;
+ }
+
+ /**
+ * Gets the configuration file path.
+ *
+ * @return the configuration file path
+ */
+ public String getConfigurationFilePath() {
+ return configurationFilePath;
+ }
+
+ /**
+ * Gets the full expanded configuration file path.
+ *
+ * @return the configuration file path
+ */
+ public String getFullConfigurationFilePath() {
+ return ResourceUtils.getFilePath4Resource(getConfigurationFilePath());
+ }
+
+ /**
+ * Sets the configuration file path.
+ *
+ * @param configurationFilePath the configuration file path
+ */
+ public void setConfigurationFilePath(final String configurationFilePath) {
+ this.configurationFilePath = configurationFilePath;
+
+ }
+
+ /**
+ * Check set configuration file path.
+ *
+ * @return true, if check set configuration file path
+ */
+ public boolean checkSetConfigurationFilePath() {
+ return configurationFilePath != null && configurationFilePath.length() > 0;
+ }
+
+ /**
+ * Validate readable file.
+ *
+ * @param fileTag the file tag
+ * @param fileName the file name
+ * @throws ApexException the apex exception
+ */
+ private void validateReadableFile(final String fileTag, final String fileName) throws ApexException {
+ if (fileName == null || fileName.length() == 0) {
+ throw new ApexException(fileTag + " file was not specified as an argument");
+ }
+
+ // The file name can refer to a resource on the local file system or on the class path
+ final URL fileURL = ResourceUtils.getURL4Resource(fileName);
+ if (fileURL == null) {
+ throw new ApexException(fileTag + " file \"" + fileName + "\" does not exist");
+ }
+
+ final File theFile = new File(fileURL.getPath());
+ if (!theFile.exists()) {
+ throw new ApexException(fileTag + " file \"" + fileName + "\" does not exist");
+ }
+ if (!theFile.isFile()) {
+ throw new ApexException(fileTag + " file \"" + fileName + "\" is not a normal file");
+ }
+ if (!theFile.canRead()) {
+ throw new ApexException(fileTag + " file \"" + fileName + "\" is ureadable");
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEngineServiceHandler.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEngineServiceHandler.java
new file mode 100644
index 000000000..ad7af9449
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEngineServiceHandler.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.service.engine.engdep.EngDepMessagingService;
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.runtime.EngineService;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The Class ApexEngineServiceHandler holds the reference to the Apex engine service and the EngDep
+ * service for that engine. It also acts as an event receiver for asynchronous and synchronous
+ * events.
+ */
+public class ApexEngineServiceHandler {
+ // The logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexEngineServiceHandler.class);
+
+ // The Apex engine service, the Apex engine itself
+ private final EngineService apexEngineService;
+
+ // The interface between the Apex engine and Apex policy deployment for the Apex engine
+ private final EngDepMessagingService engDepService;
+
+ /**
+ * Instantiates a new engine holder with its engine service and EngDep service.
+ *
+ * @param apexEngineService the apex engine service
+ * @param engDepService the EngDep service
+ */
+ ApexEngineServiceHandler(final EngineService apexEngineService, final EngDepMessagingService engDepService) {
+ this.apexEngineService = apexEngineService;
+ this.engDepService = engDepService;
+ }
+
+ /**
+ * This method forwards an event to the Apex service.
+ *
+ * @param apexEvent The event to forward to Apex
+ */
+ public void forwardEvent(final ApexEvent apexEvent) {
+ try {
+ // Send the event to the engine runtime
+ apexEngineService.getEngineServiceEventInterface().sendEvent(apexEvent);
+ } catch (final Exception e) {
+ final String errorMessage = "error transferring event \"" + apexEvent.getName() + "\" to the Apex engine";
+ LOGGER.debug(errorMessage, e);
+ throw new ApexActivatorRuntimeException(errorMessage, e);
+ }
+ }
+
+ /**
+ * Terminate the Apex engine.
+ *
+ * @throws ApexException on termination errors
+ */
+ public void terminate() throws ApexException {
+ // Shut down engine management
+ if (engDepService != null) {
+ engDepService.stop();
+ }
+
+ // Shut down each engine instance
+ if (apexEngineService != null) {
+ apexEngineService.stop();
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventMarshaller.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventMarshaller.java
new file mode 100644
index 000000000..b4ba2ac3e
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventMarshaller.java
@@ -0,0 +1,232 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventProducer;
+import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
+import org.onap.policy.apex.service.engine.event.impl.EventProducerFactory;
+import org.onap.policy.apex.service.engine.event.impl.EventProtocolFactory;
+import org.onap.policy.apex.service.engine.runtime.ApexEventListener;
+import org.onap.policy.apex.service.parameters.engineservice.EngineServiceParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This event marshaler handles events coming out of Apex and sends them on, handles threading,
+ * event queuing, transformations and sending using the configured sending technology.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexEventMarshaller implements ApexEventListener, Runnable {
+ // Get a reference to the logger
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexEventMarshaller.class);
+
+ // Interval to wait between thread shutdown checks
+ private static final int MARSHALLER_SHUTDOWN_WAIT_INTERVAL = 10;
+
+ // The amount of time to wait between polls of the event queue in milliseconds
+ private static final long EVENT_QUEUE_POLL_INTERVAL = 20;
+
+ // The name of the marshaler
+ private final String name;
+
+ // The engine service and producer parameters
+ private final EngineServiceParameters engineServiceParameters;
+ private final EventHandlerParameters producerParameters;
+
+ // Apex event producer and event converter, all conversions are to and from string
+ // representation of events
+ private ApexEventProducer producer;
+ private ApexEventProtocolConverter converter;
+
+ // Temporary event holder for events coming out of Apex
+ private final BlockingQueue<ApexEvent> queue = new LinkedBlockingQueue<>();
+
+ // The marshaler thread and stopping flag
+ private Thread marshallerThread;
+ private boolean stopOrderedFlag = false;
+
+ /**
+ * Create the marshaler.
+ *
+ * @param name the name of the marshaler
+ * @param engineServiceParameters the engine service parameters for this Apex engine
+ * @param producerParameters the producer parameters for this specific marshaler
+ */
+ public ApexEventMarshaller(final String name, final EngineServiceParameters engineServiceParameters,
+ final EventHandlerParameters producerParameters) {
+ this.name = name;
+ this.engineServiceParameters = engineServiceParameters;
+ this.producerParameters = producerParameters;
+ }
+
+ /**
+ * Configure the marshaler by setting up the producer and event converter and initialize the
+ * thread for event sending.
+ *
+ * @throws ApexActivatorException on errors initializing the producer
+ * @throws ApexEventException on errors initializing event handling
+ */
+ public void init() throws ApexActivatorException, ApexEventException {
+ // Create the producer for sending events and the converter for transforming events
+ producer = new EventProducerFactory().createProducer(name, producerParameters);
+
+ // Initialize the producer
+ producer.init(this.name, this.producerParameters);
+
+ // Create the converter for transforming events
+ converter = new EventProtocolFactory().createConverter(name, producerParameters.getEventProtocolParameters());
+
+ // Configure and start the event sending thread
+ final String threadName =
+ engineServiceParameters.getEngineKey().getName() + ':' + this.getClass().getName() + ':' + this.name;
+ marshallerThread = new ApplicationThreadFactory(threadName).newThread(this);
+ marshallerThread.setDaemon(true);
+ marshallerThread.start();
+ }
+
+ /**
+ * Gets the name of the marshaler.
+ *
+ * @return the marshaler name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the technology specific producer for this marshaler.
+ *
+ * @return the producer
+ */
+ public ApexEventProducer getProducer() {
+ return producer;
+ }
+
+ /**
+ * Gets the event protocol converter for this marshaler.
+ *
+ * @return the event protocol converter
+ */
+ public ApexEventProtocolConverter getConverter() {
+ return converter;
+ }
+
+ /**
+ * Callback method called on implementations of this interface when Apex emits an event.
+ *
+ * @param apexEvent the apex event emitted by Apex
+ */
+ @Override
+ public void onApexEvent(final ApexEvent apexEvent) {
+ // Check if we are filtering events on this marshaler, if so check the event name against
+ // the filter
+ if (producerParameters.isSetEventNameFilter()
+ && !apexEvent.getName().matches(producerParameters.getEventNameFilter())) {
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("onMessage(): event {} not processed, filtered out by filter", apexEvent,
+ producerParameters.getEventNameFilter());
+ }
+
+ // Ignore this event
+ return;
+ }
+
+ // Push the event onto the queue for handling
+ try {
+ queue.put(apexEvent);
+ } catch (final InterruptedException e) {
+ LOGGER.warn("Failed to queue the event: " + apexEvent, e);
+ }
+ }
+
+ /**
+ * Run a thread that runs forever (well until system termination anyway) and listens for
+ * outgoing events on the queue.
+ */
+ @Override
+ public void run() {
+ // Run until interrupted
+ while (marshallerThread.isAlive() && !stopOrderedFlag) {
+ try {
+ // Take the next event from the queue
+ final ApexEvent apexEvent = queue.poll(EVENT_QUEUE_POLL_INTERVAL, TimeUnit.MILLISECONDS);
+ if (apexEvent == null) {
+ continue;
+ }
+
+ // Process the next Apex event from the queue
+ final Object event = converter.fromApexEvent(apexEvent);
+
+ producer.sendEvent(apexEvent.getExecutionID(), apexEvent.getName(), event);
+
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("event sent : " + apexEvent.toString());
+ }
+ } catch (final InterruptedException e) {
+ LOGGER.debug("Thread interrupted, Reason {}", e.getMessage());
+ break;
+ } catch (final Exception e) {
+ LOGGER.warn("Error while forwarding events for " + marshallerThread.getName(), e);
+ continue;
+ }
+ }
+
+ // Stop event production if we are not synchronized,;in the synchronized case, the producer
+ // takes care of its own cleanup.
+ producer.stop();
+ }
+
+ /**
+ * Get the marshaler thread.
+ *
+ * @return the marshaler thread
+ */
+ public Thread getThread() {
+ return marshallerThread;
+ }
+
+ /**
+ * Stop the Apex event marshaller's event producer using its termination mechanism.
+ */
+ public void stop() {
+ LOGGER.entry("shutting down Apex event marshaller . . .");
+
+ // Order the stop
+ stopOrderedFlag = true;
+
+ // Wait for thread shutdown
+ while (marshallerThread.isAlive()) {
+ ThreadUtilities.sleep(MARSHALLER_SHUTDOWN_WAIT_INTERVAL);
+ }
+
+ LOGGER.exit("shut down Apex event marshaller");
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventUnmarshaller.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventUnmarshaller.java
new file mode 100644
index 000000000..a9385751e
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexEventUnmarshaller.java
@@ -0,0 +1,323 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.ApexEventConsumer;
+import org.onap.policy.apex.service.engine.event.ApexEventException;
+import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
+import org.onap.policy.apex.service.engine.event.ApexEventReceiver;
+import org.onap.policy.apex.service.engine.event.PeeredReference;
+import org.onap.policy.apex.service.engine.event.SynchronousEventCache;
+import org.onap.policy.apex.service.engine.event.impl.EventConsumerFactory;
+import org.onap.policy.apex.service.engine.event.impl.EventProtocolFactory;
+import org.onap.policy.apex.service.parameters.engineservice.EngineServiceParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This event unmarshaler handles events coming into Apex, handles threading, event queuing,
+ * transformation and receiving using the configured receiving technology.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexEventUnmarshaller implements ApexEventReceiver, Runnable {
+ // Get a reference to the logger
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexEventUnmarshaller.class);
+
+ // Interval to wait between thread shutdown checks
+ private static final int UNMARSHALLER_SHUTDOWN_WAIT_INTERVAL = 10;
+
+ // The amount of time to wait between polls of the event queue in milliseconds
+ private static final long EVENT_QUEUE_POLL_INTERVAL = 20;
+
+ // The name of the unmarshaler
+ private final String name;
+
+ // The engine service and consumer parameters
+ private final EngineServiceParameters engineServiceParameters;
+ private final EventHandlerParameters consumerParameters;
+
+ // The engine service handler to use for forwarding on of unmarshalled events
+ private ApexEngineServiceHandler engineServiceHandler;
+
+ // Apex event producer and event converter, all events are sent as string representations
+ private ApexEventConsumer consumer;
+ private ApexEventProtocolConverter converter;
+
+ // Temporary event holder for events going into Apex
+ private final BlockingQueue<ApexEvent> queue = new LinkedBlockingQueue<>();
+
+ // The unmarshaler thread and stopping flag
+ private Thread unmarshallerThread = null;
+ private boolean stopOrderedFlag = false;
+
+ /**
+ * Create the unmarshaler.
+ *
+ * @param name the name of the unmarshaler
+ * @param engineServiceParameters the engine service parameters for this Apex engine
+ * @param consumerParameters the consumer parameters for this specific unmarshaler
+ */
+ public ApexEventUnmarshaller(final String name, final EngineServiceParameters engineServiceParameters,
+ final EventHandlerParameters consumerParameters) {
+ this.name = name;
+ this.engineServiceParameters = engineServiceParameters;
+ this.consumerParameters = consumerParameters;
+ }
+
+ /**
+ * Configure the consumer and initialize the thread for event sending.
+ *
+ * @param incomingEngineServiceHandler the Apex engine service handler for passing events to
+ * Apex
+ * @throws ApexEventException on errors initializing event handling
+ */
+ public void init(final ApexEngineServiceHandler incomingEngineServiceHandler) throws ApexEventException {
+ this.engineServiceHandler = incomingEngineServiceHandler;
+
+ // Create the consumer for sending events and the converter for transforming events
+ consumer = new EventConsumerFactory().createConsumer(name, consumerParameters);
+ consumer.init(this.name, this.consumerParameters, this);
+
+ converter = new EventProtocolFactory().createConverter(name, consumerParameters.getEventProtocolParameters());
+ }
+
+ /**
+ * Start the unmarshaler and consumer threads.
+ */
+ public void start() {
+ // Start the consumer
+ consumer.start();
+
+ // Configure and start the event reception thread
+ final String threadName =
+ engineServiceParameters.getEngineKey().getName() + ":" + this.getClass().getName() + ":" + name;
+ unmarshallerThread = new ApplicationThreadFactory(threadName).newThread(this);
+ unmarshallerThread.setDaemon(true);
+ unmarshallerThread.start();
+ }
+
+ /**
+ * Gets the name of the unmarshaler.
+ *
+ * @return the unmarshaler name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the technology specific consumer for this unmarshaler.
+ *
+ * @return the consumer
+ */
+ public ApexEventConsumer getConsumer() {
+ return consumer;
+ }
+
+ /**
+ * Gets the event protocol converter for this unmarshaler.
+ *
+ * @return the event protocol converter
+ */
+ public ApexEventProtocolConverter getConverter() {
+ return converter;
+ }
+
+ /**
+ * Connect a synchronous unmarshaler with a synchronous marshaler.
+ *
+ * @param peeredMode the peered mode under which the unmarshaler and marshaler are connected
+ * @param peeredMarshaller the synchronous marshaler to connect with
+ */
+ public void connectMarshaler(final EventHandlerPeeredMode peeredMode, final ApexEventMarshaller peeredMarshaller) {
+ switch (peeredMode) {
+ case SYNCHRONOUS:
+ // To connect a synchronous unmarshaler and marshaler, we create a synchronous event
+ // cache on the consumer/producer pair
+ new SynchronousEventCache(peeredMode, consumer, peeredMarshaller.getProducer(),
+ consumerParameters.getPeerTimeout(EventHandlerPeeredMode.SYNCHRONOUS));
+ return;
+
+ case REQUESTOR:
+ new PeeredReference(peeredMode, consumer, peeredMarshaller.getProducer());
+ return;
+
+ default:
+ return;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.event.ApexEventReceiver#receiveEvent(java.lang.Object)
+ */
+ @Override
+ public void receiveEvent(final Object event) throws ApexEventException {
+ receiveEvent(0, event, true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.event.ApexEventReceiver#receiveEvent(long,
+ * java.lang.Object)
+ */
+ @Override
+ public void receiveEvent(final long executionId, final Object event) throws ApexEventException {
+ receiveEvent(executionId, event, false);
+ }
+
+ /**
+ * Receive an event from a consumer, convert its protocol and forward it to Apex.
+ *
+ * @param executionId the execution id the incoming execution ID
+ * @param event the event in its native format
+ * @param generateExecutionId if true, let Apex generate the execution ID, if false, use the
+ * incoming execution ID
+ * @throws ApexEventException on unmarshaling errors on events
+ */
+ private void receiveEvent(final long executionId, final Object event, final boolean generateExecutionId)
+ throws ApexEventException {
+ // Push the event onto the queue
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("onMessage(): event received: {}", event.toString());
+ }
+
+ // Convert the incoming events to Apex events
+ try {
+ final List<ApexEvent> apexEventList = converter.toApexEvent(consumerParameters.getEventName(), event);
+ for (final ApexEvent apexEvent : apexEventList) {
+ // Check if we are filtering events on this unmarshaler, if so check the event name
+ // against the filter
+ if (consumerParameters.isSetEventNameFilter()
+ && !apexEvent.getName().matches(consumerParameters.getEventNameFilter())) {
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("onMessage(): event {} not processed, filtered out by filter", apexEvent,
+ consumerParameters.getEventNameFilter());
+ }
+
+ // Ignore this event
+ continue;
+ }
+
+ if (!generateExecutionId) {
+ apexEvent.setExecutionID(executionId);
+ }
+
+ // Enqueue the event
+ queue.add(apexEvent);
+
+ // Cache synchronized events that are sent
+ if (consumerParameters.isPeeredMode(EventHandlerPeeredMode.SYNCHRONOUS)) {
+ final SynchronousEventCache synchronousEventCache =
+ (SynchronousEventCache) consumer.getPeeredReference(EventHandlerPeeredMode.SYNCHRONOUS);
+ synchronousEventCache.cacheSynchronizedEventToApex(apexEvent.getExecutionID(), apexEvent);
+ }
+ }
+ } catch (final ApexException e) {
+ final String errorMessage = "Error while converting event into an ApexEvent for " + name + ": "
+ + e.getMessage() + ", Event=" + event;
+ LOGGER.warn(errorMessage, e);
+ throw new ApexEventException(errorMessage, e);
+ }
+ }
+
+ /**
+ * Run a thread that runs forever (well until system termination anyway) and listens for
+ * incoming events on the queue.
+ */
+ @Override
+ public void run() {
+ // Run until interruption
+ while (unmarshallerThread.isAlive() && !stopOrderedFlag) {
+ try {
+ // Take the next event from the queue
+ final ApexEvent apexEvent = queue.poll(EVENT_QUEUE_POLL_INTERVAL, TimeUnit.MILLISECONDS);
+ if (apexEvent == null) {
+ continue;
+ }
+
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("event received {}", apexEvent.toString());
+ }
+
+ // Pass the event to the activator for forwarding to Apex
+ engineServiceHandler.forwardEvent(apexEvent);
+ } catch (final InterruptedException e) {
+ LOGGER.warn("BatchProcessor thread interrupted, Reason {}", e.getMessage());
+ break;
+ } catch (final Exception e) {
+ LOGGER.warn("Error while forwarding events for " + unmarshallerThread.getName(), e);
+ continue;
+ }
+ }
+
+ // Stop event production
+ consumer.stop();
+ }
+
+ /**
+ * Get the unmarshaler thread.
+ *
+ * @return the unmarshaler thread
+ */
+ public Thread getThread() {
+ return unmarshallerThread;
+ }
+
+ /**
+ * Stop the Apex event unmarshaller's event producer using its termination mechanism.
+ */
+ public void stop() {
+ LOGGER.entry("shutting down Apex event unmarshaller . . .");
+
+ // Order the stop
+ stopOrderedFlag = true;
+
+ // Order a stop on the synchronous cache if one exists
+ if (consumerParameters != null && consumerParameters.isPeeredMode(EventHandlerPeeredMode.SYNCHRONOUS)) {
+ if (consumer.getPeeredReference(EventHandlerPeeredMode.SYNCHRONOUS) != null) {
+ ((SynchronousEventCache) consumer.getPeeredReference(EventHandlerPeeredMode.SYNCHRONOUS)).stop();
+ }
+ }
+
+ // Wait for thread shutdown
+ while (unmarshallerThread != null && unmarshallerThread.isAlive()) {
+ ThreadUtilities.sleep(UNMARSHALLER_SHUTDOWN_WAIT_INTERVAL);
+ }
+
+ LOGGER.exit("shut down Apex event unmarshaller");
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexMain.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexMain.java
new file mode 100644
index 000000000..1b5603482
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/ApexMain.java
@@ -0,0 +1,169 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.main;
+
+import java.util.Arrays;
+import java.util.Map.Entry;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.service.parameters.ApexParameterHandler;
+import org.onap.policy.apex.service.parameters.ApexParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class initiates Apex as a complete service from the command line.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexMain {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexMain.class);
+
+ // The Apex Activator that activates the Apex engine
+ private ApexActivator activator;
+
+ // The parameters read in from JSON
+ private ApexParameters parameters;
+
+ /**
+ * Instantiates the Apex Apex service.
+ *
+ * @param args the commaind line arguments
+ */
+ public ApexMain(final String[] args) {
+ System.out.println("Starting Apex service with parameters " + Arrays.toString(args) + " . . .");
+ LOGGER.entry("Starting Apex service with parameters " + Arrays.toString(args) + " . . .");
+
+ // Check the arguments
+ final ApexCommandLineArguments arguments = new ApexCommandLineArguments();
+ try {
+ // The arguments return a string if there is a message to print and we should exit
+ final String argumentMessage = arguments.parse(args);
+ if (argumentMessage != null) {
+ LOGGER.info(argumentMessage);
+ System.out.println(argumentMessage);
+ return;
+ }
+
+ // Validate that the arguments are sane
+ arguments.validate();
+ } catch (final ApexException e) {
+ System.err.println("start of Apex service failed: " + e.getMessage());
+ LOGGER.error("start of Apex service failed", e);
+ System.err.println(arguments.help(ApexMain.class.getCanonicalName()));
+ return;
+ }
+
+ // Read the parameters
+ try {
+ parameters = new ApexParameterHandler().getParameters(arguments);
+ } catch (final Exception e) {
+ System.err.println("start of Apex service failed\n" + e.getMessage());
+ LOGGER.error("start of Apex service failed", e);
+ return;
+ }
+
+ // Set the name of the event handler parameters for producers and consumers
+ for (final Entry<String, EventHandlerParameters> ehParameterEntry : parameters.getEventOutputParameters()
+ .entrySet()) {
+ if (!ehParameterEntry.getValue().checkSetName()) {
+ ehParameterEntry.getValue().setName(ehParameterEntry.getKey());
+ }
+ }
+ for (final Entry<String, EventHandlerParameters> ehParameterEntry : parameters.getEventInputParameters()
+ .entrySet()) {
+ if (!ehParameterEntry.getValue().checkSetName()) {
+ ehParameterEntry.getValue().setName(ehParameterEntry.getKey());
+ }
+ }
+
+ // Now, create the activator for the Apex service
+ activator = new ApexActivator(parameters);
+
+ // Start the activator
+ try {
+ activator.initialize();
+ } catch (final ApexActivatorException e) {
+ System.err.println("start of Apex service failed, used parameters are " + Arrays.toString(args));
+ e.printStackTrace(System.err);
+ LOGGER.error("start of Apex service failed, used parameters are " + Arrays.toString(args), e);
+ return;
+ }
+
+ // Add a shutdown hook to shut everything down in an orderly manner
+ Runtime.getRuntime().addShutdownHook(new ApexMainShutdownHookClass());
+ LOGGER.exit("Started Apex");
+ System.out.println("Started Apex service");
+ }
+
+ /**
+ * Get the parameters specified in JSON.
+ *
+ * @return the parameters
+ */
+ public ApexParameters getParameters() {
+ return parameters;
+ }
+
+ /**
+ * Shut down Execution.
+ *
+ * @throws ApexException on shutdown errors
+ */
+ public void shutdown() throws ApexException {
+ if (activator != null) {
+ activator.terminate();
+ }
+ }
+
+ /**
+ * The Class ApexMainShutdownHookClass terminates the Apex engine for the Apex service when its
+ * run method is called.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+ private class ApexMainShutdownHookClass extends Thread {
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ try {
+ // Shutdown the Apex engine and wait for everything to stop
+ activator.terminate();
+ } catch (final ApexException e) {
+ LOGGER.warn("error occured during shut down of the Apex service", e);
+ }
+ }
+ }
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(final String[] args) {
+ new ApexMain(args);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/package-info.java
new file mode 100644
index 000000000..488d5ab19
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/main/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides the APEX as a complete service together with all its context, executor and event
+ * handling plugins. A main method to allow APEX execution from the command line is also provided.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.main;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/package-info.java
new file mode 100644
index 000000000..cdd6c5e16
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/package-info.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides Java APIs for Apex. APIs are provided to give access to the APEX engine runtime, to give
+ * access to APEX event handling, and to give access to the ApexEngDep protocol for engine
+ * management.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/ApexEventListener.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/ApexEventListener.java
new file mode 100644
index 000000000..a498bcff8
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/ApexEventListener.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.runtime;
+
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+
+/**
+ * The listener interface for receiving apexEvent events. The class that is interested in processing
+ * a apexEvent event implements this interface, and the object created with that class is registered
+ * with a component using the component's {@code addApexEventListener} method. When the apexEvent
+ * event occurs, that object's appropriate method is invoked.
+ *
+ * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com)
+ */
+public interface ApexEventListener {
+
+ /**
+ * Callback method called on implementations of this interface when APEX emits an event.
+ *
+ * @param apexEvent the apex event emitted by APEX
+ */
+ void onApexEvent(ApexEvent apexEvent);
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineService.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineService.java
new file mode 100644
index 000000000..e6fc332f2
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineService.java
@@ -0,0 +1,214 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.runtime;
+
+import java.util.Collection;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.enginemodel.concepts.AxEngineState;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+
+/**
+ * The administration interface for Apex engine users. Apex engine implementations expose this
+ * interface and external users use it to manage Apex engines.
+ *
+ * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com)
+ */
+public interface EngineService {
+ /**
+ * A method to attach a listener to the engine.
+ *
+ * @param listenerName a unique name for the listener
+ * @param listener is a callback interface to the engine.
+ */
+ void registerActionListener(String listenerName, ApexEventListener listener);
+
+ /**
+ * A method to detach a listener from the engine.
+ *
+ * @param listenerName the unique name of the listener to deregister
+ */
+ void deregisterActionListener(String listenerName);
+
+ /**
+ * This method gets the current runtime information for the running Apex engines.
+ *
+ * @return the engine service event interface
+ */
+ EngineServiceEventInterface getEngineServiceEventInterface();
+
+ /**
+ * Gets the key of the engine service or worker.
+ *
+ * @return the key
+ */
+ AxArtifactKey getKey();
+
+ /**
+ * This method gets the keys of the engines on the engine service.
+ *
+ * @return the engine keys
+ */
+ Collection<AxArtifactKey> getEngineKeys();
+
+ /**
+ * The the key of the Apex model the engine service is running on.
+ *
+ * @return the Apex model key
+ */
+ AxArtifactKey getApexModelKey();
+
+ /**
+ * This method updates the Apex model on Apex execution engines using a string representation of
+ * the model.
+ *
+ * @param engineServiceKey The key of the engine service on which to update the model
+ * @param apexModelString the apex model string
+ * @param forceFlag if true, model updates will be executed even on incompatible models
+ * (different model names) and versions (different model version)
+ * @throws ApexException on model update errors
+ */
+ void updateModel(AxArtifactKey engineServiceKey, String apexModelString, boolean forceFlag) throws ApexException;
+
+ /**
+ * This method updates the Apex model on Apex execution engines using a policy model as input.
+ *
+ * @param engineServiceKey The key of the engine service on which to update the model
+ * @param apexModel is a policy definition model
+ * @param forceFlag if true, model updates will be executed even on incompatible models
+ * (different model names) and versions (different model version)
+ * @throws ApexException on model update errors
+ */
+ void updateModel(AxArtifactKey engineServiceKey, AxPolicyModel apexModel, boolean forceFlag) throws ApexException;
+
+ /**
+ * This method returns the state of an engine service or engine.
+ *
+ * @return The engine service or engine state
+ */
+ AxEngineState getState();
+
+ /**
+ * This method starts all Apex engines in the engine service.
+ *
+ * @throws ApexException on start errors
+ */
+ void startAll() throws ApexException;
+
+ /**
+ * This method starts an Apex engine in the engine service.
+ *
+ * @param engineKey The key of the Apex engine to start
+ * @throws ApexException on start errors
+ */
+ void start(AxArtifactKey engineKey) throws ApexException;
+
+ /**
+ * This method stops all Apex engines in the engine service.
+ *
+ * @throws ApexException on stop errors
+ */
+ void stop() throws ApexException;
+
+ /**
+ * This method stops an Apex engine in the engine service.
+ *
+ * @param engineKey The key of the Apex engine to stop
+ * @throws ApexException on stop errors
+ */
+ void stop(AxArtifactKey engineKey) throws ApexException;
+
+ /**
+ * This method checks if all Apex engines in the engine service are started.
+ * <p>
+ * Note: an engine can be both not stopped and not started, for example, when it is starting or
+ * stopping
+ *
+ * @return true if all Apex engines in the engine service are started.
+ */
+ boolean isStarted();
+
+ /**
+ * This method checks if an Apex engine in the engine service is started.
+ * <p>
+ * Note: an engine can be both not stopped and not started, for example, when it is starting or
+ * stopping
+ *
+ * @param engineKey The key of the Apex engine to check
+ * @return true if all Apex engines in the engine service are started.
+ */
+ boolean isStarted(AxArtifactKey engineKey);
+
+ /**
+ * This method checks if all Apex engines in the engine service are stopped.
+ * <p>
+ * Note: an engine can be both not stopped and not started, for example, when it is starting or
+ * stopping
+ *
+ * @return true if all Apex engines in the engine service are stopped.
+ */
+ boolean isStopped();
+
+ /**
+ * This method checks if an Apex engine in the engine service is stopped.
+ * <p>
+ * Note: an engine can be both not stopped and not started, for example, when it is starting or
+ * stopping
+ *
+ * @param engineKey The key of the Apex engine to check
+ * @return true if all Apex engines in the engine service are stopped.
+ */
+ boolean isStopped(AxArtifactKey engineKey);
+
+ /**
+ * This method starts periodic event generation.
+ *
+ * @param period The period in milliseconds between periodic events
+ * @throws ApexException On periodic event start errors
+ */
+ void startPeriodicEvents(long period) throws ApexException;
+
+ /**
+ * This method stops periodic event generation.
+ *
+ * @throws ApexException On periodic event stop errors
+ */
+ void stopPeriodicEvents() throws ApexException;
+
+ /**
+ * This method gets the status of an Apex engine in the engine service.
+ *
+ * @param engineKey the engine key
+ * @return the engine runtime information
+ * @throws ApexException on status read errors
+ */
+ String getStatus(AxArtifactKey engineKey) throws ApexException;
+
+ /**
+ * This method gets the runtime information of all Apex engines in the engine service.
+ *
+ * @param engineKey the engine key
+ * @return the engine runtime information
+ * @throws ApexException on runtime information read errors
+ */
+ String getRuntimeInfo(AxArtifactKey engineKey) throws ApexException;
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineServiceEventInterface.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineServiceEventInterface.java
new file mode 100644
index 000000000..8e4cb82e2
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/EngineServiceEventInterface.java
@@ -0,0 +1,39 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.runtime;
+
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+
+/**
+ * The run time interface for APEX engine users. APEX engine implementations expose this interface
+ * and external users use it to send events to the engine.
+ *
+ * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com), John Keeney
+ * (john.keeney@ericsson.com)
+ */
+public interface EngineServiceEventInterface {
+ /**
+ * This method forwards an event to the APEX engine.
+ *
+ * @param event is an instance {@link ApexEvent}
+ */
+ void sendEvent(ApexEvent event);
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EnEventListenerImpl.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EnEventListenerImpl.java
new file mode 100644
index 000000000..abd6db2d9
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EnEventListenerImpl.java
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.runtime.impl;
+
+import org.onap.policy.apex.core.engine.engine.EnEventListener;
+import org.onap.policy.apex.core.engine.event.EnEvent;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.impl.enevent.ApexEvent2EnEventConverter;
+import org.onap.policy.apex.service.engine.runtime.ApexEventListener;
+
+/**
+ * The Class EnEventListenerImpl is used by the Apex engine implementation to listen for events
+ * coming from the core APEX engine. This listener converts the {@link EnEvent} instances into
+ * {@link ApexEvent} instances using an {@link ApexEvent2EnEventConverter} instance and forwards the
+ * events to an {@link ApexEventListener} instance for outputting to listening applications. The
+ * {@link ApexEventListener} is implemented in the external application communicating with Apex.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public final class EnEventListenerImpl implements EnEventListener {
+ // Listener for ApexEvents
+ private ApexEventListener apexEventListener = null;
+
+ // Converter for Engine events to Apex Events
+ private ApexEvent2EnEventConverter apexEnEventConverter = null;
+
+ /**
+ * Instantiates a new listener implementation.
+ *
+ * @param apexEventListener the apex event listener
+ * @param apexEnEventConverter the ApexEvent to enEvent converter
+ */
+ public EnEventListenerImpl(final ApexEventListener apexEventListener,
+ final ApexEvent2EnEventConverter apexEnEventConverter) {
+ this.apexEventListener = apexEventListener;
+ this.apexEnEventConverter = apexEnEventConverter;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.core.engine.engine.EnEventListener#onEnEvent(org.onap.policy.apex.core.
+ * engine.event.EnEvent)
+ */
+ @Override
+ public void onEnEvent(final EnEvent enEvent) throws ApexException {
+ for (final ApexEvent apexEvent : apexEnEventConverter.toApexEvent(enEvent.getName(), enEvent)) {
+ apexEventListener.onApexEvent(apexEvent);
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineServiceImpl.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineServiceImpl.java
new file mode 100644
index 000000000..24d8263f4
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineServiceImpl.java
@@ -0,0 +1,682 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.runtime.impl;
+
+import java.io.ByteArrayInputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.onap.policy.apex.context.ContextException;
+import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.handling.ApexModelException;
+import org.onap.policy.apex.model.basicmodel.handling.ApexModelReader;
+import org.onap.policy.apex.model.basicmodel.service.ModelService;
+import org.onap.policy.apex.model.enginemodel.concepts.AxEngineState;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.ApexPeriodicEventGenerator;
+import org.onap.policy.apex.service.engine.runtime.ApexEventListener;
+import org.onap.policy.apex.service.engine.runtime.EngineService;
+import org.onap.policy.apex.service.engine.runtime.EngineServiceEventInterface;
+import org.onap.policy.apex.service.parameters.engineservice.EngineServiceParameters;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The Class EngineServiceImpl controls a thread pool that runs a set of Apex engine workers, each
+ * of which is running on an identical Apex model. This class handles the management of the engine
+ * worker instances, their threads, and event forwarding to and from the engine workers.
+ *
+ * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com)
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ * @author John Keeney (john.keeney@ericsson.com)
+ */
+public final class EngineServiceImpl implements EngineService, EngineServiceEventInterface {
+ // Logging static variables
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EngineServiceImpl.class);
+ private static final boolean DEBUG_ENABLED = LOGGER.isDebugEnabled();
+
+ // Constants for timing
+ private static final long MAX_START_WAIT_TIME = 5000; // 5 seconds
+ private static final long MAX_STOP_WAIT_TIME = 5000; // 5 seconds
+ private static final int ENGINE_SERVICE_STOP_START_WAIT_INTERVAL = 200;
+
+ // The ID of this engine
+ private AxArtifactKey engineServiceKey = null;
+
+ // The Apex engine workers this engine service is handling
+ private final Map<AxArtifactKey, EngineService> engineWorkerMap =
+ Collections.synchronizedMap(new LinkedHashMap<AxArtifactKey, EngineService>());
+
+ // Event queue for events being sent into the Apex engines, it used by all engines within a
+ // group.
+ private final BlockingQueue<ApexEvent> queue = new LinkedBlockingQueue<>();
+
+ // Thread factory for thread management
+ private final ApplicationThreadFactory tFactory = new ApplicationThreadFactory("apex-engine-service", 512);
+
+ // Periodic event generator and its period in milliseconds
+ private ApexPeriodicEventGenerator periodicEventGenerator = null;
+ private long periodicEventPeriod;
+
+ /**
+ * This constructor instantiates engine workers and adds them to the set of engine workers to be
+ * managed. The constructor is private to prevent subclassing.
+ *
+ * @param engineServiceKey the engine service key
+ * @param incomingThreadCount the thread count, the number of engine workers to start
+ * @param periodicEventPeriod the period in milliseconds at which periodic events are generated
+ * @throws ApexException on worker instantiation errors
+ */
+ private EngineServiceImpl(final AxArtifactKey engineServiceKey, final int incomingThreadCount,
+ final long periodicEventPeriod) throws ApexException {
+ LOGGER.entry(engineServiceKey, incomingThreadCount);
+
+ this.engineServiceKey = engineServiceKey;
+ this.periodicEventPeriod = periodicEventPeriod;
+
+ int threadCount = incomingThreadCount;
+ if (threadCount <= 0) {
+ // Just start one engine worker
+ threadCount = 1;
+ }
+
+ // Start engine workers
+ for (int engineCounter = 0; engineCounter < threadCount; engineCounter++) {
+ final AxArtifactKey engineWorkerKey =
+ new AxArtifactKey(engineServiceKey.getName() + '-' + engineCounter, engineServiceKey.getVersion());
+ engineWorkerMap.put(engineWorkerKey, new EngineWorker(engineWorkerKey, queue, tFactory));
+ LOGGER.info("Created apex engine {} .", engineWorkerKey.getID());
+ }
+
+ LOGGER.info("APEX service created.");
+ LOGGER.exit();
+ }
+
+ /**
+ * Create an Apex Engine Service instance. This method is deprecated and will be removed in the
+ * next version.
+ *
+ * @param engineServiceKey the engine service key
+ * @param threadCount the thread count, the number of engine workers to start
+ * @return the Engine Service instance
+ * @throws ApexException on worker instantiation errors
+ * @deprecated Do not use this version. Use {@link #create(EngineServiceParameters)}
+ */
+ @Deprecated
+ public static EngineServiceImpl create(final AxArtifactKey engineServiceKey, final int threadCount)
+ throws ApexException {
+ // Check if the Apex model specified is sane
+ if (engineServiceKey == null) {
+ LOGGER.warn("engine service key is null");
+ throw new ApexException("engine service key is null");
+ }
+ return new EngineServiceImpl(engineServiceKey, threadCount, 0);
+ }
+
+ /**
+ * Create an Apex Engine Service instance. This method does not load the policy so
+ * {@link #updateModel(AxArtifactKey, AxPolicyModel, boolean)} or
+ * {@link #updateModel(AxArtifactKey, AxPolicyModel, boolean)} must be used to load a model.
+ * This method does not start the Engine Service so {@link #start(AxArtifactKey)} or
+ * {@link #startAll()} must be used.
+ *
+ * @param config the configuration for this Apex Engine Service.
+ * @return the Engine Service instance
+ * @throws ApexException on worker instantiation errors
+ */
+ public static EngineServiceImpl create(final EngineServiceParameters config) throws ApexException {
+ if (config == null) {
+ LOGGER.warn("Engine service configuration parameters is null");
+ throw new ApexException("engine service configuration parameters is null");
+ }
+ final String validation = config.validate();
+ if (validation != null && validation.length() > 0) {
+ LOGGER.warn("Invalid engine service configuration parameters: " + validation);
+ throw new ApexException("Invalid engine service configuration parameters: " + validation);
+ }
+ final AxArtifactKey engineServiceKey = config.getEngineKey();
+ final int threadCount = config.getInstanceCount();
+
+ // Check if the Apex model specified is sane
+ if (engineServiceKey == null) {
+ LOGGER.warn("engine service key is null");
+ throw new ApexException("engine service key is null");
+ }
+
+ return new EngineServiceImpl(engineServiceKey, threadCount, config.getPeriodicEventPeriod());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#registerActionListener(java.lang.
+ * String, com.ericsson.apex.service.engine.runtime.ApexEventListener)
+ */
+ @Override
+ public void registerActionListener(final String listenerName, final ApexEventListener apexEventListener) {
+ LOGGER.entry(apexEventListener);
+
+ // Register the Apex event listener on all engine workers, each worker will return Apex
+ // events to the listening application
+ for (final EngineService engineWorker : engineWorkerMap.values()) {
+ engineWorker.registerActionListener(listenerName, apexEventListener);
+ }
+
+ LOGGER.info("Added the action listener to the engine");
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#deregisterActionListener(java.lang.
+ * String)
+ */
+ @Override
+ public void deregisterActionListener(final String listenerName) {
+ LOGGER.entry(listenerName);
+
+ // Register the Apex event listener on all engine workers, each worker will return Apex
+ // events to the listening application
+ for (final EngineService engineWorker : engineWorkerMap.values()) {
+ engineWorker.deregisterActionListener(listenerName);
+ }
+
+ LOGGER.info("Removed the action listener from the engine");
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#getEngineServiceEventInterface()
+ */
+ @Override
+ public EngineServiceEventInterface getEngineServiceEventInterface() {
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#getKey()
+ */
+ @Override
+ public AxArtifactKey getKey() {
+ return engineServiceKey;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#getInfo()
+ */
+ @Override
+ public Collection<AxArtifactKey> getEngineKeys() {
+ return engineWorkerMap.keySet();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#getApexModelKey()
+ */
+ @Override
+ public AxArtifactKey getApexModelKey() {
+ if (engineWorkerMap.size() == 0) {
+ return null;
+ }
+
+ return engineWorkerMap.entrySet().iterator().next().getValue().getApexModelKey();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#updateModel(com.ericsson.apex.model.
+ * basicmodel.concepts.AxArtifactKey, java.lang.String, boolean)
+ */
+ @Override
+ public void updateModel(final AxArtifactKey incomingEngineServiceKey, final String apexModelString,
+ final boolean forceFlag) throws ApexException {
+ // Check if the Apex model specified is sane
+ if (apexModelString == null || apexModelString.trim().length() == 0) {
+ LOGGER.warn(
+ "model for updating on engine service with key " + incomingEngineServiceKey.getID() + " is empty");
+ throw new ApexException(
+ "model for updating on engine service with key " + incomingEngineServiceKey.getID() + " is empty");
+ }
+
+ // Read the Apex model into memory using the Apex Model Reader
+ AxPolicyModel apexPolicyModel = null;
+ try {
+ final ApexModelReader<AxPolicyModel> modelReader = new ApexModelReader<>(AxPolicyModel.class);
+ apexPolicyModel = modelReader.read(new ByteArrayInputStream(apexModelString.getBytes()));
+ } catch (final ApexModelException e) {
+ LOGGER.error("failed to unmarshal the apex model on engine service " + incomingEngineServiceKey.getID(), e);
+ throw new ApexException(
+ "failed to unmarshal the apex model on engine service " + incomingEngineServiceKey.getID(), e);
+ }
+
+ if (apexPolicyModel == null) {
+ LOGGER.error("apex model null on engine service " + incomingEngineServiceKey.getID());
+ throw new ApexException("apex model null on engine service " + incomingEngineServiceKey.getID());
+ }
+
+ // Update the model
+ updateModel(incomingEngineServiceKey, apexPolicyModel, forceFlag);
+
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#updateModel(com.ericsson.apex.model.
+ * basicmodel.concepts.AxArtifactKey,
+ * com.ericsson.apex.model.policymodel.concepts.AxPolicyModel, boolean)
+ */
+ @Override
+ public void updateModel(final AxArtifactKey incomingEngineServiceKey, final AxPolicyModel apexModel,
+ final boolean forceFlag) throws ApexException {
+ LOGGER.entry(incomingEngineServiceKey);
+
+ // Check if the Apex model specified is sane
+ if (apexModel == null) {
+ LOGGER.warn(
+ "model for updating on engine service with key " + incomingEngineServiceKey.getID() + " is null");
+ throw new ApexException(
+ "model for updating on engine service with key " + incomingEngineServiceKey.getID() + " is null");
+ }
+
+ // Check if the key on the update request is correct
+ if (!this.engineServiceKey.equals(incomingEngineServiceKey)) {
+ LOGGER.warn("engine service key " + incomingEngineServiceKey.getID() + " does not match the key"
+ + engineServiceKey.getID() + " of this engine service");
+ throw new ApexException("engine service key " + incomingEngineServiceKey.getID() + " does not match the key"
+ + engineServiceKey.getID() + " of this engine service");
+ }
+
+ // Check model compatibility
+ if (ModelService.existsModel(AxPolicyModel.class)) {
+ // The current policy model may or may not be defined
+ final AxPolicyModel currentModel = ModelService.getModel(AxPolicyModel.class);
+ if (!currentModel.getKey().isCompatible(apexModel.getKey())) {
+ if (forceFlag) {
+ LOGGER.warn("apex model update forced, supplied model with key \"" + apexModel.getKey().getID()
+ + "\" is not a compatible model update from the existing engine model with key \""
+ + currentModel.getKey().getID() + "\"");
+ } else {
+ throw new ContextException(
+ "apex model update failed, supplied model with key \"" + apexModel.getKey().getID()
+ + "\" is not a compatible model update from the existing engine model with key \""
+ + currentModel.getKey().getID() + "\"");
+ }
+ }
+ }
+
+ final boolean wasstopped = isStopped();
+
+ if (!wasstopped) {
+ // Stop all engines on this engine service
+ stop();
+ final long stoptime = System.currentTimeMillis();
+ while (!isStopped() && System.currentTimeMillis() - stoptime < MAX_STOP_WAIT_TIME) {
+ ThreadUtilities.sleep(ENGINE_SERVICE_STOP_START_WAIT_INTERVAL);
+ }
+ // Check if all engines are stopped
+ final StringBuilder notStoppedEngineIDBuilder = new StringBuilder();
+ for (final Entry<AxArtifactKey, EngineService> engineWorkerEntry : engineWorkerMap.entrySet()) {
+ if (engineWorkerEntry.getValue().getState() != AxEngineState.STOPPED) {
+ notStoppedEngineIDBuilder.append(engineWorkerEntry.getKey().getID());
+ notStoppedEngineIDBuilder.append('(');
+ notStoppedEngineIDBuilder.append(engineWorkerEntry.getValue().getState());
+ notStoppedEngineIDBuilder.append(") ");
+ }
+ }
+ if (notStoppedEngineIDBuilder.length() > 0) {
+ final String errorString = "cannot update model on engine service with key "
+ + incomingEngineServiceKey.getID() + ", engines not stopped after " + MAX_STOP_WAIT_TIME
+ + "ms are: " + notStoppedEngineIDBuilder.toString().trim();
+ LOGGER.warn(errorString);
+ throw new ApexException(errorString);
+ }
+ }
+
+ // Update the engines
+ for (final Entry<AxArtifactKey, EngineService> engineWorkerEntry : engineWorkerMap.entrySet()) {
+ LOGGER.info("Registering apex model on engine {}", engineWorkerEntry.getKey().getID());
+ engineWorkerEntry.getValue().updateModel(engineWorkerEntry.getKey(), apexModel, forceFlag);
+ }
+
+ if (!wasstopped) {
+ // start all engines on this engine service if it was not stopped before the update
+ startAll();
+ final long starttime = System.currentTimeMillis();
+ while (!isStarted() && System.currentTimeMillis() - starttime < MAX_START_WAIT_TIME) {
+ ThreadUtilities.sleep(ENGINE_SERVICE_STOP_START_WAIT_INTERVAL);
+ }
+ // Check if all engines are running
+ final StringBuilder notRunningEngineIDBuilder = new StringBuilder();
+ for (final Entry<AxArtifactKey, EngineService> engineWorkerEntry : engineWorkerMap.entrySet()) {
+ if (engineWorkerEntry.getValue().getState() != AxEngineState.READY
+ && engineWorkerEntry.getValue().getState() != AxEngineState.EXECUTING) {
+ notRunningEngineIDBuilder.append(engineWorkerEntry.getKey().getID());
+ notRunningEngineIDBuilder.append('(');
+ notRunningEngineIDBuilder.append(engineWorkerEntry.getValue().getState());
+ notRunningEngineIDBuilder.append(") ");
+ }
+ }
+ if (notRunningEngineIDBuilder.length() > 0) {
+ final String errorString = "engine start error on model update on engine service with key "
+ + incomingEngineServiceKey.getID() + ", engines not running are: "
+ + notRunningEngineIDBuilder.toString().trim();
+ LOGGER.warn(errorString);
+ throw new ApexException(errorString);
+ }
+ }
+
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#getState()
+ */
+ @Override
+ public AxEngineState getState() {
+ // If one worker is running then we are running, otherwise we are stopped
+ for (final EngineService engine : engineWorkerMap.values()) {
+ if (engine.getState() != AxEngineState.STOPPED) {
+ return AxEngineState.EXECUTING;
+ }
+ }
+
+ return AxEngineState.STOPPED;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#startAll()
+ */
+ @Override
+ public void startAll() throws ApexException {
+ for (final EngineService engine : engineWorkerMap.values()) {
+ start(engine.getKey());
+ }
+
+ // Check if periodic events should be turned on
+ if (periodicEventPeriod > 0) {
+ startPeriodicEvents(periodicEventPeriod);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#start(com.ericsson.apex.core.model.
+ * concepts.AxArtifactKey)
+ */
+ @Override
+ public void start(final AxArtifactKey engineKey) throws ApexException {
+ LOGGER.entry(engineKey);
+
+ // Check if we have this key on our map
+ if (!engineWorkerMap.containsKey(engineKey)) {
+ LOGGER.warn("engine with key " + engineKey.getID() + " not found in engine service");
+ throw new ApexException("engine with key " + engineKey.getID() + " not found in engine service");
+ }
+
+ // Start the engine
+ engineWorkerMap.get(engineKey).start(engineKey);
+
+ LOGGER.exit(engineKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#stop()
+ */
+ @Override
+ public void stop() throws ApexException {
+ LOGGER.entry();
+
+ // Stop each engine
+ for (final EngineService engine : engineWorkerMap.values()) {
+ if (engine.getState() != AxEngineState.STOPPED) {
+ engine.stop();
+ }
+ }
+
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#stop(com.ericsson.apex.core.model.
+ * concepts.AxArtifactKey)
+ */
+ @Override
+ public void stop(final AxArtifactKey engineKey) throws ApexException {
+ LOGGER.entry(engineKey);
+
+ // Check if we have this key on our map
+ if (!engineWorkerMap.containsKey(engineKey)) {
+ LOGGER.warn("engine with key " + engineKey.getID() + " not found in engine service");
+ throw new ApexException("engine with key " + engineKey.getID() + " not found in engine service");
+ }
+
+ // Stop the engine
+ engineWorkerMap.get(engineKey).stop(engineKey);
+
+ LOGGER.exit(engineKey);
+ }
+
+ /**
+ * Check all engines are started.
+ *
+ * @return true if <i>all</i> engines are started
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#isStarted()
+ */
+ @Override
+ public boolean isStarted() {
+ for (final EngineService engine : engineWorkerMap.values()) {
+ if (!engine.isStarted()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#isStarted(com.ericsson.apex.model.
+ * basicmodel.concepts.AxArtifactKey)
+ */
+ @Override
+ public boolean isStarted(final AxArtifactKey engineKey) {
+ // Check if we have this key on our map
+ if (!engineWorkerMap.containsKey(engineKey)) {
+ LOGGER.warn("engine with key " + engineKey.getID() + " not found in engine service");
+ }
+ return engineWorkerMap.get(engineKey).isStarted();
+ }
+
+ /**
+ * Check all engines are stopped.
+ *
+ * @return true if <i>all</i> engines are stopped
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#isStopped()
+ */
+ @Override
+ public boolean isStopped() {
+ for (final EngineService engine : engineWorkerMap.values()) {
+ if (!engine.isStopped()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#isStopped(com.ericsson.apex.model.
+ * basicmodel.concepts.AxArtifactKey)
+ */
+ @Override
+ public boolean isStopped(final AxArtifactKey engineKey) {
+ // Check if we have this key on our map
+ if (!engineWorkerMap.containsKey(engineKey)) {
+ LOGGER.warn("engine with key " + engineKey.getID() + " not found in engine service");
+ }
+ return engineWorkerMap.get(engineKey).isStopped();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#startPeriodicEvents(long)
+ */
+ @Override
+ public void startPeriodicEvents(final long period) throws ApexException {
+ // Check if periodic events are already started
+ if (periodicEventGenerator != null) {
+ LOGGER.warn("Peiodic event geneation already running on engine " + engineServiceKey.getID() + ", "
+ + periodicEventGenerator.toString());
+ throw new ApexException("Peiodic event geneation already running on engine " + engineServiceKey.getID()
+ + ", " + periodicEventGenerator.toString());
+ }
+
+ // Set up periodic event execution, its a Java Timer/TimerTask
+ periodicEventGenerator = new ApexPeriodicEventGenerator(this.getEngineServiceEventInterface(), period);
+
+ // Record the periodic event period because it may have been set over the Web Socket admin
+ // interface
+ this.periodicEventPeriod = period;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ericsson.apex.service.engine.runtime.EngineService#stopPeriodicEvents()
+ */
+ @Override
+ public void stopPeriodicEvents() throws ApexException {
+ // Check if periodic events are already started
+ if (periodicEventGenerator == null) {
+ LOGGER.warn("Peiodic event geneation not running on engine " + engineServiceKey.getID());
+ throw new ApexException("Peiodic event geneation not running on engine " + engineServiceKey.getID());
+ }
+
+ // Stop periodic events
+ periodicEventGenerator.cancel();
+ periodicEventGenerator = null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#getStatus(com.ericsson.apex.core.model
+ * .concepts.AxArtifactKey)
+ */
+ @Override
+ public String getStatus(final AxArtifactKey engineKey) throws ApexException {
+ // Check if we have this key on our map
+ if (!engineWorkerMap.containsKey(engineKey)) {
+ LOGGER.warn("engine with key " + engineKey.getID() + " not found in engine service");
+ throw new ApexException("engine with key " + engineKey.getID() + " not found in engine service");
+ }
+
+ // Return the information for this worker
+ return engineWorkerMap.get(engineKey).getStatus(engineKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineService#getRuntimeInfo(com.ericsson.apex.core.
+ * model.concepts.AxArtifactKey)
+ */
+ @Override
+ public String getRuntimeInfo(final AxArtifactKey engineKey) throws ApexException {
+ // Check if we have this key on our map
+ if (!engineWorkerMap.containsKey(engineKey)) {
+ LOGGER.warn("engine with key " + engineKey.getID() + " not found in engine service");
+ throw new ApexException("engine with key " + engineKey.getID() + " not found in engine service");
+ }
+
+ // Return the information for this worker
+ return engineWorkerMap.get(engineKey).getRuntimeInfo(engineKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.ericsson.apex.service.engine.runtime.EngineServiceEventInterface#sendEvent(com.ericsson.
+ * apex.service.engine.event.ApexEvent)
+ */
+ @Override
+ public void sendEvent(final ApexEvent event) {
+ // Check if we have this key on our map
+ if (getState() == AxEngineState.STOPPED) {
+ LOGGER.warn("event " + event.getName() + " not processed, no engines on engine service "
+ + engineServiceKey.getID() + " are running");
+ return;
+ }
+
+ if (event == null) {
+ LOGGER.warn("Null events cannot be processed, in engine service " + engineServiceKey.getID());
+ return;
+ }
+
+ if (DEBUG_ENABLED) {
+ LOGGER.debug("Forwarding Apex Event {} to the processing engine", event);
+ }
+
+ // Add the incoming event to the queue, the next available worker will process it
+ queue.add(event);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineWorker.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineWorker.java
new file mode 100644
index 000000000..20f8aaf75
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/EngineWorker.java
@@ -0,0 +1,674 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.engine.runtime.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+
+import org.onap.policy.apex.context.ContextException;
+import org.onap.policy.apex.context.ContextRuntimeException;
+import org.onap.policy.apex.context.SchemaHelper;
+import org.onap.policy.apex.context.impl.schema.SchemaHelperFactory;
+import org.onap.policy.apex.core.engine.engine.ApexEngine;
+import org.onap.policy.apex.core.engine.engine.impl.ApexEngineFactory;
+import org.onap.policy.apex.core.engine.event.EnEvent;
+import org.onap.policy.apex.core.infrastructure.threading.ApplicationThreadFactory;
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.handling.ApexModelException;
+import org.onap.policy.apex.model.basicmodel.handling.ApexModelReader;
+import org.onap.policy.apex.model.basicmodel.handling.ApexModelWriter;
+import org.onap.policy.apex.model.basicmodel.service.ModelService;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbums;
+import org.onap.policy.apex.model.enginemodel.concepts.AxEngineModel;
+import org.onap.policy.apex.model.enginemodel.concepts.AxEngineState;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.onap.policy.apex.service.engine.event.ApexEvent;
+import org.onap.policy.apex.service.engine.event.impl.enevent.ApexEvent2EnEventConverter;
+import org.onap.policy.apex.service.engine.runtime.ApexEventListener;
+import org.onap.policy.apex.service.engine.runtime.EngineService;
+import org.onap.policy.apex.service.engine.runtime.EngineServiceEventInterface;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+/**
+ * The Class EngineWorker encapsulates a core {@link ApexEngine} instance, which runs policies
+ * defined in the {@link org.onap.policy.apex.model.basicmodel.concepts.AxModelAxModel}. Each policy
+ * is triggered by an Apex event, and when the policy is triggered it runs through to completion in
+ * the ApexEngine.
+ *
+ * This class acts as a container for an {@link ApexEngine}, running it in a thread, sending it
+ * events, and receiving events from it.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+final class EngineWorker implements EngineService {
+ // Logger for this class
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EngineService.class);
+
+ // The ID of this engine
+ private final AxArtifactKey engineWorkerKey;
+
+ // The Apex engine which is running the policies in this worker
+ private final ApexEngine engine;
+
+ // The event processor is an inner class, an instance of which runs as a thread that reads
+ // incoming events from a queue and forwards them to the Apex engine
+ private EventProcessor processor = null;
+
+ // Thread handling for the worker
+ private final ApplicationThreadFactory threadFactory;
+ private Thread processorThread;
+
+ // Converts ApexEvent instances to and from EnEvent instances
+ private ApexEvent2EnEventConverter apexEnEventConverter = null;
+
+ /**
+ * Constructor that creates an Apex engine, an event processor for events to be sent to that
+ * engine, and an {@link ApexModelReader} instance to read Apex models using JAXB.
+ *
+ * @param engineWorkerKey the engine worker key
+ * @param queue the queue on which events for this Apex worker will come
+ * @param threadFactory the thread factory to use for creating the event processing thread
+ * @throws ApexException thrown on errors on worker instantiation
+ */
+ EngineWorker(final AxArtifactKey engineWorkerKey, final BlockingQueue<ApexEvent> queue,
+ final ApplicationThreadFactory threadFactory) throws ApexException {
+ LOGGER.entry(engineWorkerKey);
+
+ this.engineWorkerKey = engineWorkerKey;
+ this.threadFactory = threadFactory;
+
+ // Create the Apex engine
+ engine = new ApexEngineFactory().createApexEngine(engineWorkerKey);
+
+ // Create and run the event processor
+ processor = new EventProcessor(queue);
+
+ // Set the Event converter up
+ apexEnEventConverter = new ApexEvent2EnEventConverter(engine);
+
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#registerActionListener(java.lang.
+ * String, org.onap.policy.apex.service.engine.runtime.ApexEventListener)
+ */
+ @Override
+ public void registerActionListener(final String listenerName, final ApexEventListener apexEventListener) {
+ // Sanity checks on the Apex model
+ if (engine == null) {
+ LOGGER.warn("listener registration on engine with key " + engineWorkerKey.getID()
+ + ", failed, listener is null");
+ return;
+ }
+
+ engine.addEventListener(listenerName, new EnEventListenerImpl(apexEventListener, apexEnEventConverter));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#deregisterActionListener(java.lang.
+ * String)
+ */
+ @Override
+ public void deregisterActionListener(final String listenerName) {
+ // Sanity checks on the Apex model
+ if (engine == null) {
+ LOGGER.warn("listener deregistration on engine with key " + engineWorkerKey.getID()
+ + ", failed, listener is null");
+ return;
+ }
+
+ engine.removeEventListener(listenerName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#getEngineServiceEventInterface()
+ */
+ @Override
+ public EngineServiceEventInterface getEngineServiceEventInterface() {
+ throw new UnsupportedOperationException(
+ "getEngineServiceEventInterface() call is not allowed on an Apex Engine Worker");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#getKey()
+ */
+ @Override
+ public AxArtifactKey getKey() {
+ return engineWorkerKey;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#getInfo()
+ */
+ @Override
+ public Collection<AxArtifactKey> getEngineKeys() {
+ return Arrays.asList(engineWorkerKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#getApexModelKey()
+ */
+ @Override
+ public AxArtifactKey getApexModelKey() {
+ if (ModelService.existsModel(AxPolicyModel.class)) {
+ return ModelService.getModel(AxPolicyModel.class).getKey();
+ } else {
+ return null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#updateModel(org.onap.policy.apex.
+ * model. basicmodel.concepts.AxArtifactKey, java.lang.String, boolean)
+ */
+ @Override
+ public void updateModel(final AxArtifactKey engineKey, final String engineModel, final boolean forceFlag)
+ throws ApexException {
+ LOGGER.entry(engineKey);
+
+ // Read the Apex model into memory using the Apex Model Reader
+ AxPolicyModel apexPolicyModel = null;
+ try {
+ final ApexModelReader<AxPolicyModel> modelReader = new ApexModelReader<>(AxPolicyModel.class);
+ apexPolicyModel = modelReader.read(new ByteArrayInputStream(engineModel.getBytes()));
+ } catch (final ApexModelException e) {
+ LOGGER.error("failed to unmarshal the apex model on engine " + engineKey.getID(), e);
+ throw new ApexException("failed to unmarshal the apex model on engine " + engineKey.getID(), e);
+ }
+
+ if (apexPolicyModel == null) {
+ LOGGER.error("apex model null on engine " + engineKey.getID());
+ throw new ApexException("apex model null on engine " + engineKey.getID());
+ }
+
+ // Update the Apex model in the Apex engine
+ updateModel(engineKey, apexPolicyModel, forceFlag);
+
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#updateModel(org.onap.policy.apex.
+ * model. basicmodel.concepts.AxArtifactKey,
+ * org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel, boolean)
+ */
+ @Override
+ public void updateModel(final AxArtifactKey engineKey, final AxPolicyModel apexModel, final boolean forceFlag)
+ throws ApexException {
+ LOGGER.entry(engineKey);
+
+ // Check if the key on the update request is correct
+ if (!engineWorkerKey.equals(engineKey)) {
+ LOGGER.warn("engine key " + engineKey.getID() + " does not match the key" + engineWorkerKey.getID()
+ + " of this engine");
+ throw new ApexException("engine key " + engineKey.getID() + " does not match the key"
+ + engineWorkerKey.getID() + " of this engine");
+ }
+
+ // Sanity checks on the Apex model
+ if (engine == null) {
+ LOGGER.warn("engine with key " + engineKey.getID() + " not initialized");
+ throw new ApexException("engine with key " + engineKey.getID() + " not initialized");
+ }
+
+ // Check model compatibility
+ if (ModelService.existsModel(AxPolicyModel.class)) {
+ // The current policy model may or may not be defined
+ final AxPolicyModel currentModel = ModelService.getModel(AxPolicyModel.class);
+ if (!currentModel.getKey().isCompatible(apexModel.getKey())) {
+ if (forceFlag) {
+ LOGGER.warn("apex model update forced, supplied model with key \"" + apexModel.getKey().getID()
+ + "\" is not a compatible model update from the existing engine model with key \""
+ + currentModel.getKey().getID() + "\"");
+ } else {
+ throw new ContextException(
+ "apex model update failed, supplied model with key \"" + apexModel.getKey().getID()
+ + "\" is not a compatible model update from the existing engine model with key \""
+ + currentModel.getKey().getID() + "\"");
+ }
+ }
+ }
+
+ // Update the Apex model in the Apex engine
+ engine.updateModel(apexModel);
+
+ LOGGER.debug("engine model {} added to the engine-{}", apexModel.getKey().getID(), engineWorkerKey);
+ LOGGER.exit();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#getState()
+ */
+ @Override
+ public AxEngineState getState() {
+ return engine.getState();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#startAll()
+ */
+ @Override
+ public void startAll() throws ApexException {
+ start(this.getKey());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#start(org.onap.policy.apex.core.
+ * model. concepts.AxArtifactKey)
+ */
+ @Override
+ public void start(final AxArtifactKey engineKey) throws ApexException {
+ LOGGER.entry(engineKey);
+
+ // Check if the key on the start request is correct
+ if (!engineWorkerKey.equals(engineKey)) {
+ LOGGER.warn("engine key " + engineKey.getID() + " does not match the key" + engineWorkerKey.getID()
+ + " of this engine");
+ throw new ApexException("engine key " + engineKey.getID() + " does not match the key"
+ + engineWorkerKey.getID() + " of this engine");
+ }
+
+ if (engine == null) {
+ LOGGER.error("apex engine for engine key" + engineWorkerKey.getID() + " null");
+ throw new ApexException("apex engine for engine key" + engineWorkerKey.getID() + " null");
+ }
+
+ // Starts the event processing thread that handles incoming events
+ if (processorThread != null && processorThread.isAlive()) {
+ LOGGER.error("apex engine for engine key" + engineWorkerKey.getID() + " is already running with state "
+ + getState());
+ throw new ApexException("apex engine for engine key" + engineWorkerKey.getID()
+ + " is already running with state " + getState());
+ }
+
+ // Start the engine
+ engine.start();
+
+ // Start a thread to process events for the engine
+ processorThread = threadFactory.newThread(processor);
+ processorThread.start();
+
+ LOGGER.exit(engineKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#stop()
+ */
+ @Override
+ public void stop() throws ApexException {
+ stop(this.getKey());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#stop(org.onap.policy.apex.core.
+ * model. concepts.AxArtifactKey)
+ */
+ @Override
+ public void stop(final AxArtifactKey engineKey) throws ApexException {
+ // Check if the key on the start request is correct
+ if (!engineWorkerKey.equals(engineKey)) {
+ LOGGER.warn("engine key " + engineKey.getID() + " does not match the key" + engineWorkerKey.getID()
+ + " of this engine");
+ throw new ApexException("engine key " + engineKey.getID() + " does not match the key"
+ + engineWorkerKey.getID() + " of this engine");
+ }
+
+ if (engine == null) {
+ LOGGER.error("apex engine for engine key" + engineWorkerKey.getID() + " null");
+ throw new ApexException("apex engine for engine key" + engineWorkerKey.getID() + " null");
+ }
+
+ // Interrupt the worker to stop its thread
+ if (processorThread == null || !processorThread.isAlive()) {
+ processorThread = null;
+
+ LOGGER.warn("apex engine for engine key" + engineWorkerKey.getID() + " is already stopped with state "
+ + getState());
+ return;
+ }
+
+ // Interrupt the thread that is handling events toward the engine
+ processorThread.interrupt();
+
+ // Stop the engine
+ engine.stop();
+
+ LOGGER.exit(engineKey);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#isStarted()
+ */
+ @Override
+ public boolean isStarted() {
+ return isStarted(this.getKey());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#isStarted(org.onap.policy.apex.
+ * model. basicmodel.concepts.AxArtifactKey)
+ */
+ @Override
+ public boolean isStarted(final AxArtifactKey engineKey) {
+ final AxEngineState engstate = getState();
+ switch (engstate) {
+ case STOPPED:
+ case STOPPING:
+ case UNDEFINED:
+ return false;
+ case EXECUTING:
+ case READY:
+ return processorThread != null && processorThread.isAlive() && !processorThread.isInterrupted();
+ default:
+ break;
+ }
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#isStopped()
+ */
+ @Override
+ public boolean isStopped() {
+ return isStopped(this.getKey());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#isStopped(org.onap.policy.apex.
+ * model. basicmodel.concepts.AxArtifactKey)
+ */
+ @Override
+ public boolean isStopped(final AxArtifactKey engineKey) {
+ final AxEngineState engstate = getState();
+ switch (engstate) {
+ case STOPPING:
+ case UNDEFINED:
+ case EXECUTING:
+ case READY:
+ return false;
+ case STOPPED:
+ return processorThread == null || !processorThread.isAlive();
+ default:
+ break;
+ }
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#startPeriodicEvents(long)
+ */
+ @Override
+ public void startPeriodicEvents(final long period) {
+ throw new UnsupportedOperationException("startPeriodicEvents() call is not allowed on an Apex Engine Worker");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.engine.runtime.EngineService#stopPeriodicEvents()
+ */
+ @Override
+ public void stopPeriodicEvents() {
+ throw new UnsupportedOperationException("stopPeriodicEvents() call is not allowed on an Apex Engine Worker");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#getStatus(org.onap.policy.apex.core
+ * .model .concepts.AxArtifactKey)
+ */
+ @Override
+ public String getStatus(final AxArtifactKey engineKey) {
+ // Get the information from the engine that we want to return
+ final AxEngineModel apexEngineModel = engine.getEngineStatus();
+ apexEngineModel.getKeyInformation().generateKeyInfo(apexEngineModel);
+
+ // Convert that information into a string
+ try {
+ final ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
+ final ApexModelWriter<AxEngineModel> modelWriter = new ApexModelWriter<>(AxEngineModel.class);
+ modelWriter.write(apexEngineModel, baOutputStream);
+ return baOutputStream.toString();
+ } catch (final Exception e) {
+ LOGGER.warn("error outputting runtime information for engine {}", engineWorkerKey, e);
+ return null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.policy.apex.service.engine.runtime.EngineService#getRuntimeInfo(org.onap.policy.apex
+ * .core.model.concepts.AxArtifactKey)
+ */
+ @Override
+ public String getRuntimeInfo(final AxArtifactKey engineKey) {
+ // We'll build up the JSON string for runtime information bit by bit
+ final StringBuilder runtimeJsonStringBuilder = new StringBuilder();
+
+ // Get the engine information
+ final AxEngineModel engineModel = engine.getEngineStatus();
+ final Map<AxArtifactKey, Map<String, Object>> engineContextAlbums = engine.getEngineContext();
+
+ // Use GSON to convert our context information into JSON
+ final Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+ // Get context into a JSON string
+ runtimeJsonStringBuilder.append("{\"TimeStamp\":");
+ runtimeJsonStringBuilder.append(engineModel.getTimestamp());
+ runtimeJsonStringBuilder.append(",\"State\":");
+ runtimeJsonStringBuilder.append(engineModel.getState());
+ runtimeJsonStringBuilder.append(",\"Stats\":");
+ runtimeJsonStringBuilder.append(gson.toJson(engineModel.getStats()));
+
+ // Get context into a JSON string
+ runtimeJsonStringBuilder.append(",\"ContextAlbums\":[");
+
+ boolean firstAlbum = true;
+ for (final Entry<AxArtifactKey, Map<String, Object>> contextAlbumEntry : engineContextAlbums.entrySet()) {
+ if (firstAlbum) {
+ firstAlbum = false;
+ } else {
+ runtimeJsonStringBuilder.append(",");
+ }
+
+ runtimeJsonStringBuilder.append("{\"AlbumKey\":");
+ runtimeJsonStringBuilder.append(gson.toJson(contextAlbumEntry.getKey()));
+ runtimeJsonStringBuilder.append(",\"AlbumContent\":[");
+
+
+ // Get the schema helper to use to marshal context album objects to JSON
+ final AxContextAlbum axContextAlbum =
+ ModelService.getModel(AxContextAlbums.class).get(contextAlbumEntry.getKey());
+ SchemaHelper schemaHelper = null;
+
+ try {
+ // Get a schema helper to manage the translations between objects on the album map
+ // for this album
+ schemaHelper = new SchemaHelperFactory().createSchemaHelper(axContextAlbum.getKey(),
+ axContextAlbum.getItemSchema());
+ } catch (final ContextRuntimeException e) {
+ final String resultString =
+ "could not find schema helper to marshal context album \"" + axContextAlbum + "\" to JSON";
+ LOGGER.warn(resultString, e);
+
+ // End of context album entry
+ runtimeJsonStringBuilder.append(resultString);
+ runtimeJsonStringBuilder.append("]}");
+
+ continue;
+ }
+
+ boolean firstEntry = true;
+ for (final Entry<String, Object> contextEntry : contextAlbumEntry.getValue().entrySet()) {
+ if (firstEntry) {
+ firstEntry = false;
+ } else {
+ runtimeJsonStringBuilder.append(",");
+ }
+ runtimeJsonStringBuilder.append("{\"EntryName\":");
+ runtimeJsonStringBuilder.append(gson.toJson(contextEntry.getKey()));
+ runtimeJsonStringBuilder.append(",\"EntryContent\":");
+ runtimeJsonStringBuilder.append(gson.toJson(schemaHelper.marshal2Json(contextEntry.getValue())));
+
+ // End of context entry
+ runtimeJsonStringBuilder.append("}");
+ }
+
+ // End of context album entry
+ runtimeJsonStringBuilder.append("]}");
+ }
+
+ runtimeJsonStringBuilder.append("]}");
+
+ // Tidy up the JSON string
+ final JsonParser jsonParser = new JsonParser();
+ final JsonElement jsonElement = jsonParser.parse(runtimeJsonStringBuilder.toString());
+ final String tidiedRuntimeString = gson.toJson(jsonElement);
+
+ LOGGER.debug("runtime information=" + tidiedRuntimeString);
+
+ return tidiedRuntimeString;
+ }
+
+ /**
+ * This is an event processor thread, this class decouples the events handling logic from core
+ * business logic. This class runs its own thread and continuously querying the blocking queue
+ * for the events that have been sent to the worker for processing by the Apex engine.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+ private class EventProcessor implements Runnable {
+ private final boolean debugEnabled = LOGGER.isDebugEnabled();
+ // the events queue
+ private BlockingQueue<ApexEvent> eventProcessingQueue = null;
+
+ /**
+ * Constructor accepts {@link ApexEngine} and {@link BlockingQueue} type objects.
+ *
+ * @param eventProcessingQueue is reference of {@link BlockingQueue} which contains trigger
+ * events.
+ */
+ EventProcessor(final BlockingQueue<ApexEvent> eventProcessingQueue) {
+ this.eventProcessingQueue = eventProcessingQueue;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ LOGGER.debug("Engine {} processing ... ", engineWorkerKey);
+
+ // Take events from the event processing queue of the worker and pass them to the engine
+ // for processing
+ while (!processorThread.isInterrupted()) {
+ ApexEvent event = null;
+ try {
+ event = eventProcessingQueue.take();
+ } catch (final InterruptedException e) {
+ LOGGER.debug("Engine {} processing interrupted ", engineWorkerKey);
+ break;
+ }
+
+ try {
+ if (event != null) {
+ if (debugEnabled) {
+ LOGGER.debug("Trigger Event {} forwarded to the Apex engine", event);
+ }
+ final EnEvent enevent = apexEnEventConverter.fromApexEvent(event);
+ engine.handleEvent(enevent);
+ }
+ } catch (final ApexException e) {
+ LOGGER.warn("Engine {} failed to process event {}", engineWorkerKey, event.toString(), e);
+ } catch (final Exception e) {
+ LOGGER.warn("Engine {} terminated processing event {}", engineWorkerKey, event.toString(), e);
+ break;
+ }
+ }
+ LOGGER.debug("Engine {} completed processing", engineWorkerKey);
+ }
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/package-info.java
new file mode 100644
index 000000000..b0acca8d7
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/impl/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides the implementation of the APEX engine runtime interfaces. It uses the APEX core engine
+ * as its implementation.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.runtime.impl;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/package-info.java
new file mode 100644
index 000000000..b54a90349
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/engine/runtime/package-info.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Provides Java APIs for APEX engines at runtime. The {@link EngineService} is used to start, stop
+ * and manage APEX engines. {@link EngineServiceEventInterface} is used to send events to an APEX
+ * engine. {@link ApexEventListener} interface is used to receive events from an APEX engine.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.engine.runtime;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterException.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterException.java
new file mode 100644
index 000000000..229250bcf
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterException.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
+
+/**
+ * This exception will be called if an error occurs in Apex parameter handling.
+ *
+ * @author Liam Fallon
+ */
+public class ApexParameterException extends ApexException {
+ private static final long serialVersionUID = -8507246953751956974L;
+
+ /**
+ * Instantiates a new apex parameter handling exception with a message.
+ *
+ * @param message the message
+ */
+ public ApexParameterException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex parameter handling exception with a message and a caused by
+ * exception.
+ *
+ * @param message the message
+ * @param e the exception that caused this exception to be thrown
+ */
+ public ApexParameterException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterHandler.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterHandler.java
new file mode 100644
index 000000000..79f10bdea
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterHandler.java
@@ -0,0 +1,100 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters;
+
+import java.io.FileReader;
+
+import org.onap.policy.apex.core.engine.EngineParameters;
+import org.onap.policy.apex.service.engine.main.ApexCommandLineArguments;
+import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters;
+import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParametersJSONAdapter;
+import org.onap.policy.apex.service.parameters.engineservice.EngineServiceParametersJSONAdapter;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParametersJSONAdapter;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * This class handles reading, parsing and validating of Apex parameters from JSON files.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexParameterHandler {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexParameterHandler.class);
+
+ /**
+ * Read the parameters from the parameter file.
+ *
+ * @param arguments the arguments passed to Apex
+ * @return the parameters read from the configuration file
+ * @throws ApexParameterException on parameter exceptions
+ */
+ public ApexParameters getParameters(final ApexCommandLineArguments arguments) throws ApexParameterException {
+ ApexParameters parameters = null;
+
+ // Read the parameters
+ try {
+ // Register the adapters for our carrier technologies and event protocols with GSON
+ // @formatter:off
+ final Gson gson = new GsonBuilder()
+ .registerTypeAdapter(EngineParameters .class, new EngineServiceParametersJSONAdapter())
+ .registerTypeAdapter(CarrierTechnologyParameters.class, new CarrierTechnologyParametersJSONAdapter())
+ .registerTypeAdapter(EventProtocolParameters .class, new EventProtocolParametersJSONAdapter())
+ .create();
+ // @formatter:on
+ parameters = gson.fromJson(new FileReader(arguments.getFullConfigurationFilePath()), ApexParameters.class);
+ } catch (final Exception e) {
+ final String errorMessage = "error reading parameters from \"" + arguments.getConfigurationFilePath()
+ + "\"\n" + "(" + e.getClass().getSimpleName() + "):" + e.getMessage();
+ LOGGER.error(errorMessage, e);
+ throw new ApexParameterException(errorMessage, e);
+ }
+
+ // The JSON processing returns null if there is an empty file
+ if (parameters == null) {
+ final String errorMessage = "no parameters found in \"" + arguments.getConfigurationFilePath() + "\"";
+ LOGGER.error(errorMessage);
+ throw new ApexParameterException(errorMessage);
+ }
+
+ // Check if we should override the model file parameter
+ final String modelFilePath = arguments.getModelFilePath();
+ if (modelFilePath != null && modelFilePath.replaceAll("\\s+", "").length() > 0) {
+ parameters.getEngineServiceParameters().setPolicyModelFileName(modelFilePath);
+ }
+
+ // validate the parameters
+ final String validationResult = parameters.validate();
+ if (!validationResult.isEmpty()) {
+ String returnMessage =
+ "validation error(s) on parameters from \"" + arguments.getConfigurationFilePath() + "\"\n";
+ returnMessage += validationResult;
+
+ LOGGER.error(returnMessage);
+ throw new ApexParameterException(returnMessage);
+ }
+
+ return parameters;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterRuntimeException.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterRuntimeException.java
new file mode 100644
index 000000000..2334a7e60
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterRuntimeException.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters;
+
+import org.onap.policy.apex.model.basicmodel.concepts.ApexRuntimeException;
+
+/**
+ * This exception will be called if an error occurs in Apex parameter handling.
+ *
+ * @author Liam Fallon
+ */
+public class ApexParameterRuntimeException extends ApexRuntimeException {
+ private static final long serialVersionUID = -8507246953751956974L;
+
+ /**
+ * Instantiates a new apex parameter handling exception with a message.
+ *
+ * @param message the message
+ */
+ public ApexParameterRuntimeException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new apex parameter handling exception with a message and a caused by
+ * exception.
+ *
+ * @param message the message
+ * @param e the exception that caused this exception to be thrown
+ */
+ public ApexParameterRuntimeException(final String message, final Exception e) {
+ super(message, e);
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterValidator.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterValidator.java
new file mode 100644
index 000000000..a8cbe3b46
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameterValidator.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters;
+
+/**
+ * This interface is implemented by Apex parameter classes so that they can be validated.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public interface ApexParameterValidator {
+ /**
+ * Validate a parameter java bean, if the parameter bean is valid, an empty string is returned,
+ * otherwise the string gives details of the invalid parameters.
+ *
+ * @return the string with validation errors
+ */
+ String validate();
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameters.java
new file mode 100644
index 000000000..52c6f4960
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/ApexParameters.java
@@ -0,0 +1,357 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.onap.policy.apex.context.parameters.ContextParameters;
+import org.onap.policy.apex.model.basicmodel.service.AbstractParameters;
+import org.onap.policy.apex.model.basicmodel.service.ParameterService;
+import org.onap.policy.apex.service.parameters.engineservice.EngineServiceParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
+import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
+
+/**
+ * The main container parameter class for an Apex service.
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>engineServiceParameters: The parameters for the Apex engine service itself, such as the
+ * number of engine threads to run and the deployment port number to use.
+ * <li>eventOutputParameters: A map of parameters for event outputs that Apex will use to emit
+ * events. Apex emits events on all outputs
+ * <li>eventInputParameters: A map or parameters for event inputs from which Apex will consume
+ * events. Apex reads events from all its event inputs.
+ * <li>synchronousEventHandlerParameters: A map of parameters for synchronous event handlers That
+ * Apex receives events from and replies immediately to those events.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class ApexParameters extends AbstractParameters implements ApexParameterValidator {
+ /**
+ * Constructor to create an apex parameters instance and register the instance with the
+ * parameter service.
+ */
+ public ApexParameters() {
+ super(ContextParameters.class.getCanonicalName());
+ ParameterService.registerParameters(ApexParameters.class, this);
+ }
+
+ // Parameters for the engine service and the engine threads in the engine service
+ private EngineServiceParameters engineServiceParameters;
+
+ // Parameters for the event outputs that Apex will use to send events on its outputs
+ private Map<String, EventHandlerParameters> eventOutputParameters = new LinkedHashMap<>();
+
+ // Parameters for the event inputs that Apex will use to receive events on its inputs
+ private Map<String, EventHandlerParameters> eventInputParameters = new LinkedHashMap<>();
+
+ /**
+ * Gets the parameters for the Apex engine service.
+ *
+ * @return the engine service parameters
+ */
+ public EngineServiceParameters getEngineServiceParameters() {
+ return engineServiceParameters;
+ }
+
+ /**
+ * Sets the engine service parameters.
+ *
+ * @param engineServiceParameters the engine service parameters
+ */
+ public void setEngineServiceParameters(final EngineServiceParameters engineServiceParameters) {
+ this.engineServiceParameters = engineServiceParameters;
+ }
+
+ /**
+ * Gets the event output parameter map.
+ *
+ * @return the parameters for all event outputs
+ */
+ public Map<String, EventHandlerParameters> getEventOutputParameters() {
+ return eventOutputParameters;
+ }
+
+ /**
+ * Sets the event output parameters.
+ *
+ * @param eventOutputParameters the event outputs parameters
+ */
+ public void setEventOutputParameters(final Map<String, EventHandlerParameters> eventOutputParameters) {
+ this.eventOutputParameters = eventOutputParameters;
+ }
+
+ /**
+ * Gets the event input parameter map.
+ *
+ * @return the parameters for all event inputs
+ */
+ public Map<String, EventHandlerParameters> getEventInputParameters() {
+ return eventInputParameters;
+ }
+
+ /**
+ * Sets the event input parameters.
+ *
+ * @param eventInputParameters the event input parameters
+ */
+ public void setEventInputParameters(final Map<String, EventHandlerParameters> eventInputParameters) {
+ this.eventInputParameters = eventInputParameters;
+ }
+
+ /**
+ * This method formats a validation result with a header if the result is not empty.
+ *
+ * @param validationResultMessage The incoming message
+ * @param heading The heading to prepend on the message
+ * @return the formatted message
+ */
+ private String validationResultFormatter(final String validationResultMessage, final String heading) {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ if (validationResultMessage.length() > 0) {
+ errorMessageBuilder.append(heading);
+ errorMessageBuilder.append(validationResultMessage);
+ }
+
+ return errorMessageBuilder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ if (engineServiceParameters == null) {
+ errorMessageBuilder.append(" engine service parameters are not specified\n");
+ } else {
+ errorMessageBuilder.append(validationResultFormatter(engineServiceParameters.validate(),
+ " engine service parameters invalid\n"));
+ }
+
+ // Sanity check, we must have an entry in both output and input maps
+ if (eventOutputParameters.isEmpty() || eventInputParameters.isEmpty()) {
+ errorMessageBuilder.append(" at least one event output and one event input must be specified\n");
+ }
+
+ // Validate that the values of all parameters are ok
+ validateEventHandlerMap("event input", errorMessageBuilder, eventInputParameters);
+ validateEventHandlerMap("event output", errorMessageBuilder, eventOutputParameters);
+
+ // Only do peer mode validate if there are no other errors
+ if (errorMessageBuilder.length() == 0) {
+ for (final EventHandlerPeeredMode peeredMode : EventHandlerPeeredMode.values()) {
+ validatePeeredMode(errorMessageBuilder, peeredMode);
+ }
+ }
+
+ // Check if we have any errors
+ if (errorMessageBuilder.length() > 0) {
+ errorMessageBuilder.insert(0, "Apex parameters invalid\n");
+ }
+
+ return errorMessageBuilder.toString().trim();
+ }
+
+ /**
+ * This method validates the parameters in an event handler map.
+ *
+ * @param eventHandlerType the type of the event handler to use on error messages
+ * @param errorMessageBuilder the builder to use to return validation messages
+ * @param parsForValidation The event handler parameters to validate (input or output)
+ */
+ // CHECKSTYLE:OFF: checkstyle:finalParameter
+ private void validateEventHandlerMap(final String eventHandlerType, final StringBuilder errorMessageBuilder,
+ final Map<String, EventHandlerParameters> parsForValidation) {
+ // CHECKSTYLE:ON: checkstyle:finalParameter
+ for (final Entry<String, EventHandlerParameters> parameterEntry : parsForValidation.entrySet()) {
+ if (parameterEntry.getKey() == null || parameterEntry.getKey().trim().isEmpty()) {
+ errorMessageBuilder
+ .append(" invalid " + eventHandlerType + " name \"" + parameterEntry.getKey() + "\" \n");
+ } else if (parameterEntry.getValue() == null) {
+ errorMessageBuilder.append(" invalid/Null event input prameters specified for " + eventHandlerType
+ + " name \"" + parameterEntry.getKey() + "\" \n");
+ } else {
+ errorMessageBuilder.append(validationResultFormatter(parameterEntry.getValue().validate(),
+ " " + eventHandlerType + " (" + parameterEntry.getKey() + ") parameters invalid\n"));
+ }
+
+ parameterEntry.getValue().setName(parameterEntry.getKey());
+
+ // Validate parameters for peered mode settings
+ for (final EventHandlerPeeredMode peeredMode : EventHandlerPeeredMode.values()) {
+ validatePeeredModeParameters(eventHandlerType, errorMessageBuilder, parameterEntry, peeredMode);
+ }
+ }
+ }
+
+ /**
+ * Validate parameter values for event handlers in a peered mode
+ *
+ * @param eventHandlerType The event handler type we are checking
+ * @param errorMessageBuilder The builder to which to append any error messages
+ * @param parameterEntry The entry to check the peered mode on
+ * @param peeredMode The mode to check
+ */
+ private void validatePeeredModeParameters(final String eventHandlerType, final StringBuilder errorMessageBuilder,
+ final Entry<String, EventHandlerParameters> parameterEntry, final EventHandlerPeeredMode peeredMode) {
+ final String messagePreamble = " specified peered mode \"" + peeredMode + "\"";
+ final String peer = parameterEntry.getValue().getPeer(peeredMode);
+
+ if (parameterEntry.getValue().isPeeredMode(peeredMode)) {
+ if (peer == null || peer.trim().isEmpty()) {
+ errorMessageBuilder.append(messagePreamble + " mandatory parameter not specified or is null on "
+ + eventHandlerType + " \"" + parameterEntry.getKey() + "\" \n");
+ }
+ if (parameterEntry.getValue().getPeerTimeout(peeredMode) < 0) {
+ errorMessageBuilder.append(
+ messagePreamble + " timeout value \"" + parameterEntry.getValue().getPeerTimeout(peeredMode)
+ + "\" is illegal on " + eventHandlerType + " \"" + parameterEntry.getKey()
+ + "\", specify a non-negative timeout value in milliseconds\n");
+ }
+ } else {
+ if (peer != null) {
+ errorMessageBuilder.append(messagePreamble + " peer is illegal on non synchronous " + eventHandlerType
+ + " \"" + parameterEntry.getKey() + "\" \n");
+ }
+ if (parameterEntry.getValue().getPeerTimeout(peeredMode) != 0) {
+ errorMessageBuilder.append(messagePreamble + " timeout is illegal on non synchronous "
+ + eventHandlerType + " \"" + parameterEntry.getKey() + "\" \n");
+ }
+ }
+ }
+
+ /**
+ * This method validates that the settings are valid for the given peered mode
+ *
+ * @param errorMessageBuilder The builder to which to append any error messages
+ * @param peeredMode The peered mode to check
+ */
+ private void validatePeeredMode(final StringBuilder errorMessageBuilder, final EventHandlerPeeredMode peeredMode) {
+ // Find the input and output event handlers that use this peered mode
+ final Map<String, EventHandlerParameters> inputParametersUsingMode = new HashMap<>();
+ final Map<String, EventHandlerParameters> outputParametersUsingMode = new HashMap<>();
+
+ // Find input and output parameters using this mode
+ for (final Entry<String, EventHandlerParameters> inputParameterEntry : eventInputParameters.entrySet()) {
+ if (inputParameterEntry.getValue().isPeeredMode(peeredMode)) {
+ inputParametersUsingMode.put(inputParameterEntry.getKey(), inputParameterEntry.getValue());
+ }
+ }
+ for (final Entry<String, EventHandlerParameters> outputParameterEntry : eventOutputParameters.entrySet()) {
+ if (outputParameterEntry.getValue().isPeeredMode(peeredMode)) {
+ outputParametersUsingMode.put(outputParameterEntry.getKey(), outputParameterEntry.getValue());
+ }
+ }
+
+ // Validate the parameters for each side of the peered mode parameters
+ validatePeeredModePeers(" event input for peered mode \"" + peeredMode + "\": ", errorMessageBuilder,
+ peeredMode, inputParametersUsingMode, outputParametersUsingMode);
+ validatePeeredModePeers(" event output for peered mode \"" + peeredMode + "\": ", errorMessageBuilder,
+ peeredMode, outputParametersUsingMode, inputParametersUsingMode);
+ }
+
+ /**
+ * This method validates that the settings are valid for the event handlers on one
+ *
+ * @param messagePreamble the preamble for messages indicating the peered mode side
+ * @param errorMessageBuilder The builder to which to append any error messages
+ * @param leftModeParameters The mode parameters being checked
+ * @param rightModeParameters The mode parameters being referenced by the checked parameters
+ */
+ private void validatePeeredModePeers(final String messagePreamble, final StringBuilder errorMessageBuilder,
+ final EventHandlerPeeredMode peeredMode, final Map<String, EventHandlerParameters> leftModeParameterMap,
+ final Map<String, EventHandlerParameters> rightModeParameterMap) {
+
+ // These sets are used to check for duplicate references on the both sides
+ final Set<String> leftCheckDuplicateSet = new HashSet<>();
+ final Set<String> rightCheckDuplicateSet = new HashSet<>();
+
+ // Check for missing peers, all peers are set because we have checked them previously so no
+ // need for null checks
+ for (final Entry<String, EventHandlerParameters> leftModeParameterEntry : leftModeParameterMap.entrySet()) {
+ final String leftSidePeer = leftModeParameterEntry.getValue().getPeer(peeredMode);
+
+ final EventHandlerParameters leftModeParameters = leftModeParameterEntry.getValue();
+ final EventHandlerParameters rightModeParameters = rightModeParameterMap.get(leftSidePeer);
+
+ // Check that the peer reference is OK
+ if (rightModeParameters == null) {
+ errorMessageBuilder.append(messagePreamble + "peer \"" + leftModeParameters.getPeer(peeredMode)
+ + "\" for event handler \"" + leftModeParameterEntry.getKey()
+ + "\" does not exist or is not defined as being synchronous\n");
+ continue;
+ }
+
+ // Now check that the right side peer is the left side event handler
+ final String rightSidePeer = rightModeParameters.getPeer(peeredMode);
+ if (!rightSidePeer.equals(leftModeParameterEntry.getKey())) {
+ errorMessageBuilder
+ .append(messagePreamble + "peer value \"" + rightSidePeer + "\" on peer \"" + leftSidePeer
+ + "\" does not equal event handler \"" + leftModeParameterEntry.getKey() + "\"\n");
+ } else {
+ // Check for duplicates
+ if (!leftCheckDuplicateSet.add(leftSidePeer)) {
+ errorMessageBuilder
+ .append(messagePreamble + "peer value \"" + leftSidePeer + "\" on event handler \""
+ + leftModeParameterEntry.getKey() + "\" is used more than once\n");
+ }
+ if (!rightCheckDuplicateSet.add(rightSidePeer)) {
+ errorMessageBuilder.append(messagePreamble + "peer value \"" + rightSidePeer + "\" on peer \""
+ + leftSidePeer + "\" on event handler \"" + leftModeParameterEntry.getKey()
+ + "\" is used more than once\n");
+ }
+ }
+
+ // Cross-set the timeouts if they are not specified
+ if (leftModeParameters.getPeerTimeout(peeredMode) != 0) {
+ if (rightModeParameters.getPeerTimeout(peeredMode) != 0) {
+ if (leftModeParameters.getPeerTimeout(peeredMode) != rightModeParameters
+ .getPeerTimeout(peeredMode)) {
+ errorMessageBuilder.append(messagePreamble + "timeout "
+ + leftModeParameters.getPeerTimeout(peeredMode) + "on event handler \""
+ + leftModeParameters.getName() + "\" does not equal timeout value "
+ + rightModeParameters.getPeerTimeout(peeredMode) + "on event handler \""
+ + rightModeParameters.getName() + "\"\n");
+ }
+ } else {
+ rightModeParameters.setPeerTimeout(peeredMode, leftModeParameters.getPeerTimeout(peeredMode));
+ }
+ } else {
+ if (rightModeParameters.getPeerTimeout(peeredMode) != 0) {
+ leftModeParameters.setPeerTimeout(peeredMode, rightModeParameters.getPeerTimeout(peeredMode));
+ }
+ }
+ }
+
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParameters.java
new file mode 100644
index 000000000..ba0327de1
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParameters.java
@@ -0,0 +1,161 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.carriertechnology;
+
+import org.onap.policy.apex.model.basicmodel.service.AbstractParameters;
+import org.onap.policy.apex.service.parameters.ApexParameterValidator;
+
+/**
+ * The default carrier technology parameter class that may be specialized by carrier technology
+ * plugins that require plugin specific parameters.
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>label: The label of the carrier technology.
+ * <li>eventProducerPluginClass: The name of the plugin class that will be used by Apex to produce
+ * and emit output events for this carrier technology
+ * <li>eventConsumerPluginClass: The name of the plugin class that will be used by Apex to receive
+ * and process input events from this carrier technology carrier technology
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class CarrierTechnologyParameters extends AbstractParameters implements ApexParameterValidator {
+
+ // The carrier technology label
+ private String label = null;
+
+ // Producer and Consumer plugin classes for the event producer and consumer for this carrier
+ // technology
+ private String eventProducerPluginClass = null;
+ private String eventConsumerPluginClass = null;
+
+ /**
+ * Constructor to create a carrier technology parameters instance with the name of a sub class
+ * of this class and register the instance with the parameter service.
+ *
+ * @param parameterClassName the class name of a sub class of this class
+ */
+ public CarrierTechnologyParameters(final String parameterClassName) {
+ super(parameterClassName);
+ }
+
+ /**
+ * Gets the label of the carrier technology.
+ *
+ * @return the label of the carrier technology
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Sets the label of the carrier technology.
+ *
+ * @param label the label of the carrier technology
+ */
+ public void setLabel(final String label) {
+ if (label != null) {
+ this.label = label.replaceAll("\\s+", "");
+ } else {
+ this.label = null;
+ }
+ }
+
+ /**
+ * Gets the event producer plugin class.
+ *
+ * @return the event producer plugin class
+ */
+ public String getEventProducerPluginClass() {
+ return eventProducerPluginClass;
+ }
+
+ /**
+ * Sets the event producer plugin class.
+ *
+ * @param eventProducerPluginClass the new event producer plugin class
+ */
+ public void setEventProducerPluginClass(final String eventProducerPluginClass) {
+ if (eventProducerPluginClass != null) {
+ this.eventProducerPluginClass = eventProducerPluginClass.replaceAll("\\s+", "");
+ } else {
+ this.eventProducerPluginClass = null;
+ }
+ }
+
+ /**
+ * Gets the event consumer plugin class.
+ *
+ * @return the event consumer plugin class
+ */
+ public String getEventConsumerPluginClass() {
+ return eventConsumerPluginClass;
+ }
+
+ /**
+ * Sets the event consumer plugin class.
+ *
+ * @param eventConsumerPluginClass the new event consumer plugin class
+ */
+ public void setEventConsumerPluginClass(final String eventConsumerPluginClass) {
+ if (eventConsumerPluginClass != null) {
+ this.eventConsumerPluginClass = eventConsumerPluginClass.replaceAll("\\s+", "");
+ } else {
+ this.eventConsumerPluginClass = null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "CarrierTechnologyParameters [label=" + label + ", eventProducerPluginClass=" + eventProducerPluginClass
+ + ", eventConsumerPluginClass=" + eventConsumerPluginClass + "]";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ if (label == null || label.length() == 0) {
+ errorMessageBuilder.append(" carrier technology label not specified or is blank\n");
+ }
+
+ if (eventProducerPluginClass == null || eventProducerPluginClass.length() == 0) {
+ errorMessageBuilder.append(" carrier technology eventProducerPluginClass not specified or is blank\n");
+ }
+
+ if (eventConsumerPluginClass == null || eventConsumerPluginClass.length() == 0) {
+ errorMessageBuilder.append(" carrier technology eventConsumerPluginClass not specified or is blank\n");
+ }
+
+ return errorMessageBuilder.toString();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParametersJSONAdapter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParametersJSONAdapter.java
new file mode 100644
index 000000000..5aa7d6455
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/CarrierTechnologyParametersJSONAdapter.java
@@ -0,0 +1,176 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.carriertechnology;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.onap.policy.apex.service.engine.event.impl.eventrequestor.EventRequestorCarrierTechnologyParameters;
+import org.onap.policy.apex.service.engine.event.impl.filecarrierplugin.FILECarrierTechnologyParameters;
+import org.onap.policy.apex.service.parameters.ApexParameterRuntimeException;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * This class deserialises various type of carrier technology parameters from JSON.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class CarrierTechnologyParametersJSONAdapter
+ implements JsonSerializer<CarrierTechnologyParameters>, JsonDeserializer<CarrierTechnologyParameters> {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(CarrierTechnologyParametersJSONAdapter.class);
+
+ private static final String PARAMETER_CLASS_NAME = "parameterClassName";
+
+ private static final String CARRIER_TECHNOLOGY_TOKEN = "carrierTechnology";
+ private static final String CARRIER_TECHNOLOGY_PARAMETERS = "parameters";
+
+ // Built in technology parameters
+ private static final Map<String, String> BUILT_IN_CARRIER_TECHNOLOGY_PARMETER_CLASS_MAP = new HashMap<>();
+ static {
+ BUILT_IN_CARRIER_TECHNOLOGY_PARMETER_CLASS_MAP.put("FILE",
+ FILECarrierTechnologyParameters.class.getCanonicalName());
+ BUILT_IN_CARRIER_TECHNOLOGY_PARMETER_CLASS_MAP.put("EVENT_REQUESTOR",
+ EventRequestorCarrierTechnologyParameters.class.getCanonicalName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.google.gson.JsonSerializer#serialize(java.lang.Object, java.lang.reflect.Type,
+ * com.google.gson.JsonSerializationContext)
+ */
+ @Override
+ public JsonElement serialize(final CarrierTechnologyParameters src, final Type typeOfSrc,
+ final JsonSerializationContext context) {
+ final String returnMessage = "serialization of Apex carrier technology parameters to Json is not supported";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.google.gson.JsonDeserializer#deserialize(com.google.gson.JsonElement,
+ * java.lang.reflect.Type, com.google.gson.JsonDeserializationContext)
+ */
+ @Override
+ public CarrierTechnologyParameters deserialize(final JsonElement json, final Type typeOfT,
+ final JsonDeserializationContext context) throws JsonParseException {
+ final JsonObject jsonObject = json.getAsJsonObject();
+
+ // Get the carrier technology label primitive
+ final JsonPrimitive labelJsonPrimitive = (JsonPrimitive) jsonObject.get(CARRIER_TECHNOLOGY_TOKEN);
+
+ // Check if we found our carrier technology
+ if (labelJsonPrimitive == null) {
+ LOGGER.warn("carrier technology parameter \"" + CARRIER_TECHNOLOGY_TOKEN + "\" not found in JSON file");
+ return null;
+ }
+
+ // Get and check the carrier technology label
+ final String carrierTechnologyLabel = labelJsonPrimitive.getAsString().replaceAll("\\s+", "");
+ if (carrierTechnologyLabel == null || carrierTechnologyLabel.length() == 0) {
+ final String errorMessage = "carrier technology parameter \"" + CARRIER_TECHNOLOGY_TOKEN + "\" value \""
+ + labelJsonPrimitive.getAsString() + "\" invalid in JSON file";
+ LOGGER.warn(errorMessage);
+ throw new ApexParameterRuntimeException(errorMessage);
+ }
+
+ // We now get the technology carrier parameter class
+ String carrierTechnologyParameterClassName = null;
+
+ // Get the technology carrier parameter class for the carrier technology plugin class from
+ // the configuration parameters
+ final JsonPrimitive classNameJsonPrimitive = (JsonPrimitive) jsonObject.get(PARAMETER_CLASS_NAME);
+
+ // If no technology carrier parameter class was specified, we try to use a built in carrier
+ // technology
+ if (classNameJsonPrimitive == null) {
+ carrierTechnologyParameterClassName =
+ BUILT_IN_CARRIER_TECHNOLOGY_PARMETER_CLASS_MAP.get(carrierTechnologyLabel);
+ } else {
+ // We use the specified one
+ carrierTechnologyParameterClassName = classNameJsonPrimitive.getAsString().replaceAll("\\s+", "");
+ }
+
+ // Check the carrier technology parameter class
+ if (carrierTechnologyParameterClassName == null || carrierTechnologyParameterClassName.length() == 0) {
+ final String errorMessage =
+ "carrier technology \"" + carrierTechnologyLabel + "\" parameter \"" + PARAMETER_CLASS_NAME
+ + "\" value \"" + classNameJsonPrimitive.getAsString() + "\" invalid in JSON file";
+ LOGGER.warn(errorMessage);
+ throw new ApexParameterRuntimeException(errorMessage);
+ }
+
+ // Get the class for the carrier technology
+ Class<?> carrierTechnologyParameterClass = null;
+ try {
+ carrierTechnologyParameterClass = Class.forName(carrierTechnologyParameterClassName);
+ } catch (final ClassNotFoundException e) {
+ final String errorMessage =
+ "carrier technology \"" + carrierTechnologyLabel + "\" parameter \"" + PARAMETER_CLASS_NAME
+ + "\" value \"" + carrierTechnologyParameterClassName + "\", could not find class";
+ LOGGER.warn(errorMessage, e);
+ throw new ApexParameterRuntimeException(errorMessage, e);
+ }
+
+ // Deserialise the class
+ CarrierTechnologyParameters carrierTechnologyParameters =
+ context.deserialize(jsonObject.get(CARRIER_TECHNOLOGY_PARAMETERS), carrierTechnologyParameterClass);
+ if (carrierTechnologyParameters == null) {
+ // OK no parameters for the carrier technology have been specified, just instantiate the
+ // default parameters
+ try {
+ carrierTechnologyParameters =
+ (CarrierTechnologyParameters) carrierTechnologyParameterClass.newInstance();
+ } catch (final Exception e) {
+ final String errorMessage = "could not create default parameters for carrier technology \""
+ + carrierTechnologyLabel + "\"\n" + e.getMessage();
+ LOGGER.warn(errorMessage, e);
+ throw new ApexParameterRuntimeException(errorMessage, e);
+ }
+ }
+
+ // Check that the carrier technology label matches the label in the carrier technology
+ // parameters object
+ if (!carrierTechnologyParameters.getLabel().equals(carrierTechnologyLabel)) {
+ final String errorMessage = "carrier technology \"" + carrierTechnologyLabel + "\" does not match plugin \""
+ + carrierTechnologyParameters.getLabel() + "\" in \"" + carrierTechnologyParameterClassName
+ + "\", specify correct carrier technology parameter plugin in parameter \"" + PARAMETER_CLASS_NAME
+ + "\"";
+ LOGGER.warn(errorMessage);
+ throw new ApexParameterRuntimeException(errorMessage);
+ }
+
+ return carrierTechnologyParameters;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/package-info.java
new file mode 100644
index 000000000..5912c0129
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/carriertechnology/package-info.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Defines the structure of carrier technology parameters for APEX.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.parameters.carriertechnology;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParameters.java
new file mode 100644
index 000000000..6b60732c3
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParameters.java
@@ -0,0 +1,329 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.engineservice;
+
+import java.io.File;
+import java.net.URL;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.basicmodel.service.AbstractParameters;
+import org.onap.policy.apex.model.basicmodel.service.ParameterService;
+import org.onap.policy.apex.model.utilities.ResourceUtils;
+import org.onap.policy.apex.service.parameters.ApexParameterValidator;
+
+import org.onap.policy.apex.core.engine.EngineParameters;
+
+/**
+ * This class holds the parameters for an Apex Engine Service with multiple engine threads running
+ * multiple engines.
+ *
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>name: The name of the Apex engine service, which can be set to any value that matches the
+ * regular expression {@link org.onap.policy.apex.model.basicmodel.concepts.AxKey#NAME_REGEXP}.
+ * <li>version: The name of the Apex engine service, which can be set to any value that matches the
+ * regular expression {@link org.onap.policy.apex.model.basicmodel.concepts.AxKey#VERSION_REGEXP}.
+ * <li>id: The ID of the Apex engine service, which can be set to any integer value by a user.
+ * <li>instanceCount: The number of Apex engines to spawn in this engine service. Each engine
+ * executes in its own thread.
+ * <li>deploymentPort: The port that the Apex Engine Service will open so that it can be managed
+ * using the EngDep protocol. The EngDep protocol allows the engine service to be monitored, to
+ * start and stop engines in the engine service, and to update the policy model of the engine
+ * service.
+ * <li>engineParameters: Parameters (a {@link EngineParameters} instance) that all of the engines in
+ * the engine service will use. All engine threads use the same parameters and act as a pool of
+ * engines. Engine parameters specify the executors and context management for the engines.
+ * <li>policyModelFileName: The full path to the policy model file name to deploy on the engine
+ * service.
+ * <li>periodicEventPeriod: The period in milliseconds at which the periodic event PERIOIC_EVENT
+ * will be generated by APEX, 0 means no periodic event generation, negative values are illegal.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EngineServiceParameters extends AbstractParameters implements ApexParameterValidator {
+ private static final int MAX_PORT = 65535;
+
+ // @formatter:off
+ /** The default name of the Apex engine service. */
+ public static final String DEFAULT_NAME = "ApexEngineService";
+
+ /** The default version of the Apex engine service. */
+ public static final String DEFAULT_VERSION = "1.0.0";
+
+ /** The default ID of the Apex engine service. */
+ public static final int DEFAULT_ID = -1;
+
+ /** The default instance count for the Apex engine service. */
+ public static final int DEFAULT_INSTANCE_COUNT = 1;
+
+ /** The default EngDep deployment port of the Apex engine service. */
+ public static final int DEFAULT_DEPLOYMENT_PORT = 34421;
+
+ // Apex engine service parameters
+ private String name = DEFAULT_NAME;
+ private String version = DEFAULT_VERSION;
+ private int id = DEFAULT_ID;
+ private int instanceCount = DEFAULT_INSTANCE_COUNT;
+ private int deploymentPort = DEFAULT_DEPLOYMENT_PORT;
+ private String policyModelFileName = null;
+ private long periodicEventPeriod = 0;
+ // @formatter:on
+
+ // Apex engine internal parameters
+ private EngineParameters engineParameters = new EngineParameters();
+
+ /**
+ * Constructor to create an apex engine service parameters instance and register the instance
+ * with the parameter service.
+ */
+ public EngineServiceParameters() {
+ super(EngineServiceParameters.class.getCanonicalName());
+ ParameterService.registerParameters(EngineServiceParameters.class, this);
+ }
+
+ /**
+ * Gets the key of the Apex engine service.
+ *
+ * @return the Apex engine service key
+ */
+ public AxArtifactKey getEngineKey() {
+ return new AxArtifactKey(name, version);
+ }
+
+ /**
+ * Sets the key of the Apex engine service.
+ *
+ * @param key the the Apex engine service key
+ */
+ public void setEngineKey(final AxArtifactKey key) {
+ this.setName(key.getName());
+ this.setVersion(key.getVersion());
+ }
+
+ /**
+ * Gets the name of the engine service.
+ *
+ * @return the name of the engine service
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the engine service.
+ *
+ * @param name the name of the engine service
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * Gets the version of the engine service.
+ *
+ * @return the version of the engine service
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Sets the version of the engine service.
+ *
+ * @param version the version of the engine service
+ */
+ public void setVersion(final String version) {
+ this.version = version;
+ }
+
+ /**
+ * Gets the id of the engine service.
+ *
+ * @return the id of the engine service
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Sets the id of the engine service.
+ *
+ * @param id the id of the engine service
+ */
+ public void setId(final int id) {
+ this.id = id;
+ }
+
+ /**
+ * Gets the instance count of the engine service.
+ *
+ * @return the instance count of the engine service
+ */
+ public int getInstanceCount() {
+ return instanceCount;
+ }
+
+ /**
+ * Sets the instance count of the engine service.
+ *
+ * @param instanceCount the instance count of the engine service
+ */
+ public void setInstanceCount(final int instanceCount) {
+ this.instanceCount = instanceCount;
+ }
+
+ /**
+ * Gets the deployment port of the engine service.
+ *
+ * @return the deployment port of the engine service
+ */
+ public int getDeploymentPort() {
+ return deploymentPort;
+ }
+
+ /**
+ * Sets the deployment port of the engine service.
+ *
+ * @param deploymentPort the deployment port of the engine service
+ */
+ public void setDeploymentPort(final int deploymentPort) {
+ this.deploymentPort = deploymentPort;
+ }
+
+ /**
+ * Gets the file name of the policy engine for deployment on the engine service.
+ *
+ * @return the file name of the policy engine for deployment on the engine service
+ */
+ public String getPolicyModelFileName() {
+ return ResourceUtils.getFilePath4Resource(policyModelFileName);
+ }
+
+ /**
+ * Sets the file name of the policy engine for deployment on the engine service.
+ *
+ * @param policyModelFileName the file name of the policy engine for deployment on the engine
+ * service
+ */
+ public void setPolicyModelFileName(final String policyModelFileName) {
+ this.policyModelFileName = policyModelFileName;
+ }
+
+ /**
+ * Get the period in milliseconds at which periodic events are sent, zero means no periodic
+ * events are being sent.
+ *
+ * @return the periodic period
+ */
+ public long getPeriodicEventPeriod() {
+ return periodicEventPeriod;
+ }
+
+ /**
+ * Set the period in milliseconds at which periodic events are sent, zero means no periodic
+ * events are to be sent, negative values are illegal.
+ *
+ * @param periodicEventPeriod the periodic period
+ */
+ public void setPeriodicEventPeriod(final long periodicEventPeriod) {
+ this.periodicEventPeriod = periodicEventPeriod;
+ }
+
+ /**
+ * Gets the engine parameters for engines in the engine service.
+ *
+ * @return the engine parameters for engines in the engine service
+ */
+ public EngineParameters getEngineParameters() {
+ return engineParameters;
+ }
+
+ /**
+ * Sets the engine parameters for engines in the engine service.
+ *
+ * @param engineParameters the engine parameters for engines in the engine service
+ */
+ public void setEngineParameters(final EngineParameters engineParameters) {
+ this.engineParameters = engineParameters;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.apps.uservice.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ try {
+ new AxArtifactKey(name, version);
+ } catch (final Exception e) {
+ errorMessageBuilder.append(" name [" + name + "] and/or version [" + version + "] invalid\n");
+ errorMessageBuilder.append(" " + e.getMessage() + "\n");
+ }
+
+ if (id < 0) {
+ errorMessageBuilder.append(
+ " id not specified or specified value [" + id + "] invalid, must be specified as id >= 0\n");
+ }
+
+ if (instanceCount < 1) {
+ errorMessageBuilder.append(
+ " instanceCount [" + instanceCount + "] invalid, must be specified as instanceCount >= 1\n");
+ }
+
+ if (deploymentPort < 1 || deploymentPort > MAX_PORT) {
+ errorMessageBuilder.append(
+ " deploymentPort [" + deploymentPort + "] invalid, must be specified as 1024 <= port <= 65535\n");
+ }
+
+ if (policyModelFileName != null) {
+ if (policyModelFileName.trim().length() == 0) {
+ errorMessageBuilder.append(" policyModelFileName [" + policyModelFileName
+ + "] invalid, must be specified as a non-empty string\n");
+ } else {
+ // The file name can refer to a resource on the local file system or on the class
+ // path
+ final URL fileURL = ResourceUtils.getURL4Resource(policyModelFileName);
+ if (fileURL == null) {
+ errorMessageBuilder.append(
+ " policyModelFileName [" + policyModelFileName + "] not found or is not a plain file\n");
+ } else {
+ final File policyModelFile = new File(fileURL.getPath());
+ if (!policyModelFile.isFile()) {
+ errorMessageBuilder.append(" policyModelFileName [" + policyModelFileName
+ + "] not found or is not a plain file\n");
+ }
+ }
+ }
+ }
+
+ if (periodicEventPeriod < 0) {
+ errorMessageBuilder.append(" periodicEventPeriod [" + periodicEventPeriod
+ + "] invalid, must be specified in milliseconds as >=0\n");
+ }
+
+ return errorMessageBuilder.toString();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParametersJSONAdapter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParametersJSONAdapter.java
new file mode 100644
index 000000000..9fca2fd19
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/EngineServiceParametersJSONAdapter.java
@@ -0,0 +1,287 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.engineservice;
+
+import java.lang.reflect.Type;
+import java.util.Map.Entry;
+
+import org.onap.policy.apex.context.impl.schema.java.JavaSchemaHelperParameters;
+import org.onap.policy.apex.context.parameters.ContextParameters;
+import org.onap.policy.apex.context.parameters.DistributorParameters;
+import org.onap.policy.apex.context.parameters.LockManagerParameters;
+import org.onap.policy.apex.context.parameters.PersistorParameters;
+import org.onap.policy.apex.context.parameters.SchemaHelperParameters;
+import org.onap.policy.apex.context.parameters.SchemaParameters;
+import org.onap.policy.apex.core.engine.EngineParameters;
+import org.onap.policy.apex.core.engine.ExecutorParameters;
+import org.onap.policy.apex.model.basicmodel.service.AbstractParameters;
+import org.onap.policy.apex.service.parameters.ApexParameterRuntimeException;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * This class deserializes engine service parameters from JSON format. The class produces an
+ * {@link EngineServiceParameters} instance from incoming JSON read from a configuration file in
+ * JSON format.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EngineServiceParametersJSONAdapter
+ implements JsonSerializer<EngineParameters>, JsonDeserializer<EngineParameters> {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EngineServiceParametersJSONAdapter.class);
+
+ private static final String PARAMETER_CLASS_NAME = "parameterClassName";
+
+ // @formatter:off
+ private static final String CONTEXT_PARAMETERS = "contextParameters";
+ private static final String DISTRIBUTOR_PARAMETERS = "distributorParameters";
+ private static final String LOCK_MANAGER_PARAMETERS = "lockManagerParameters";
+ private static final String PERSISTOR_PARAMETERS = "persistorParameters";
+ private static final String SCHEMA_PARAMETERS = "schemaParameters";
+ private static final String EXECUTOR_PARAMETERS = "executorParameters";
+ // @formatter:on
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.google.gson.JsonSerializer#serialize(java.lang.Object, java.lang.reflect.Type,
+ * com.google.gson.JsonSerializationContext)
+ */
+ @Override
+ public JsonElement serialize(final EngineParameters src, final Type typeOfSrc,
+ final JsonSerializationContext context) {
+ final String returnMessage = "serialization of Apex parameters to Json is not supported";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.google.gson.JsonDeserializer#deserialize(com.google.gson.JsonElement,
+ * java.lang.reflect.Type, com.google.gson.JsonDeserializationContext)
+ */
+ @Override
+ public EngineParameters deserialize(final JsonElement json, final Type typeOfT,
+ final JsonDeserializationContext context) throws JsonParseException {
+ final JsonObject engineParametersJsonObject = json.getAsJsonObject();
+
+ final EngineParameters engineParameters = new EngineParameters();
+
+ // Deserialise context parameters, they may be a subclass of the ContextParameters class
+ engineParameters.setContextParameters(
+ (ContextParameters) context.deserialize(engineParametersJsonObject, ContextParameters.class));
+
+ // Context parameter wrangling
+ getContextParameters(engineParametersJsonObject, engineParameters, context);
+
+ // Executor parameter wrangling
+ getExecutorParameters(engineParametersJsonObject, engineParameters, context);
+
+ return engineParameters;
+ }
+
+ /**
+ * Get the context parameters for Apex.
+ *
+ * @param engineParametersJsonObject The input JSON
+ * @param engineParameters The output parameters
+ * @param context the JSON context
+ */
+ private void getContextParameters(final JsonObject engineParametersJsonObject,
+ final EngineParameters engineParameters, final JsonDeserializationContext context) {
+ final JsonElement contextParametersElement = engineParametersJsonObject.get(CONTEXT_PARAMETERS);
+
+ // Context parameters are optional so if the element does not exist, just return
+ if (contextParametersElement == null) {
+ return;
+ }
+
+ // We do this because the JSON parameters may be for a subclass of ContextParameters
+ final ContextParameters contextParameters =
+ (ContextParameters) deserializeParameters(CONTEXT_PARAMETERS, contextParametersElement, context);
+
+ // We know this will work because if the context parameters was not a Json object, the
+ // previous deserializeParameters() call would not have worked
+ final JsonObject contextParametersObject = engineParametersJsonObject.get(CONTEXT_PARAMETERS).getAsJsonObject();
+
+ // Now get the distributor, lock manager, and persistence parameters
+ final JsonElement distributorParametersElement = contextParametersObject.get(DISTRIBUTOR_PARAMETERS);
+ if (distributorParametersElement != null) {
+ contextParameters
+ .setDistributorParameters((DistributorParameters) deserializeParameters(DISTRIBUTOR_PARAMETERS,
+ distributorParametersElement, context));
+ }
+
+ final JsonElement lockManagerParametersElement = contextParametersObject.get(LOCK_MANAGER_PARAMETERS);
+ if (lockManagerParametersElement != null) {
+ contextParameters
+ .setLockManagerParameters((LockManagerParameters) deserializeParameters(LOCK_MANAGER_PARAMETERS,
+ lockManagerParametersElement, context));
+ }
+
+ final JsonElement persistorParametersElement = contextParametersObject.get(PERSISTOR_PARAMETERS);
+ if (persistorParametersElement != null) {
+ contextParameters.setPersistorParameters((PersistorParameters) deserializeParameters(PERSISTOR_PARAMETERS,
+ persistorParametersElement, context));
+ }
+
+ // Schema Handler parameter wrangling
+ getSchemaHandlerParameters(contextParametersObject, contextParameters, context);
+
+ // Get the engine plugin parameters
+ engineParameters.setContextParameters(contextParameters);
+ }
+
+ /**
+ * Get the executor parameters for Apex.
+ *
+ * @param engineParametersJsonObject The input JSON
+ * @param engineParameters The output parameters
+ * @param context the JSON context
+ */
+ private void getExecutorParameters(final JsonObject engineParametersJsonObject,
+ final EngineParameters engineParameters, final JsonDeserializationContext context) {
+ final JsonElement executorParametersElement = engineParametersJsonObject.get(EXECUTOR_PARAMETERS);
+
+ // Executor parameters are mandatory so if the element does not exist throw an exception
+ if (executorParametersElement == null) {
+ final String returnMessage = "no \"" + EXECUTOR_PARAMETERS
+ + "\" entry found in parameters, at least one executor parameter entry must be specified";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ // Deserialize the executor parameters
+ final JsonObject executorParametersJsonObject =
+ engineParametersJsonObject.get(EXECUTOR_PARAMETERS).getAsJsonObject();
+
+ for (final Entry<String, JsonElement> executorEntries : executorParametersJsonObject.entrySet()) {
+ final ExecutorParameters executorParameters =
+ (ExecutorParameters) deserializeParameters(EXECUTOR_PARAMETERS + ':' + executorEntries.getKey(),
+ executorEntries.getValue(), context);
+ engineParameters.getExecutorParameterMap().put(executorEntries.getKey(), executorParameters);
+ }
+ }
+
+ /**
+ * Get the schema parameters for Apex.
+ *
+ * @param contextParametersJsonObject The input JSON
+ * @param contextParameters The output parameters
+ * @param context the JSON context
+ */
+ private void getSchemaHandlerParameters(final JsonObject contextParametersJsonObject,
+ final ContextParameters contextParameters, final JsonDeserializationContext context) {
+ final JsonElement schemaParametersElement = contextParametersJsonObject.get(SCHEMA_PARAMETERS);
+
+ // Insert the default Java schema helper
+ contextParameters.getSchemaParameters().getSchemaHelperParameterMap()
+ .put(SchemaParameters.DEFAULT_SCHEMA_FLAVOUR, new JavaSchemaHelperParameters());
+
+ // Context parameters are optional so if the element does not exist, just return
+ if (schemaParametersElement == null) {
+ return;
+ }
+
+ // Deserialize the executor parameters
+ final JsonObject schemaHelperParametersJsonObject =
+ contextParametersJsonObject.get(SCHEMA_PARAMETERS).getAsJsonObject();
+
+ for (final Entry<String, JsonElement> schemaHelperEntries : schemaHelperParametersJsonObject.entrySet()) {
+ contextParameters.getSchemaParameters().getSchemaHelperParameterMap().put(schemaHelperEntries.getKey(),
+ (SchemaHelperParameters) deserializeParameters(
+ SCHEMA_PARAMETERS + ':' + schemaHelperEntries.getKey(), schemaHelperEntries.getValue(),
+ context));
+ }
+ }
+
+ /**
+ * Deserialize a parameter object that's a superclass of the AbstractParameters class.
+ *
+ * @param parametersLabel Label to use for error messages
+ * @param parametersElement The JSON object holding the parameters
+ * @param context The GSON context
+ * @return the parameters
+ * @throws ApexParameterRuntimeException on errors reading the parameters
+ */
+ private AbstractParameters deserializeParameters(final String parametersLabel, final JsonElement parametersElement,
+ final JsonDeserializationContext context) throws ApexParameterRuntimeException {
+ JsonObject parametersObject = null;
+
+ // Check that the JSON element is a JSON object
+ if (parametersElement.isJsonObject()) {
+ parametersObject = parametersElement.getAsJsonObject();
+ } else {
+ final String returnMessage = "value of \"" + parametersLabel + "\" entry is not a parameter JSON object";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ // Get the parameter class name for instantiation in deserialization
+ final JsonElement parameterClassNameElement = parametersObject.get(PARAMETER_CLASS_NAME);
+ if (parameterClassNameElement == null) {
+ final String returnMessage =
+ "could not find field \"" + PARAMETER_CLASS_NAME + "\" in \"" + parametersLabel + "\" entry";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ // Check the parameter is a JSON primitive
+ if (!parameterClassNameElement.isJsonPrimitive()) {
+ final String returnMessage = "value for field \"" + PARAMETER_CLASS_NAME + "\" in \"" + parametersLabel
+ + "\" entry is not a plain string";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ // Check the parameter has a value
+ final String parameterClassName = parameterClassNameElement.getAsString();
+ if (parameterClassName == null || parameterClassName.trim().length() == 0) {
+ final String returnMessage = "value for field \"" + PARAMETER_CLASS_NAME + "\" in \"" + parametersLabel
+ + "\" entry is not specified or is blank";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ // Deserialize the parameters using GSON
+ AbstractParameters parameters = null;
+ try {
+ parameters = context.deserialize(parametersObject, Class.forName(parameterClassName));
+ } catch (JsonParseException | ClassNotFoundException e) {
+ final String returnMessage =
+ "failed to deserialize the parameters for \"" + parametersLabel + "\" " + "to parameter class \""
+ + parameterClassName + "\"\n" + e.getClass().getCanonicalName() + ": " + e.getMessage();
+ LOGGER.error(returnMessage, e);
+ throw new ApexParameterRuntimeException(returnMessage, e);
+ }
+
+ return parameters;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/package-info.java
new file mode 100644
index 000000000..e724ce41c
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/engineservice/package-info.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Defines the parameters for the APEX Engine Service and for engines running in the engine service.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.parameters.engineservice;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerParameters.java
new file mode 100644
index 000000000..34589f31b
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerParameters.java
@@ -0,0 +1,362 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.eventhandler;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.onap.policy.apex.model.basicmodel.service.AbstractParameters;
+import org.onap.policy.apex.service.parameters.ApexParameterValidator;
+import org.onap.policy.apex.service.parameters.carriertechnology.CarrierTechnologyParameters;
+import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
+
+/**
+ * The parameters for a single event producer, event consumer or synchronous event handler.
+ * <p>
+ * Event producers, consumers, and synchronous event handlers all use a carrier technology and an
+ * event protocol so the actual parameters for each one are the same. Therefore, we use the same
+ * class for the parameters of each one.
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>carrierTechnologyParameters: The carrier technology is the type of messaging infrastructure
+ * used to carry events. Examples are File, Kafka or REST.
+ * <li>eventProtocolParameters: The format that the events are in when being carried. Examples are
+ * JSON, XML, or Java Beans. carrier technology
+ * <li>synchronousMode: true if the event handler is working in synchronous mode, defaults to false
+ * <li>synchronousPeer: the peer event handler (consumer for producer or producer for consumer) of
+ * this event handler in synchronous mode
+ * <li>synchronousTimeout: the amount of time to wait for the reply to synchronous events before
+ * they are timed out
+ * <li>requestorMode: true if the event handler is working in requestor mode, defaults to false
+ * <li>requestorPeer: the peer event handler (consumer for producer or producer for consumer) of
+ * this event handler in requestor mode
+ * <li>requestorTimeout: the amount of time to wait for the reply to synchronous events before they
+ * are timed out
+ * <li>eventNameFilter: a regular expression to apply to events on this event handler. If specified,
+ * events not matching the given regular expression are ignored. If it is null, all events are
+ * handledDefaults to null.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EventHandlerParameters extends AbstractParameters implements ApexParameterValidator {
+ private String name = null;
+ private CarrierTechnologyParameters carrierTechnologyParameters = null;
+ private EventProtocolParameters eventProtocolParameters = null;
+ private boolean synchronousMode = false;
+ private String synchronousPeer = null;
+ private long synchronousTimeout = 0;
+ private boolean requestorMode = false;
+ private String requestorPeer = null;
+ private long requestorTimeout = 0;
+ private String eventName = null;
+ private String eventNameFilter = null;
+
+ /**
+ * Constructor to create an event handler parameters instance.
+ */
+ public EventHandlerParameters() {
+ super(EventHandlerParameters.class.getCanonicalName());
+ }
+
+ /**
+ * Constructor to create an event handler parameters instance with the name of a sub class of
+ * this class.
+ *
+ * @param parameterClassName the class name of a sub class of this class
+ */
+ public EventHandlerParameters(final String parameterClassName) {
+ super(parameterClassName);
+ }
+
+ /**
+ * Gets the name of the event handler.
+ *
+ * @return the event handler name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the event handler.
+ *
+ * @param name the event handler name
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * Checks if the name of the event handler is set.
+ *
+ * @return true if the name is set
+ */
+ public boolean checkSetName() {
+ return !(name == null || name.trim().length() == 0);
+ }
+
+ /**
+ * Gets the carrier technology parameters of the event handler.
+ *
+ * @return the carrierTechnologyParameters of the event handler
+ */
+ public CarrierTechnologyParameters getCarrierTechnologyParameters() {
+ return carrierTechnologyParameters;
+ }
+
+ /**
+ * Sets the carrier technology parameters of the event handler.
+ *
+ * @param carrierTechnologyParameters the carrierTechnologyParameters to set
+ */
+ public void setCarrierTechnologyParameters(final CarrierTechnologyParameters carrierTechnologyParameters) {
+ this.carrierTechnologyParameters = carrierTechnologyParameters;
+ }
+
+ /**
+ * Gets the event protocol parameters of the event handler.
+ *
+ * @return the eventProtocolParameters
+ */
+ public EventProtocolParameters getEventProtocolParameters() {
+ return eventProtocolParameters;
+ }
+
+ /**
+ * Sets the event protocol parameters.
+ *
+ * @param eventProtocolParameters the eventProtocolParameters to set
+ */
+ public void setEventProtocolParameters(final EventProtocolParameters eventProtocolParameters) {
+ this.eventProtocolParameters = eventProtocolParameters;
+ }
+
+
+ /**
+ * Checks if the event handler is in the given peered mode.
+ *
+ * @param peeredMode the peer mode
+ * @return true, if the event handler is in the peered mode
+ */
+ public boolean isPeeredMode(final EventHandlerPeeredMode peeredMode) {
+ switch (peeredMode) {
+ case SYNCHRONOUS:
+ return synchronousMode;
+ case REQUESTOR:
+ return requestorMode;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Sets a peered mode as true or false on the event handler.
+ *
+ * @param peeredMode the peered mode to set
+ * @param peeredModeValue the value to set the peered mode to
+ */
+ public void setPeeredMode(final EventHandlerPeeredMode peeredMode, final boolean peeredModeValue) {
+ switch (peeredMode) {
+ case SYNCHRONOUS:
+ synchronousMode = peeredModeValue;
+ return;
+ case REQUESTOR:
+ requestorMode = peeredModeValue;
+ return;
+ default:
+ return;
+ }
+ }
+
+ /**
+ * Gets the peer for the event handler in this peered mode.
+ *
+ * @param peeredMode the peered mode to get the peer for
+ * @return the peer
+ */
+ public String getPeer(final EventHandlerPeeredMode peeredMode) {
+ switch (peeredMode) {
+ case SYNCHRONOUS:
+ return synchronousPeer;
+ case REQUESTOR:
+ return requestorPeer;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Sets the peer for the event handler in this peered mode.
+ *
+ * @param peeredMode the peered mode to set the peer for
+ * @param peer the peer
+ */
+ public void setPeer(final EventHandlerPeeredMode peeredMode, final String peer) {
+ switch (peeredMode) {
+ case SYNCHRONOUS:
+ synchronousPeer = peer;
+ return;
+ case REQUESTOR:
+ requestorPeer = peer;
+ return;
+ default:
+ return;
+ }
+ }
+
+ /**
+ * Get the timeout value for the event handler in peered mode.
+ *
+ * @param peeredMode the peered mode to get the timeout for
+ * @return the timeout value
+ */
+ public long getPeerTimeout(final EventHandlerPeeredMode peeredMode) {
+ switch (peeredMode) {
+ case SYNCHRONOUS:
+ return synchronousTimeout;
+ case REQUESTOR:
+ return requestorTimeout;
+ default:
+ return -1;
+ }
+ }
+
+ /**
+ * Set the timeout value for the event handler in peered mode.
+ *
+ * @param peeredMode the peered mode to set the timeout for
+ * @param timeout the timeout value
+ */
+ public void setPeerTimeout(final EventHandlerPeeredMode peeredMode, final long timeout) {
+ switch (peeredMode) {
+ case SYNCHRONOUS:
+ synchronousTimeout = timeout;
+ return;
+ case REQUESTOR:
+ requestorTimeout = timeout;
+ return;
+ default:
+ return;
+ }
+ }
+
+ /**
+ * Check if an event name is being used.
+ *
+ * @return true if an event name is being used
+ */
+ public boolean isSetEventName() {
+ return eventName != null;
+ }
+
+ /**
+ * Gets the event name for this event handler.
+ *
+ * @return the event name
+ */
+ public String getEventName() {
+ return eventName;
+ }
+
+ /**
+ * Sets the event name for this event handler.
+ *
+ * @param eventName the event name
+ */
+ public void setEventName(final String eventName) {
+ this.eventName = eventName;
+ }
+
+ /**
+ * Check if event name filtering is being used.
+ *
+ * @return true if event name filtering is being used
+ */
+ public boolean isSetEventNameFilter() {
+ return eventNameFilter != null;
+ }
+
+ /**
+ * Gets the event name filter for this event handler.
+ *
+ * @return the event name filter
+ */
+ public String getEventNameFilter() {
+ return eventNameFilter;
+ }
+
+ /**
+ * Sets the event name filter for this event handler.
+ *
+ * @param eventNameFilter the event name filter
+ */
+ public void setEventNameFilter(final String eventNameFilter) {
+ this.eventNameFilter = eventNameFilter;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ if (eventProtocolParameters == null) {
+ errorMessageBuilder.append(" event handler eventProtocolParameters not specified or blank\n");
+ } else {
+ errorMessageBuilder.append(eventProtocolParameters.validate());
+ }
+
+ if (carrierTechnologyParameters == null) {
+ errorMessageBuilder.append(" event handler carrierTechnologyParameters not specified or blank\n");
+ } else {
+ errorMessageBuilder.append(carrierTechnologyParameters.validate());
+ }
+
+ if (eventNameFilter != null) {
+ try {
+ Pattern.compile(eventNameFilter);
+ } catch (final PatternSyntaxException pse) {
+ errorMessageBuilder.append(" event handler eventNameFilter is not a valid regular expression: "
+ + pse.getMessage() + "\n");
+ }
+ }
+ return errorMessageBuilder.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "EventHandlerParameters [name=" + name + ", carrierTechnologyParameters=" + carrierTechnologyParameters
+ + ", eventProtocolParameters=" + eventProtocolParameters + ", synchronousMode=" + synchronousMode
+ + ", synchronousPeer=" + synchronousPeer + ", synchronousTimeout=" + synchronousTimeout
+ + ", requestorMode=" + requestorMode + ", requestorPeer=" + requestorPeer + ", requestorTimeout="
+ + requestorTimeout + ", eventName=" + eventName + ", eventNameFilter=" + eventNameFilter + "]";
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerPeeredMode.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerPeeredMode.java
new file mode 100644
index 000000000..b7ee667f3
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/EventHandlerPeeredMode.java
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.eventhandler;
+
+/**
+ * This enum specifies the peered mode that an event handler may be in.
+ *
+ * <p>
+ * The following values are defined:
+ * <ol>
+ * <li>SYNCHRONOUS: The event handler is tied to another event handler for event handling in APEX,
+ * used for request-response calls where APEX is the receiver.
+ * <li>REQUESTOR: The event handler is tied another event handler for event handling in APEX, used
+ * for request-response calls where APEX is the sender.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ *
+ * @author liam.fallon@ericsson.com
+ *
+ */
+public enum EventHandlerPeeredMode {
+ SYNCHRONOUS, REQUESTOR
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/package-info.java
new file mode 100644
index 000000000..2866358ff
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventhandler/package-info.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Defines the structure of producer parameters for APEX.
+ *
+ * @author John Keeney (john.keeney@ericsson.com)
+ */
+package org.onap.policy.apex.service.parameters.eventhandler;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParameters.java
new file mode 100644
index 000000000..6e66a18e9
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParameters.java
@@ -0,0 +1,123 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.eventprotocol;
+
+import org.onap.policy.apex.model.basicmodel.service.AbstractParameters;
+import org.onap.policy.apex.service.parameters.ApexParameterValidator;
+
+/**
+ * A default event protocol parameter class that may be specialized by event protocol plugins that
+ * require plugin specific parameters.
+ *
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>label: The label of the event protocol technology.
+ * <li>eventProducerPluginClass: The name of the plugin class that will be used by Apex to produce
+ * and emit output events for this carrier technology
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class EventProtocolParameters extends AbstractParameters implements ApexParameterValidator {
+ // The event protocol label
+ private String label = null;
+
+ // Event protocol converter plugin class for this event protocol
+ private String eventProtocolPluginClass;
+
+ /**
+ * Constructor to create an event protocol parameters instance with the name of a sub class of
+ * this class and register the instance with the parameter service.
+ *
+ * @param parameterClassName the class name of a sub class of this class
+ */
+ public EventProtocolParameters(final String parameterClassName) {
+ super(parameterClassName);
+ }
+
+ /**
+ * Gets the label of the event protocol.
+ *
+ * @return the label of the event protocol
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Sets the label of the event protocol.
+ *
+ * @param label the label of the event protocol
+ */
+ public void setLabel(final String label) {
+ this.label = label.replaceAll("\\s+", "");
+ }
+
+ /**
+ * Gets the event event protocol plugin class.
+ *
+ * @return the event event protocol plugin class
+ */
+ public String getEventProtocolPluginClass() {
+ return eventProtocolPluginClass;
+ }
+
+ /**
+ * Sets the event event protocol plugin class.
+ *
+ * @param eventProtocolPluginClass the event event protocol plugin class
+ */
+ public void setEventProtocolPluginClass(final String eventProtocolPluginClass) {
+ this.eventProtocolPluginClass = eventProtocolPluginClass.replaceAll("\\s+", "");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.model.basicmodel.service.AbstractParameters#toString()
+ */
+ @Override
+ public String toString() {
+ return "CarrierTechnologyParameters [label=" + label + ", EventProtocolPluginClass=" + eventProtocolPluginClass
+ + "]";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ if (label == null || label.length() == 0) {
+ errorMessageBuilder.append(" event protocol label not specified or is blank\n");
+ }
+
+ if (eventProtocolPluginClass == null || eventProtocolPluginClass.length() == 0) {
+ errorMessageBuilder.append(" event protocol eventProtocolPluginClass not specified or is blank\n");
+ }
+
+ return errorMessageBuilder.toString();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParametersJSONAdapter.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParametersJSONAdapter.java
new file mode 100644
index 000000000..c880756b3
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolParametersJSONAdapter.java
@@ -0,0 +1,172 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.eventprotocol;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.onap.policy.apex.service.engine.event.impl.apexprotocolplugin.ApexEventProtocolParameters;
+import org.onap.policy.apex.service.engine.event.impl.jsonprotocolplugin.JSONEventProtocolParameters;
+import org.onap.policy.apex.service.parameters.ApexParameterRuntimeException;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * This class serialises and deserialises various type of event protocol parameters to and from
+ * JSON.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public class EventProtocolParametersJSONAdapter
+ implements JsonSerializer<EventProtocolParameters>, JsonDeserializer<EventProtocolParameters> {
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(EventProtocolParametersJSONAdapter.class);
+
+ private static final String PARAMETER_CLASS_NAME = "parameterClassName";
+
+ private static final String EVENT_PROTOCOL_TOKEN = "eventProtocol";
+ private static final String EVENT_PROTOCOL_PARAMETERS = "parameters";
+
+ // Built in event protocol parameters
+ private static final Map<String, String> BUILT_IN_EVENT_RPOTOCOL_PARMETER_CLASS_MAP = new HashMap<>();
+ static {
+ BUILT_IN_EVENT_RPOTOCOL_PARMETER_CLASS_MAP.put("JSON", JSONEventProtocolParameters.class.getCanonicalName());
+ BUILT_IN_EVENT_RPOTOCOL_PARMETER_CLASS_MAP.put("APEX", ApexEventProtocolParameters.class.getCanonicalName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.google.gson.JsonSerializer#serialize(java.lang.Object, java.lang.reflect.Type,
+ * com.google.gson.JsonSerializationContext)
+ */
+ @Override
+ public JsonElement serialize(final EventProtocolParameters src, final Type typeOfSrc,
+ final JsonSerializationContext context) {
+ final String returnMessage = "serialization of Apex event protocol parameters to Json is not supported";
+ LOGGER.error(returnMessage);
+ throw new ApexParameterRuntimeException(returnMessage);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.google.gson.JsonDeserializer#deserialize(com.google.gson.JsonElement,
+ * java.lang.reflect.Type, com.google.gson.JsonDeserializationContext)
+ */
+ @Override
+ public EventProtocolParameters deserialize(final JsonElement json, final Type typeOfT,
+ final JsonDeserializationContext context) throws JsonParseException {
+ final JsonObject jsonObject = json.getAsJsonObject();
+
+ // Get the event protocol label primitive
+ final JsonPrimitive labelJsonPrimitive = (JsonPrimitive) jsonObject.get(EVENT_PROTOCOL_TOKEN);
+
+ // Check if we found our event protocol
+ if (labelJsonPrimitive == null) {
+ LOGGER.warn("event protocol parameter \"" + EVENT_PROTOCOL_TOKEN + "\" not found in JSON file");
+ return null;
+ }
+
+ // Get and check the event protocol label
+ final String eventProtocolLabel = labelJsonPrimitive.getAsString().replaceAll("\\s+", "");
+ if (eventProtocolLabel == null || eventProtocolLabel.length() == 0) {
+ final String errorMessage = "event protocol parameter \"" + EVENT_PROTOCOL_TOKEN + "\" value \""
+ + labelJsonPrimitive.getAsString() + "\" invalid in JSON file";
+ LOGGER.warn(errorMessage);
+ throw new ApexParameterRuntimeException(errorMessage);
+ }
+
+ // We now get the event protocol parameter class
+ String eventProtocolParameterClassName = null;
+
+ // Get the event protocol parameter class for the event protocol plugin class from the
+ // configuration parameters
+ final JsonPrimitive classNameJsonPrimitive = (JsonPrimitive) jsonObject.get(PARAMETER_CLASS_NAME);
+
+ // If no event protocol parameter class was specified, we use the default
+ if (classNameJsonPrimitive == null) {
+ eventProtocolParameterClassName = BUILT_IN_EVENT_RPOTOCOL_PARMETER_CLASS_MAP.get(eventProtocolLabel);
+ } else {
+ // We use the specified one
+ eventProtocolParameterClassName = classNameJsonPrimitive.getAsString().replaceAll("\\s+", "");
+ }
+
+ // Check the event protocol parameter class
+ if (eventProtocolParameterClassName == null || eventProtocolParameterClassName.length() == 0) {
+ final String errorMessage =
+ "event protocol \"" + eventProtocolLabel + "\" parameter \"" + PARAMETER_CLASS_NAME + "\" value \""
+ + classNameJsonPrimitive.getAsString() + "\" invalid in JSON file";
+ LOGGER.warn(errorMessage);
+ throw new ApexParameterRuntimeException(errorMessage);
+ }
+
+ // Get the class for the event protocol
+ Class<?> eventProtocolParameterClass = null;
+ try {
+ eventProtocolParameterClass = Class.forName(eventProtocolParameterClassName);
+ } catch (final ClassNotFoundException e) {
+ final String errorMessage =
+ "event protocol \"" + eventProtocolLabel + "\" parameter \"" + PARAMETER_CLASS_NAME + "\" value \""
+ + eventProtocolParameterClassName + "\", could not find class";
+ LOGGER.warn(errorMessage, e);
+ throw new ApexParameterRuntimeException(errorMessage, e);
+ }
+
+ // Deserialise the class
+ EventProtocolParameters eventProtocolParameters =
+ context.deserialize(jsonObject.get(EVENT_PROTOCOL_PARAMETERS), eventProtocolParameterClass);
+ if (eventProtocolParameters == null) {
+ // OK no parameters for the event protocol have been specified, just instantiate the
+ // default parameters
+ try {
+ eventProtocolParameters = (EventProtocolParameters) eventProtocolParameterClass.newInstance();
+ } catch (final Exception e) {
+ final String errorMessage = "could not create default parameters for event protocol \""
+ + eventProtocolLabel + "\"\n" + e.getMessage();
+ LOGGER.warn(errorMessage, e);
+ throw new ApexParameterRuntimeException(errorMessage, e);
+ }
+ }
+
+ // Check that the event protocol label matches the label in the event protocol parameters
+ // object
+ if (!eventProtocolParameters.getLabel().equals(eventProtocolLabel)) {
+ final String errorMessage = "event protocol \"" + eventProtocolLabel + "\" does not match plugin \""
+ + eventProtocolParameters.getLabel() + "\" in \"" + eventProtocolParameterClassName
+ + "\", specify correct event protocol parameter plugin in parameter \"" + PARAMETER_CLASS_NAME
+ + "\"";
+ LOGGER.warn(errorMessage);
+ throw new ApexParameterRuntimeException(errorMessage);
+ }
+
+ return eventProtocolParameters;
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextCharDelimitedParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextCharDelimitedParameters.java
new file mode 100644
index 000000000..f8873ada4
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextCharDelimitedParameters.java
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.eventprotocol;
+
+import org.onap.policy.apex.service.parameters.ApexParameterValidator;
+
+/**
+ * An event protocol parameter class for character delimited textual event protocols that may be
+ * specialized by event protocol plugins that require plugin specific parameters.
+ *
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>startChar: starting character delimiter for text blocks containing an event.
+ * <li>endChar: ending character delimiter for text blocks containing an event.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class EventProtocolTextCharDelimitedParameters extends EventProtocolParameters
+ implements ApexParameterValidator {
+ // The starting and ending character delimiter
+ private char startChar = '\0';
+ private char endChar = '\0';
+
+ /**
+ * Constructor to create an event protocol parameters instance with the name of a sub class of
+ * this class.
+ *
+ * @param parameterClassName the class name of a sub class of this class
+ */
+ public EventProtocolTextCharDelimitedParameters(final String parameterClassName) {
+ super(parameterClassName);
+ }
+
+ /**
+ * Gets the start character that delimits the start of text blocks.
+ *
+ * @return the start char
+ */
+ public char getStartChar() {
+ return startChar;
+ }
+
+ /**
+ * Sets the start character that delimits the start of text blocks.
+ *
+ * @param startChar the start character
+ */
+ public void setStartChar(final char startChar) {
+ this.startChar = startChar;
+ }
+
+ /**
+ * Gets the end character that delimits the end of text blocks.
+ *
+ * @return the end character
+ */
+ public char getEndChar() {
+ return endChar;
+ }
+
+ /**
+ * Sets the end character that delimits the end of text blocks.
+ *
+ * @param endChar the end character
+ */
+ public void setEndChar(final char endChar) {
+ this.endChar = endChar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters#toString()
+ */
+ @Override
+ public String toString() {
+ return "EventProtocolTextCharDelimitedParameters {" + super.toString() + "} [startChar=" + startChar
+ + ", endChar=" + endChar + "]";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ errorMessageBuilder.append(super.validate());
+
+ if (startChar == '\0') {
+ errorMessageBuilder.append(" text character delimited start character has not been specified\n");
+ }
+
+ if (endChar == '\0') {
+ errorMessageBuilder.append(" text character delimited end character has not been specified\n");
+ }
+
+ return errorMessageBuilder.toString();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextTokenDelimitedParameters.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextTokenDelimitedParameters.java
new file mode 100644
index 000000000..37fbd32bf
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/EventProtocolTextTokenDelimitedParameters.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.service.parameters.eventprotocol;
+
+import org.onap.policy.apex.service.parameters.ApexParameterValidator;
+
+/**
+ * An event protocol parameter class for token delimited textual event protocols that may be
+ * specialized by event protocol plugins that require plugin specific parameters.
+ *
+ * <p>
+ * The following parameters are defined:
+ * <ol>
+ * <li>delimiterToken: the token string that delimits text blocks that contain events.
+ * </ol>
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public abstract class EventProtocolTextTokenDelimitedParameters extends EventProtocolParameters
+ implements ApexParameterValidator {
+ // The delimiter token for text blocks
+ private String delimiterToken = null;
+
+ /**
+ * Constructor to create an event protocol parameters instance with the name of a sub class of
+ * this class.
+ *
+ * @param parameterClassName the class name of a sub class of this class
+ */
+ public EventProtocolTextTokenDelimitedParameters(final String parameterClassName) {
+ super(parameterClassName);
+ }
+
+ /**
+ * Gets the delimiter token that delimits events in the text.
+ *
+ * @return the delimiter token
+ */
+ public String getDelimiterToken() {
+ return delimiterToken;
+ }
+
+
+ /**
+ * Sets the delimiter token that delimits events in the text.
+ *
+ * @param delimiterToken the delimiter token
+ */
+ public void setDelimiterToken(final String delimiterToken) {
+ this.delimiterToken = delimiterToken;
+ }
+
+
+ @Override
+ public String toString() {
+ return "EventProtocolTextCharDelimitedParameters {" + super.toString() + "} [delimiterToken=" + delimiterToken
+ + "]";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.onap.policy.apex.service.parameters.ApexParameterValidator#validate()
+ */
+ @Override
+ public String validate() {
+ final StringBuilder errorMessageBuilder = new StringBuilder();
+
+ errorMessageBuilder.append(super.validate());
+
+ if (delimiterToken == null || delimiterToken.length() == 0) {
+ errorMessageBuilder.append(" text delimiter token not specified or is blank\n");
+ }
+
+ return errorMessageBuilder.toString();
+ }
+}
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/package-info.java
new file mode 100644
index 000000000..967198a62
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/eventprotocol/package-info.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Defines the structure of event protocol parameters for APEX.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.parameters.eventprotocol;
diff --git a/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/package-info.java b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/package-info.java
new file mode 100644
index 000000000..2c6473776
--- /dev/null
+++ b/services/services-engine/src/main/java/org/onap/policy/apex/service/parameters/package-info.java
@@ -0,0 +1,29 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Implements parameter handling for all parameters in APEX. It uses specializations of (@link
+ * {@link org.onap.policy.apex.model.basicmodel.service.AbstractParameters} for all parameters and
+ * works with {@link org.onap.policy.apex.model.basicmodel.service.ParameterService} for storing and
+ * finding parameters.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+package org.onap.policy.apex.service.parameters;
diff --git a/services/services-engine/src/main/resources/version.txt b/services/services-engine/src/main/resources/version.txt
new file mode 100644
index 000000000..f1ce55824
--- /dev/null
+++ b/services/services-engine/src/main/resources/version.txt
@@ -0,0 +1,4 @@
+Apex Adaptive Policy Engine
+Version: ${project.version}
+Built (UTC): ${timestamp}
+ONAP https://wiki.onap.org \ No newline at end of file