Refactor Editor REST servlet 89/67789/3
authorliamfallon <liam.fallon@ericsson.com>
Wed, 19 Sep 2018 16:23:48 +0000 (17:23 +0100)
committerliamfallon <liam.fallon@ericsson.com>
Thu, 20 Sep 2018 11:26:57 +0000 (12:26 +0100)
Issue-ID: POLICY-1034
Change-Id: Ifa08c7a31b4fe19eb62c2035b67b6f5cad313b5f
Signed-off-by: liamfallon <liam.fallon@ericsson.com>
38 files changed:
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/ApexEditorRestResource.java [deleted file]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ApexEditorRestResource.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ContextAlbumHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ContextSchemaHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/EventHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/KeyInfoHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ModelHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/PolicyHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommand.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommandHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommandType.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestSession.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestSessionHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestUtils.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/RestUtils.java with 98% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/TaskHandler.java [new file with mode: 0644]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanBase.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanBase.java with 97% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanContextAlbum.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanContextAlbum.java with 97% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanContextSchema.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanContextSchema.java with 97% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanEvent.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanEvent.java with 98% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanField.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanField.java with 96% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanKeyRef.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanKeyRef.java with 96% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanLogic.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanLogic.java with 96% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanModel.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanModel.java with 96% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanPolicy.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanPolicy.java with 97% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanState.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanState.java with 98% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanStateOutput.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanStateOutput.java with 96% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanStateTaskRef.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanStateTaskRef.java with 96% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanTask.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanTask.java with 98% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanTaskParameter.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/BeanTaskParameter.java with 96% similarity]
client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/bean/package-info.java [moved from client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/bean/package-info.java with 94% similarity]
client/client-editor/src/main/resources/templates/PeriodicEventTemplate.json [new file with mode: 0644]
client/client-editor/src/test/java/org/onap/policy/apex/client/editor/rest/handling/TestApexEditorRestResource.java [moved from client/client-editor/src/test/java/org/onap/policy/apex/client/editor/rest/TestApexEditorRestResource.java with 98% similarity]
client/client-editor/src/test/java/org/onap/policy/apex/client/editor/rest/handling/bean/BeanFake.java [moved from client/client-editor/src/test/java/org/onap/policy/apex/client/editor/rest/bean/BeanFake.java with 95% similarity]
client/client-editor/src/test/java/org/onap/policy/apex/client/editor/rest/handling/bean/TestBeans.java [moved from client/client-editor/src/test/java/org/onap/policy/apex/client/editor/rest/bean/TestBeans.java with 98% similarity]
testsuites/integration/integration-executor-test/src/test/java/org/onap/policy/apex/testsuites/integration/executor/engine/TestApexEngineJava.java
testsuites/integration/integration-executor-test/src/test/java/org/onap/policy/apex/testsuites/integration/executor/engine/TestApexEngineJavascript.java
testsuites/integration/integration-executor-test/src/test/java/org/onap/policy/apex/testsuites/integration/executor/engine/TestApexEngineJython.java
testsuites/integration/integration-executor-test/src/test/java/org/onap/policy/apex/testsuites/integration/executor/engine/TestApexEngineMvel.java

diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/ApexEditorRestResource.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/ApexEditorRestResource.java
deleted file mode 100644 (file)
index fed1a50..0000000
+++ /dev/null
@@ -1,2038 +0,0 @@
-/*-
- * ============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.client.editor.rest;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-
-import org.onap.policy.apex.client.editor.rest.bean.BeanContextAlbum;
-import org.onap.policy.apex.client.editor.rest.bean.BeanContextSchema;
-import org.onap.policy.apex.client.editor.rest.bean.BeanEvent;
-import org.onap.policy.apex.client.editor.rest.bean.BeanField;
-import org.onap.policy.apex.client.editor.rest.bean.BeanKeyRef;
-import org.onap.policy.apex.client.editor.rest.bean.BeanLogic;
-import org.onap.policy.apex.client.editor.rest.bean.BeanModel;
-import org.onap.policy.apex.client.editor.rest.bean.BeanPolicy;
-import org.onap.policy.apex.client.editor.rest.bean.BeanState;
-import org.onap.policy.apex.client.editor.rest.bean.BeanStateOutput;
-import org.onap.policy.apex.client.editor.rest.bean.BeanStateTaskRef;
-import org.onap.policy.apex.client.editor.rest.bean.BeanTask;
-import org.onap.policy.apex.client.editor.rest.bean.BeanTaskParameter;
-import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
-import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
-import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
-import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
-import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
-import org.onap.policy.apex.model.modelapi.ApexApiResult;
-import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
-import org.onap.policy.apex.model.modelapi.ApexModel;
-import org.onap.policy.apex.model.modelapi.ApexModelFactory;
-import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
-import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
-import org.onap.policy.apex.model.policymodel.concepts.AxTask;
-import org.slf4j.ext.XLogger;
-import org.slf4j.ext.XLoggerFactory;
-
-/**
- * The class represents the root resource exposed at the base URL<br> The url to access this resource would be in the
- * form {@code <baseURL>/rest/<session>/....} <br> For example: a PUT request to the following URL
- * {@code http://localhost:8080/apex/rest/109/ContextSchema/Update}, with a JSON string payload containing the new
- * {@code Schema} in the body, can be explained as: <ul> <li>The server or servlet is running at the base URL
- * {@code http://localhost:8080/apex} <li>This resource {@code ApexRestEditorResource} is used because the path
- * {@code rest/109} matches the {@code Path} filter specification for this Resource ({@code @Path("rest/{session}")}),
- * where the {@code int} path parameter {@code session} is assigned the {@code int} value {@code 109} <li>The path
- * {@code ContextSchema/Update} redirects this call to the method {@link #updateContextSchema(String)}, which should be
- * a {@link javax.ws.rs.PUT}, with a single String in the body/payload which gets mapped to the single String parameter
- * for the method. <li>So, in summary, the REST request updates a {@code ContextSchema} as specified in the payload for
- * {@code session} number {@code 109} </ul>
- *
- * <b>Note:</b> An allocated {@code Session} identifier must be included in (almost) all requests. Models for different
- * {@code Session} identifiers are completely isolated from one another.
- *
- * <b>Note:</b> To create a new {@code Session}, and have a new session ID allocated use {@link javax.ws.rs.GET} request
- * to {@code <baseURL>/rest/-1/Session/Create} (for example: {@code http://localhost:8080/apex/rest/-1/Session/Create} )
- *
- */
-@Path("editor/{session}")
-@Produces(
-    { MediaType.APPLICATION_JSON })
-@Consumes(
-    { MediaType.APPLICATION_JSON })
-
-public class ApexEditorRestResource {
-    // Get a reference to the logger
-    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexEditorRestResource.class);
-
-    // Recurring string constants
-    private static final String IN_TASK = "\" in task ";
-    private static final String POLICY_STATE_CREATED_OTHER_ERROR =
-                    "\". The policy and state were created, but there was an error adding the";
-    private static final String IN_STATE = "\" in state \"";
-    private static final String POLICY_CREATED_STATE_ERROR =
-                    "\". The policy was created, but there was an error adding the state.";
-    private static final String FOR_POLICY = "\" for policy \"";
-    private static final String NOT_OK = ": Not OK";
-    private static final String TASK_PARTIALLY_DEFINED = " The task has only been partially defined.";
-    private static final String POLICY_PARTIALLY_DEFINED = " The policy has only been partially defined.";
-    private static final String POLICY_WAS_CREATED = "\". The policy was created, ";
-    private static final String VERSION = "version";
-    private static final String POLICY_KEY = "policyKey";
-    private static final String DESCRIPTION = "description";
-    private static final String APEX_KEY_INFO = "apexKeyInfo";
-
-    // The next session will have this number, stating at 0
-    private static int nextSession = 0;
-
-    // All REST editor sessions being handled by the server
-    private static final Map<Integer, ApexModel> SESSIONMODELMAP = new TreeMap<>();
-
-    // The ID of this session. This gets injected from the URL.
-    @PathParam("session")
-    private int sessionId = -1;
-
-    // The Apex model for the session
-    private ApexModel sessionApexModel = null;
-
-    /**
-     * This method sets the Apex model for the current editor session. Don't forget to call {@link #commitChanges()}
-     * when finished! This makes requests atomic.
-     *
-     * @return the result of finding the session Apex model and setting it
-     */
-    private ApexApiResult initialiseSessionForChanges() {
-        if (sessionId < 0) {
-            return new ApexApiResult(Result.FAILED, "Session ID  \"" + sessionId + "\" is negative");
-        }
-
-        if (!SESSIONMODELMAP.containsKey(sessionId)) {
-            return new ApexApiResult(Result.FAILED, "A session with session ID \"" + sessionId + "\" does not exist");
-        }
-
-        if (sessionApexModel == null) {
-            sessionApexModel = SESSIONMODELMAP.get(sessionId).clone();
-        }
-        return new ApexApiResult();
-    }
-
-    /**
-     * This method sets the Apex model for the current editor session. Don't make any changes to the model.
-     *
-     * @return the result of finding the session Apex model and setting it
-     */
-    private ApexApiResult initialiseSessionForReadOnly() {
-        if (sessionId < 0) {
-            return new ApexApiResult(Result.FAILED, "Session ID  \"" + sessionId + "\" is negative");
-        }
-
-        if (!SESSIONMODELMAP.containsKey(sessionId)) {
-            return new ApexApiResult(Result.FAILED, "A session with session ID \"" + sessionId + "\" does not exist");
-        }
-
-        if (sessionApexModel == null) {
-            sessionApexModel = SESSIONMODELMAP.get(sessionId);
-        }
-        return new ApexApiResult();
-    }
-
-    /**
-     * This method commits changes to the Apex model for the current editor session. This should only be called once, at
-     * the end of a successful change to the model for this session
-     *
-     * @return the result of committing the session Apex model
-     */
-    private ApexApiResult commitChanges() {
-
-        if (sessionApexModel == null) {
-            return new ApexApiResult(Result.FAILED, "Cannot commit a changes for Session ID  \"" + sessionId
-                            + "\", because it has not been initialised / started");
-        }
-
-        SESSIONMODELMAP.put(sessionId, sessionApexModel);
-
-        return new ApexApiResult();
-    }
-
-    /**
-     * Creates a new session. Always call this method with sessionID -1, whereby a new sessionID will be allocated. If
-     * successful the new sessionID will be available in the first message in the result.
-     *
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}. This includes the session id
-     *         for this session.
-     */
-    @GET
-    @Path("Session/Create")
-    public ApexApiResult createSession() {
-        ApexApiResult ret = null;
-        LOGGER.entry();
-        try {
-            if (sessionId != -1) {
-                ret = new ApexApiResult(Result.FAILED, "Session ID must be set to -1 to create sessions: " + sessionId);
-                return ret;
-            }
-
-            final int newSessionId = nextSession;
-
-            if (SESSIONMODELMAP.containsKey(newSessionId)) {
-                ret = new ApexApiResult(Result.FAILED, "Session already exists for session: " + newSessionId);
-                return ret;
-            }
-
-            SESSIONMODELMAP.put(newSessionId, new ApexModelFactory().createApexModel(null, true));
-            incrementNextSession();
-
-            ret = new ApexApiResult(Result.SUCCESS, Integer.toString(newSessionId));
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            String result = "Session/Create" + (ret != null && ret.isOk() ? ": OK" : NOT_OK);
-            LOGGER.exit(result);
-        }
-    }
-
-    /**
-     * Load the model from a JSON string for this session.
-     *
-     * @param jsonString the JSON string to be parsed. The returned value(s) will be similar to {@link AxPolicyModel},
-     *        with merged {@linkplain AxKeyInfo} for the root object.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @PUT
-    @Path("/Model/Load")
-    public ApexApiResult loadFromString(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.loadFromString(jsonString);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            String result = "Model/Load" + (ret != null && ret.isOk() ? ": OK" : NOT_OK);
-            LOGGER.exit(result);
-        }
-    }
-
-    /**
-     * Analyse the model and return analysis results. If successful the analysis results will be available in the
-     * messages in the result.
-     *
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Model/Analyse")
-    public ApexApiResult analyse() {
-        ApexApiResult ret = null;
-        LOGGER.entry();
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.analyse();
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Model/Analyse" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Validate the model and return validation results. If successful the validation results will be available in the
-     * messages in the result.
-     *
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Model/Validate")
-    public ApexApiResult validate() {
-        ApexApiResult ret = null;
-        LOGGER.entry();
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.validate();
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Model/Validate" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Creates the new model model for this session.
-     *
-     * @param jsonString the JSON string to be parsed containing the new model. See {@linkplain BeanModel}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @POST
-    @Path("Model/Create")
-    public ApexApiResult createModel(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanModel jsonbean = RestUtils.getJsonParameters(jsonString, BeanModel.class);
-            ret = sessionApexModel.createModel(jsonbean.getName(), jsonbean.getVersion(), jsonbean.getUuid(),
-                            jsonbean.getDescription());
-
-            if (ret.isOk()) {
-                ret = addKeyInfo2Messages(ret);
-            }
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Model/Create" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Update the model for this session.
-     *
-     * @param jsonString the JSON string to be parsed containing the updated model. See {@linkplain BeanModel}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @PUT
-    @Path("Model/Update")
-    public ApexApiResult updateModel(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanModel jsonbean = RestUtils.getJsonParameters(jsonString, BeanModel.class);
-            ret = sessionApexModel.updateModel(jsonbean.getName(), jsonbean.getVersion(), jsonbean.getUuid(),
-                            jsonbean.getDescription());
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Model/Update" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Gets the key for the model for this session. If successful the model key will be available in the first message
-     * in the result. See {@linkplain AxKey}
-     *
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Model/GetKey")
-    public ApexApiResult getModelKey() {
-        ApexApiResult ret = null;
-        LOGGER.entry();
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.getModelKey();
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Model/GetKey" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Retrieve the model for this session. If successful the model will be available in the first message in the
-     * result. The returned value will be similar to a {@link AxPolicyModel}, with merged {@linkplain AxKeyInfo} for the
-     * root object.
-     *
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Model/Get")
-    public ApexApiResult listModel() {
-        ApexApiResult ret = null;
-        LOGGER.entry();
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.listModel();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Model/Get" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Download the model for this session as a String.
-     *
-     * @return the model represented as a JSON string. See {@linkplain AxPolicyModel}
-     */
-    @GET
-    @Path("Model/Download")
-    public String downloadModel() {
-        ApexApiResult ret = null;
-        LOGGER.entry();
-        try {
-
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                throw new IllegalStateException("Cannot download file: " + ret.getMessage());
-            }
-
-            ret = sessionApexModel.listModel();
-            if (ret.isNok()) {
-                throw new IllegalStateException("Cannot download file: " + ret.getMessage());
-            }
-
-            return ret.getMessage();
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            String result = "Model/Download" + (ret != null && ret.isOk() ? ": OK" : NOT_OK);
-            LOGGER.exit(result);
-        }
-    }
-
-    /**
-     * Delete the model for this session.
-     *
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @DELETE
-    @Path("Model/Delete")
-    public ApexApiResult deleteModel() {
-        ApexApiResult ret = null;
-        LOGGER.entry();
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.deleteModel();
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Model/Delete" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * List key information with the given key names/versions. If successful the result(s) will be available in the
-     * result messages. See {@linkplain AxKeyInfo}
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("KeyInformation/Get")
-    public ApexApiResult listKeyInformation(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listKeyInformation(name1, version1);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("KeyInformation/Get" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Creates a context schema with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextSchema}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @POST
-    @Path("ContextSchema/Create")
-    public ApexApiResult createContextSchema(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanContextSchema jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextSchema.class);
-            ret = sessionApexModel.createContextSchema(jsonbean.getName(), jsonbean.getVersion(),
-                            jsonbean.getSchemaFlavour(), jsonbean.getSchemaDefinition(), jsonbean.getUuid(),
-                            jsonbean.getDescription());
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextSchema/Create" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Update a context schema with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextSchema}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @PUT
-    @Path("ContextSchema/Update")
-    public ApexApiResult updateContextSchema(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanContextSchema jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextSchema.class);
-
-            ret = sessionApexModel.updateContextSchema(jsonbean.getName(), jsonbean.getVersion(),
-                            jsonbean.getSchemaFlavour(), jsonbean.getSchemaDefinition(), jsonbean.getUuid(),
-                            jsonbean.getDescription());
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextSchema/Update" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * List context schemas with the given key names/versions. If successful the result(s) will be available in the
-     * result messages. The returned value(s) will be similar to {@link AxContextSchema}, with merged
-     * {@linkplain AxKeyInfo} for the root object.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("ContextSchema/Get")
-    public ApexApiResult listContextSchemas(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listContextSchemas(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextSchema/Get" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Delete context schemas with the given key names/versions.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @DELETE
-    @Path("ContextSchema/Delete")
-    public ApexApiResult deleteContextSchema(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.deleteContextSchema(name1, version1);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextSchema/Delete" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Validate context schemas with the given key names/versions. The result(s) will be available in the result
-     * messages.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Validate/ContextSchema")
-    public ApexApiResult validateContextSchemas(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.validateContextSchemas(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Validate/ContextSchema" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Creates a context album with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextAlbum}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @POST
-    @Path("ContextAlbum/Create")
-    public ApexApiResult createContextAlbum(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanContextAlbum jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextAlbum.class);
-
-            ret = sessionApexModel.createContextAlbum(jsonbean.getName(), jsonbean.getVersion(), jsonbean.getScope(),
-                            Boolean.toString(jsonbean.getWriteable()), jsonbean.getItemSchema().getName(),
-                            jsonbean.getItemSchema().getVersion(), jsonbean.getUuid(), jsonbean.getDescription());
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextAlbum/Create" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Update a context album with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextAlbum}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @PUT
-    @Path("ContextAlbum/Update")
-    public ApexApiResult updateContextAlbum(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanContextAlbum jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextAlbum.class);
-
-            ret = sessionApexModel.updateContextAlbum(jsonbean.getName(), jsonbean.getVersion(), jsonbean.getScope(),
-                            Boolean.toString(jsonbean.getWriteable()), jsonbean.getItemSchema().getName(),
-                            jsonbean.getItemSchema().getVersion(), jsonbean.getUuid(), jsonbean.getDescription());
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextAlbum/Update" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * List context albums with the given key names/versions. If successful the result(s) will be available in the
-     * result messages. The returned value(s) will be similar to {@link AxContextAlbum}, with merged
-     * {@linkplain AxKeyInfo} for the root object.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("ContextAlbum/Get")
-    public ApexApiResult listContextAlbums(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listContextAlbum(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextAlbum/Get" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Delete context albums with the given key names/versions.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @DELETE
-    @Path("ContextAlbum/Delete")
-    public ApexApiResult deleteContextAlbum(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.deleteContextAlbum(name1, version1);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("ContextAlbum/Delete" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Validate context albums with the given key names/versions. The result(s) will be available in the result
-     * messages.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Validate/ContextAlbum")
-    public ApexApiResult validateContextAlbums(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.listContextAlbum(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Validate/ContextAlbum" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Creates an event with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanEvent}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @POST
-    @Path("Event/Create")
-    public ApexApiResult createEvent(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanEvent jsonbean = RestUtils.getJsonParameters(jsonString, BeanEvent.class);
-
-            ret = sessionApexModel.createEvent(jsonbean.getName(), jsonbean.getVersion(), jsonbean.getNameSpace(),
-                            jsonbean.getSource(), jsonbean.getTarget(), jsonbean.getUuid(), jsonbean.getDescription());
-            if (ret.isNok()) {
-                return ret;
-            }
-            if (jsonbean.getParameters() != null) {
-                for (final Entry<String, BeanField> p : jsonbean.getParameters().entrySet()) {
-                    if (p.getValue() == null) {
-                        ret = new ApexApiResult(Result.FAILED, "Null event parameter information for parameter \""
-                                        + p.getKey() + "\" in event " + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The event was created, but there was an error adding the event parameters."
-                                        + " The event has only been partially defined.");
-                        return ret;
-                    }
-                    final ApexApiResult rettmp = sessionApexModel.createEventPar(jsonbean.getName(),
-                                    jsonbean.getVersion(), p.getKey(), p.getValue().getName(),
-                                    p.getValue().getVersion(), p.getValue().getOptional());
-                    if (rettmp.isNok()) {
-                        rettmp.addMessage("Failed to add event parameter information for parameter \"" + p.getKey()
-                                        + "\" in event " + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The event was created, but there was an error adding the event parameters."
-                                        + " The event has only been partially defined.");
-                        ret = rettmp;
-                        return ret;
-                    }
-                }
-            }
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Event/Create" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Update an event with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanEvent}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @PUT
-    @Path("Event/Update")
-    public ApexApiResult updateEvent(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanEvent jsonbean = RestUtils.getJsonParameters(jsonString, BeanEvent.class);
-
-            if (jsonbean.getName() == null || "".equals(jsonbean.getName()) || jsonbean.getVersion() == null
-                            || "".equals(jsonbean.getVersion())) {
-                ret = new ApexApiResult(Result.FAILED, "Null/Empty event name/version (\"" + jsonbean.getName() + ":"
-                                + jsonbean.getVersion() + "\" passed to UpdateEvent");
-                return ret;
-            }
-
-            ret = sessionApexModel.deleteEvent(jsonbean.getName(), jsonbean.getVersion());
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = createEvent(jsonString);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Event/Update" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * List events with the given key names/versions. If successful the result(s) will be available in the result
-     * messages. The returned value(s) will be similar to {@link AxEvent}, with merged {@linkplain AxKeyInfo} for the
-     * root object.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Event/Get")
-    public ApexApiResult listEvent(@QueryParam("name") final String name, @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listEvent(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Event/Get" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Delete events with the given key names/versions.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @DELETE
-    @Path("Event/Delete")
-    public ApexApiResult deleteEvent(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = sessionApexModel.deleteEvent(name1, version1);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Event/Delete" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Validate events with the given key names/versions. The result(s) will be available in the result messages.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Validate/Event")
-    public ApexApiResult validateEvent(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listEvent(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Validate/Event" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Creates a task with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanTask}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @POST
-    @Path("Task/Create")
-    public ApexApiResult createTask(final String jsonString) {
-        ApexApiResult ret = null;
-        ApexApiResult tempres = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanTask jsonbean = RestUtils.getJsonParameters(jsonString, BeanTask.class);
-
-            ret = sessionApexModel.createTask(jsonbean.getName(), jsonbean.getVersion(), jsonbean.getUuid(),
-                            jsonbean.getDescription());
-            if (ret.isNok()) {
-                return ret;
-            }
-            if (jsonbean.getInputFields() != null) {
-                for (final Entry<String, BeanField> fin : jsonbean.getInputFields().entrySet()) {
-                    if (fin.getValue() == null) {
-                        ret = new ApexApiResult(Result.FAILED, "Null task input field information for field \""
-                                        + fin.getKey() + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The task was created, but there was an error adding the input fields."
-                                        + TASK_PARTIALLY_DEFINED);
-                        return ret;
-                    }
-                    if (fin.getKey() == null || !fin.getKey().equals(fin.getValue().getLocalName())) {
-                        ret = new ApexApiResult(Result.FAILED, "Invalid task input field information for field \""
-                                        + fin.getKey() + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The localName of the field (\"" + fin.getValue().getLocalName()
-                                        + "\") is not the same as the field name. "
-                                        + "The task was created, but there was an error adding the input fields."
-                                        + TASK_PARTIALLY_DEFINED);
-                        return ret;
-                    }
-                    tempres = sessionApexModel.createTaskInputField(jsonbean.getName(), jsonbean.getVersion(),
-                                    fin.getKey(), fin.getValue().getName(), fin.getValue().getVersion(),
-                                    fin.getValue().getOptional());
-                    if (tempres.isNok()) {
-                        tempres.addMessage("Failed to add task input field information for field \"" + fin.getKey()
-                                        + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The task was created, but there was an error adding the input fields."
-                                        + TASK_PARTIALLY_DEFINED);
-                        ret = tempres;
-                        return ret;
-                    }
-                }
-            }
-            if (jsonbean.getOutputFields() != null) {
-                for (final Entry<String, BeanField> fout : jsonbean.getOutputFields().entrySet()) {
-                    if (fout.getValue() == null) {
-                        ret = new ApexApiResult(Result.FAILED, "Null task output field information for field \""
-                                        + fout.getKey() + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The task was created, but there was an error adding the output fields."
-                                        + TASK_PARTIALLY_DEFINED);
-                        return ret;
-                    }
-                    if (fout.getKey() == null || !fout.getKey().equals(fout.getValue().getLocalName())) {
-                        ret = new ApexApiResult(Result.FAILED, "Invalid task output field information for field \""
-                                        + fout.getKey() + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The localName of the field (\"" + fout.getValue().getLocalName()
-                                        + "\") is not the same as the field name. "
-                                        + "The task was created, but there was an error adding the output fields."
-                                        + TASK_PARTIALLY_DEFINED);
-                        return ret;
-                    }
-                    tempres = sessionApexModel.createTaskOutputField(jsonbean.getName(), jsonbean.getVersion(),
-                                    fout.getKey(), fout.getValue().getName(), fout.getValue().getVersion(),
-                                    fout.getValue().getOptional());
-                    if (tempres.isNok()) {
-                        tempres.addMessage("Failed to add task output field information for field \"" + fout.getKey()
-                                        + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The task was created, but there was an error adding the output fields."
-                                        + TASK_PARTIALLY_DEFINED);
-                        ret = tempres;
-                        return ret;
-                    }
-                }
-            }
-            if (jsonbean.getTaskLogic() != null) {
-                final BeanLogic logic = jsonbean.getTaskLogic();
-                tempres = sessionApexModel.createTaskLogic(jsonbean.getName(), jsonbean.getVersion(),
-                                logic.getLogicFlavour(), logic.getLogic());
-                if (tempres.isNok()) {
-                    tempres.addMessage("Failed to add task logic in task " + jsonbean.getName() + ":"
-                                    + jsonbean.getVersion()
-                                    + ". The task was created, but there was an error adding the logic."
-                                    + TASK_PARTIALLY_DEFINED);
-                    ret = tempres;
-                    return ret;
-                }
-            }
-            if (jsonbean.getParameters() != null) {
-                for (final Entry<String, BeanTaskParameter> param : jsonbean.getParameters().entrySet()) {
-                    if (param.getKey() == null || param.getValue() == null
-                                    || !param.getKey().equals(param.getValue().getParameterName())) {
-                        ret = new ApexApiResult(Result.FAILED,
-                                        "Null or invalid task parameter information for parameter \"" + param.getKey()
-                                                        + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                                        + ". The task was created, "
-                                                        + "but there was an error adding the parameters."
-                                                        + TASK_PARTIALLY_DEFINED);
-                        return ret;
-                    }
-                    tempres = sessionApexModel.createTaskParameter(jsonbean.getName(), jsonbean.getVersion(),
-                                    param.getValue().getParameterName(), param.getValue().getDefaultValue());
-                    if (tempres.isNok()) {
-                        tempres.addMessage("Failed to add task parameter \"" + param.getKey() + IN_TASK
-                                        + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                        + ". The task was created, but there was an error adding the parameters."
-                                        + TASK_PARTIALLY_DEFINED);
-                        ret = tempres;
-                        return ret;
-                    }
-                }
-            }
-            if (jsonbean.getContexts() != null) {
-                for (final BeanKeyRef contextalbum : jsonbean.getContexts()) {
-                    if (contextalbum.getName() == null || contextalbum.getVersion() == null) {
-                        ret = new ApexApiResult(Result.FAILED,
-                                        "Null or invalid context album reference information in task "
-                                                        + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                                        + ". The task was created, but there was an error adding the"
-                                                        + " context album reference. "
-                                                        + "The task has only been partially defined.");
-                        return ret;
-                    }
-                    tempres = sessionApexModel.createTaskContextRef(jsonbean.getName(), jsonbean.getVersion(),
-                                    contextalbum.getName(), contextalbum.getVersion());
-                    if (tempres.isNok()) {
-                        ret = new ApexApiResult(Result.FAILED,
-                                        "Failed to add context album reference information in task "
-                                                        + jsonbean.getName() + ":" + jsonbean.getVersion()
-                                                        + ". The task was created, but there was an error adding the"
-                                                        + " context album reference. "
-                                                        + "The task has only been partially defined.");
-                        return ret;
-                    }
-                }
-            }
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Task/Create" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Update a task with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanTask}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @PUT
-    @Path("Task/Update")
-    public ApexApiResult updateTask(final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanTask jsonbean = RestUtils.getJsonParameters(jsonString, BeanTask.class);
-
-            if (jsonbean.getName() == null || "".equals(jsonbean.getName()) || jsonbean.getVersion() == null
-                            || "".equals(jsonbean.getVersion())) {
-                ret = new ApexApiResult(Result.FAILED, "Null/Empty task name/version (\"" + jsonbean.getName() + ":"
-                                + jsonbean.getVersion() + "\" passed to UpdateTask");
-                return ret;
-            }
-
-            ret = sessionApexModel.deleteTask(jsonbean.getName(), jsonbean.getVersion());
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = createTask(jsonString);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Task/Update" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * List tasks with the given key names/versions. If successful the result(s) will be available in the result
-     * messages. The returned value(s) will be similar to {@link AxTask}, with merged {@linkplain AxKeyInfo} for the
-     * root object.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Task/Get")
-    public ApexApiResult listTask(@QueryParam("name") final String name, @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listTask(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Task/Get" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Delete tasks with the given key names/versions.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @DELETE
-    @Path("Task/Delete")
-    public ApexApiResult deleteTask(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            // all input/output fields, parameters, logic, context references is "owned"/contained
-            // in the task, so
-            // deleting the task removes all of these
-            ret = sessionApexModel.deleteTask(name1, version1);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Task/Delete" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Validate tasks with the given key names/versions. The result(s) will be available in the result messages.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Validate/Task")
-    public ApexApiResult validateTask(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listTask(name1, version1);
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Validate/Task" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    // CHECKSTYLE:OFF: MethodLength
-    /**
-     * Creates a policy with the information in the JSON string passed.
-     *
-     * @param jsonString the JSON string to be parsed See {@linkplain BeanPolicy}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @POST
-    @Path("Policy/Create")
-    public ApexApiResult createPolicy(final String jsonString) {
-
-        ApexApiResult ret = null;
-        ApexApiResult tempres = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanPolicy jsonbean = RestUtils.getJsonParameters(jsonString, BeanPolicy.class);
-            final String policyname = jsonbean.getName();
-            final String policyversion = jsonbean.getVersion();
-
-            ret = sessionApexModel.createPolicy(policyname, policyversion, jsonbean.getTemplate(),
-                            jsonbean.getFirstState(), jsonbean.getUuid(), jsonbean.getDescription());
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (jsonbean.getStates() == null || jsonbean.getStates().isEmpty()) {
-                ret = new ApexApiResult(Result.FAILED,
-                                "Null or empty state map; no states defined for policy \"" + policyname + ":"
-                                                + policyversion
-                                                + "\". The policy was created, but there was an error adding states."
-                                                + POLICY_PARTIALLY_DEFINED);
-                return ret;
-            }
-
-            final Map<String, BeanState> statemap = jsonbean.getStates();
-            // need to create all the states first, before populating them
-            for (final Map.Entry<String, BeanState> e : statemap.entrySet()) {
-                final String statename = e.getKey();
-                final BeanState state = e.getValue();
-                if (state == null) {
-                    ret = new ApexApiResult(Result.FAILED,
-                                    "Null or invalid state information for state \"" + statename + FOR_POLICY
-                                                    + policyname + ":" + policyversion + POLICY_CREATED_STATE_ERROR
-                                                    + POLICY_PARTIALLY_DEFINED);
-                    return ret;
-                }
-                if (state.getTrigger() == null) {
-                    ret = new ApexApiResult(Result.FAILED,
-                                    "Null or invalid state trigger for state \"" + statename + FOR_POLICY + policyname
-                                                    + ":" + policyversion + POLICY_CREATED_STATE_ERROR
-                                                    + POLICY_PARTIALLY_DEFINED);
-                    return ret;
-                }
-                if (state.getDefaultTask() == null) {
-                    ret = new ApexApiResult(Result.FAILED,
-                                    "Null or invalid default task for state \"" + statename + FOR_POLICY + policyname
-                                                    + ":" + policyversion + POLICY_CREATED_STATE_ERROR
-                                                    + POLICY_PARTIALLY_DEFINED);
-                    return ret;
-                }
-                tempres = sessionApexModel.createPolicyState(policyname, policyversion, statename,
-                                state.getTrigger().getName(), state.getTrigger().getVersion(),
-                                state.getDefaultTask().getName(), state.getDefaultTask().getVersion());
-                if (tempres.isNok()) {
-                    ret = tempres;
-                    return ret;
-                }
-            }
-
-            for (final Map.Entry<String, BeanState> e : statemap.entrySet()) {
-                final String statename = e.getKey();
-                final BeanState state = e.getValue();
-
-                final BeanLogic tsl = state.getTaskSelectionLogic();
-                if (tsl != null) {
-                    tempres = sessionApexModel.createPolicyStateTaskSelectionLogic(policyname, policyversion, statename,
-                                    tsl.getLogicFlavour(), tsl.getLogic());
-                    if (tempres.isNok()) {
-                        tempres.addMessage("Failed to add task selection logic for state \"" + statename + "\" for"
-                                        + " policy \"" + policyname + ":" + policyversion
-                                        + POLICY_WAS_CREATED
-                                        + "but there was an error adding the task selection logic "
-                                        + "for the state. The policy has only been partially defined.");
-                        ret = tempres;
-                        return ret;
-                    }
-                }
-
-                final BeanKeyRef[] contexts = state.getContexts();
-                if (contexts != null) {
-                    for (final BeanKeyRef c : contexts) {
-                        if (c == null) {
-                            ret = new ApexApiResult(Result.FAILED, "Null or invalid context reference \"" + c + "\" for"
-                                            + " state \"" + statename + FOR_POLICY + policyname + ":" + policyversion
-                                            + "\". The policy was created, but there was an error adding the context "
-                                            + "reference for the state. The policy has only been partially defined.");
-                            return ret;
-                        }
-                        tempres = sessionApexModel.createPolicyStateContextRef(policyname, policyversion, statename,
-                                        c.getName(), c.getVersion());
-                        if (tempres.isNok()) {
-                            tempres.addMessage("Failed to add context reference \"" + c + "\" for state \"" + statename
-                                            + FOR_POLICY + policyname + ":" + policyversion
-                                            + POLICY_WAS_CREATED
-                                            + "but there was an error adding the context reference "
-                                            + "for the state. The policy has only been partially defined.");
-                            ret = tempres;
-                            return ret;
-                        }
-                    }
-                }
-
-                final Map<String, BeanLogic> finalizers = state.getFinalizers();
-                if (finalizers != null) {
-                    for (final Map.Entry<String, BeanLogic> f : finalizers.entrySet()) {
-                        final String finalizername = f.getKey();
-                        final BeanLogic finalizer = f.getValue();
-                        if (finalizername == null || finalizer == null) {
-                            ret = new ApexApiResult(Result.FAILED,
-                                            "Null or invalid finalizer information for finalizer " + "named \""
-                                                            + finalizername + IN_STATE + statename + FOR_POLICY
-                                                            + policyname + ":" + policyversion
-                                                            + POLICY_STATE_CREATED_OTHER_ERROR
-                                                            + " finalizer. The policy has only "
-                                                            + "been partially defined.");
-                            return ret;
-                        }
-                        tempres = sessionApexModel.createPolicyStateFinalizerLogic(policyname, policyversion, statename,
-                                        finalizername, finalizer.getLogicFlavour(), finalizer.getLogic());
-                        if (tempres.isNok()) {
-                            tempres.addMessage("Failed to add finalizer information for finalizer named \""
-                                            + finalizername + "\" in" + " state \"" + statename + FOR_POLICY
-                                            + policyname + ":" + policyversion + POLICY_STATE_CREATED_OTHER_ERROR
-                                            + " finalizer. The policy has only been partially defined.");
-                            ret = tempres;
-                            return ret;
-                        }
-                    }
-                }
-                final Map<String, BeanStateOutput> outputs = state.getStateOutputs();
-                if (outputs == null || outputs.isEmpty()) {
-                    ret = new ApexApiResult(Result.FAILED, "No state outputs have been defined in state \"" + statename
-                                    + FOR_POLICY + policyname + ":" + policyversion
-                                    + "\". The policy and state were created, but there was an error adding state"
-                                    + " outputs. The policy has only been partially defined.");
-                    return ret;
-                }
-                for (final Map.Entry<String, BeanStateOutput> o : outputs.entrySet()) {
-                    final String outputname = o.getKey();
-                    final BeanStateOutput output = o.getValue();
-                    if (outputname == null || output == null || output.getEvent() == null) {
-                        ret = new ApexApiResult(Result.FAILED,
-                                        "Null or invalid output information for output named \"" + outputname + IN_STATE
-                                                        + statename + FOR_POLICY + policyname + ":" + policyversion
-                                                        + POLICY_STATE_CREATED_OTHER_ERROR
-                                                        + " output. The policy has only been partially defined.");
-                        return ret;
-                    }
-                    tempres = sessionApexModel.createPolicyStateOutput(policyname, policyversion, statename, outputname,
-                                    output.getEvent().getName(), output.getEvent().getVersion(), output.getNextState());
-                    if (tempres.isNok()) {
-                        tempres.addMessage("Failed to add output information for output named \"" + outputname
-                                        + IN_STATE + statename + FOR_POLICY + policyname + ":" + policyversion
-                                        + "\". The policy and state were created, "
-                                        + "but there was an error adding the output." + POLICY_PARTIALLY_DEFINED);
-                        ret = tempres;
-                        return ret;
-                    }
-                }
-
-                final Map<String, BeanStateTaskRef> taskmap = state.getTasks();
-                if (taskmap == null || taskmap.isEmpty()) {
-                    ret = new ApexApiResult(Result.FAILED, "No tasks have been defined in state \"" + statename
-                                    + FOR_POLICY + policyname + ":" + policyversion
-                                    + "\". The policy and state were created, but there was an error adding tasks."
-                                    + POLICY_PARTIALLY_DEFINED);
-                    return ret;
-                }
-                for (final Map.Entry<String, BeanStateTaskRef> t : taskmap.entrySet()) {
-                    final String tasklocalname = t.getKey();
-                    final BeanStateTaskRef taskref = t.getValue();
-                    if (tasklocalname == null || taskref == null || taskref.getTask() == null) {
-                        ret = new ApexApiResult(Result.FAILED, "Null or invalid task information for task named \""
-                                        + tasklocalname + IN_STATE + statename + "\" for for policy \"" + policyname
-                                        + ":" + policyversion
-                                        + "\". The policy and state were created, but there was an error adding the "
-                                        + "task. The policy has only been partially defined.");
-                        return ret;
-                    }
-                    tempres = sessionApexModel.createPolicyStateTaskRef(policyname, policyversion, statename,
-                                    tasklocalname, taskref.getTask().getName(), taskref.getTask().getVersion(),
-                                    taskref.getOutputType(), taskref.getOutputName());
-                    if (tempres.isNok()) {
-                        tempres.addMessage("Failed to add task reference \"" + t + "\" for state \"" + statename
-                                        + FOR_POLICY + policyname + ":" + policyversion + POLICY_WAS_CREATED
-                                        + "but there was an error adding the task reference for"
-                                        + " the state. The policy has only been partially defined.");
-                        ret = tempres;
-                        return ret;
-                    }
-                }
-
-            }
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Policy/Create" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-    // CHECKSTYLE:ON: MethodLength
-
-    /**
-     * Update a policy with the information in the JSON string passed.
-     *
-     * @param firstStatePeriodic indicates if periodic event should be created and added to model
-     * @param jsonString the JSON string to be parsed. See {@linkplain BeanPolicy}
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @PUT
-    @Path("Policy/Update")
-    public ApexApiResult updatePolicy(@QueryParam("firstStatePeriodic") final boolean firstStatePeriodic,
-                    final String jsonString) {
-        ApexApiResult ret = null;
-        LOGGER.entry(jsonString);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            final BeanPolicy jsonbean = RestUtils.getJsonParameters(jsonString, BeanPolicy.class);
-
-            if (jsonbean.getName() == null || "".equals(jsonbean.getName()) || jsonbean.getVersion() == null
-                            || "".equals(jsonbean.getVersion())) {
-                ret = new ApexApiResult(Result.FAILED, "Null/Empty Policy name/version (\"" + jsonbean.getName() + ":"
-                                + jsonbean.getVersion() + "\" passed to UpdatePolicy");
-                return ret;
-            }
-
-            ret = sessionApexModel.deletePolicy(jsonbean.getName(), jsonbean.getVersion());
-            if (ret.isNok()) {
-                return ret;
-            }
-            if (firstStatePeriodic) {
-                final ApexApiResult existingPeriodicEvent = sessionApexModel.listEvent("PeriodicEvent", null);
-                if (existingPeriodicEvent.isNok()) {
-                    final String periodicEventString = "{\"name\":\"PeriodicEvent\",\"version\":\"0.0.1\","
-                                    + "\"uuid\":\"44236da1-3d47-4988-8033-b6fee9d6a0f4\","
-                                    + "\"description\":\"Generated description for concept referred to by key "
-                                    + "'PeriodicEvent:0.0.1'\",\"source\":\"System\",\"target\":\"Apex\","
-                                    + "\"nameSpace\":\"org.onap.policy.apex.domains.aadm.events\",\"parameters\":{}}";
-                    ret = createEvent(periodicEventString);
-                    if (ret.isNok()) {
-                        return ret;
-                    }
-                }
-            }
-            ret = createPolicy(jsonString);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Policy/Update" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * List policies with the given key names/versions. If successful the result(s) will be available in the result
-     * messages. The returned value(s) will be similar to {@link AxPolicy}, with merged {@linkplain AxKey Info} for the
-     * root object.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @GET
-    @Path("Policy/Get")
-    public ApexApiResult listPolicy(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForReadOnly();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            ret = sessionApexModel.listPolicy(name1, version1);
-
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            ret = addKeyInfo2Messages(ret);
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            LOGGER.exit("Policy/Get" + (ret != null && ret.isOk() ? ": OK" : NOT_OK));
-        }
-    }
-
-    /**
-     * Delete policies with the given key names/versions.
-     *
-     * @param name the name to search for. If null or empty, then all names will be queried
-     * @param version the version to search for. If null then all versions will be searched for.
-     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
-     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
-     */
-    @DELETE
-    @Path("Policy/Delete")
-    public ApexApiResult deletePolicy(@QueryParam("name") final String name,
-                    @QueryParam(VERSION) final String version) {
-        ApexApiResult ret = null;
-        String name1 = name;
-        String version1 = version;
-        LOGGER.entry(name1, version1);
-        try {
-            ret = initialiseSessionForChanges();
-            if (ret.isNok()) {
-                return ret;
-            }
-
-            if (name1 == null || "".equals(name1)) {
-                name1 = null;
-            }
-            if (version1 == null || "".equals(version1)) {
-                version1 = null;
-            }
-
-            // all input/output fields, parameters, logic, context references is "owned"/contained
-            // in the task, so
-            // deleting the task removes all of these
-            ret = sessionApexModel.deletePolicy(name1, version1);
-            if (ret.isOk()) {
-                commitChanges();
-            }
-            return ret;
-        } catch (final Exception e) {
-            LOGGER.catching(e);
-            throw e;
-        } finally {
-            String result = "Policy/Delete" + (ret != null && ret.isOk() ? ": OK" : NOT_OK);
-            LOGGER.exit(result);
-        }
-    }
-
-    /**
-     * The json strings representing the objects listed, stored in result.messages[], does not contain the
-     * AxKeyInformation for that object. This utility method retrieves the AxKeyInfo for each object and adds it to the
-     * json for the object.
-     *
-     * @param result The list result, containing json representations of objects stored in its "messages" array
-     * @return The list result, containing json augmented representations of objects stored in its "messages" array
-     */
-    private ApexApiResult addKeyInfo2Messages(final ApexApiResult result) {
-        if (result.isNok()) {
-            return result;
-        }
-
-        final ApexApiResult ret = new ApexApiResult(result.getResult());
-        ret.setMessages(result.getMessages());
-
-        final List<String> messages = result.getMessages();
-        final List<String> augmessages = new ArrayList<>(messages.size());
-        final GsonBuilder gb = new GsonBuilder();
-        gb.serializeNulls().enableComplexMapKeySerialization();
-        final Gson gson = gb.create();
-        for (final String message : messages) {
-            try {
-                final JsonObject jsonObject = gson.fromJson(message, JsonObject.class);
-                JsonObject objecttochange = jsonObject;
-                String name = null;
-                if (jsonObject != null && jsonObject.get("key") != null && jsonObject.get("key").isJsonObject()
-                                && jsonObject.getAsJsonObject("key").get("name") != null) {
-                    name = jsonObject.getAsJsonObject("key").get("name").getAsString();
-                } else if (jsonObject != null && jsonObject.get(POLICY_KEY) != null
-                                && jsonObject.get(POLICY_KEY).isJsonObject()
-                                && jsonObject.getAsJsonObject(POLICY_KEY).get("name") != null) {
-                    name = jsonObject.getAsJsonObject(POLICY_KEY).get("name").getAsString();
-                }
-                String version = null;
-                if (jsonObject != null && jsonObject.get("key") != null && jsonObject.get("key").isJsonObject()
-                                && jsonObject.getAsJsonObject("key").get(VERSION) != null) {
-                    version = jsonObject.getAsJsonObject("key").get(VERSION).getAsString();
-                } else if (jsonObject != null && jsonObject.get(POLICY_KEY) != null
-                                && jsonObject.get(POLICY_KEY).isJsonObject()
-                                && jsonObject.getAsJsonObject(POLICY_KEY).get(VERSION) != null) {
-                    version = jsonObject.getAsJsonObject(POLICY_KEY).get(VERSION).getAsString();
-                }
-
-                if (name == null && version == null && jsonObject.entrySet() != null
-                                && !jsonObject.entrySet().isEmpty()) {
-                    objecttochange = (JsonObject) jsonObject.entrySet().iterator().next().getValue();
-                    if (objecttochange != null && objecttochange.get("key") != null
-                                    && objecttochange.get("key").isJsonObject()
-                                    && objecttochange.getAsJsonObject("key").get("name") != null) {
-                        name = objecttochange.getAsJsonObject("key").get("name").getAsString();
-                    } else if (objecttochange != null && objecttochange.get(POLICY_KEY) != null
-                                    && objecttochange.get(POLICY_KEY).isJsonObject()
-                                    && objecttochange.getAsJsonObject(POLICY_KEY).get("name") != null) {
-                        name = objecttochange.getAsJsonObject(POLICY_KEY).get("name").getAsString();
-                    }
-                    if (objecttochange != null && objecttochange.get("key") != null
-                                    && objecttochange.get("key").isJsonObject()
-                                    && objecttochange.getAsJsonObject("key").get(VERSION) != null) {
-                        version = objecttochange.getAsJsonObject("key").get(VERSION).getAsString();
-                    } else if (objecttochange != null && objecttochange.get(POLICY_KEY) != null
-                                    && objecttochange.get(POLICY_KEY).isJsonObject()
-                                    && objecttochange.getAsJsonObject(POLICY_KEY).get(VERSION) != null) {
-                        version = objecttochange.getAsJsonObject(POLICY_KEY).get(VERSION).getAsString();
-                    }
-                }
-
-                String uuid = null;
-                String desc = null;
-
-                if (name != null && version != null) {
-                    final ApexApiResult keyInfoResult = sessionApexModel.listKeyInformation(name, version);
-                    final List<String> keyInfoMessages = keyInfoResult.getMessages();
-                    if (keyInfoResult.isOk() && keyInfoMessages != null && !keyInfoMessages.isEmpty()) {
-                        final String keyInfoJson = keyInfoMessages.get(0);
-                        final JsonObject keyInfoJsonObject = gson.fromJson(keyInfoJson, JsonObject.class);
-                        if (keyInfoJsonObject != null && keyInfoJsonObject.get(APEX_KEY_INFO) != null
-                                        && keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID") != null) {
-                            uuid = keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID").getAsString();
-                        }
-                        if (keyInfoJsonObject != null && keyInfoJsonObject.get(APEX_KEY_INFO) != null
-                                        && keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject()
-                                                        .get(DESCRIPTION) != null) {
-                            desc = keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION)
-                                            .getAsString();
-                        }
-                    }
-                }
-                objecttochange.addProperty("uuid", uuid);
-                objecttochange.addProperty(DESCRIPTION, desc);
-                augmessages.add(gson.toJson(jsonObject));
-            } catch (final Exception e) {
-                LOGGER.debug("error adding key information", e);
-                augmessages.add(message);
-            }
-        }
-        ret.setMessages(augmessages);
-
-        if (messages.size() != augmessages.size()) {
-            ret.setResult(Result.OTHER_ERROR);
-            ret.addMessage("Failed to add KeyInfo to all results. Results are not complete");
-        }
-
-        return ret;
-    }
-
-    /*
-     * This method is used only for testing and is used to cause an exception on calls from unit test to test exception
-     * handling.
-     */
-    protected static int createCorruptSession() {
-        final ApexEditorRestResource apexEditorRestResource = new ApexEditorRestResource();
-        final ApexApiResult result = apexEditorRestResource.createSession();
-        final int corruptSessionId = Integer.parseInt(result.getMessages().get(0));
-
-        SESSIONMODELMAP.put(corruptSessionId, null);
-
-        return corruptSessionId;
-    }
-
-    /**
-     * Increment the session number.
-     */
-    private static void incrementNextSession() {
-        nextSession++;
-    }
-
-}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ApexEditorRestResource.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ApexEditorRestResource.java
new file mode 100644 (file)
index 0000000..e5660c9
--- /dev/null
@@ -0,0 +1,818 @@
+/*-
+ * ============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.client.editor.rest.handling;
+
+import java.io.IOException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+import org.onap.policy.apex.model.utilities.TextFileUtils;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The class represents the root resource exposed at the base URL<br> The url to access this resource would be in the
+ * form {@code <baseURL>/rest/<session>/....} <br> For example: a PUT request to the following URL
+ * {@code http://localhost:8080/apex/rest/109/ContextSchema/Update}, with a JSON string payload containing the new
+ * {@code Schema} in the body, can be explained as: <ul> <li>The server or servlet is running at the base URL
+ * {@code http://localhost:8080/apex} <li>This resource {@code ApexRestEditorResource} is used because the path
+ * {@code rest/109} matches the {@code Path} filter specification for this Resource ({@code @Path("rest/{session}")}),
+ * where the {@code int} path parameter {@code session} is assigned the {@code int} value {@code 109} <li>The path
+ * {@code ContextSchema/Update} redirects this call to the method {@link #updateContextSchema(String)}, which should be
+ * a {@link javax.ws.rs.PUT}, with a single String in the body/payload which gets mapped to the single String parameter
+ * for the method. <li>So, in summary, the REST request updates a {@code ContextSchema} as specified in the payload for
+ * {@code session} number {@code 109} </ul>
+ *
+ * <b>Note:</b> An allocated {@code Session} identifier must be included in (almost) all requests. Models for different
+ * {@code Session} identifiers are completely isolated from one another.
+ *
+ * <b>Note:</b> To create a new {@code Session}, and have a new session ID allocated use {@link javax.ws.rs.GET} request
+ * to {@code <baseURL>/rest/-1/Session/Create} (for example: {@code http://localhost:8080/apex/rest/-1/Session/Create} )
+ *
+ */
+@Path("editor/{session}")
+@Produces(
+    { MediaType.APPLICATION_JSON })
+@Consumes(
+    { MediaType.APPLICATION_JSON })
+
+public class ApexEditorRestResource implements RestCommandHandler {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexEditorRestResource.class);
+
+    // Location of the periodi event template
+    private static final String PERIODIC_EVENT_TEMPLATE = "src/main/resources/templates/PeriodicEventTemplate.json";
+
+    // Recurring string constants
+    private static final String NAME = "name";
+    private static final String VERSION = "version";
+    private static final String REST_COMMAND_NOT_RECOGNISED = "REST command not recognised";
+    private static final String OK = ": OK";
+    private static final String NOT_OK = ": Not OK";
+    private static final String SESSION_CREATE = "Session/Create";
+    private static final String SESSION_CREATE_NOT_OK = "Session/Create: Not OK";
+
+    // The session handler for sessions on the Apex editor
+    private static final RestSessionHandler SESSION_HANDLER = new RestSessionHandler();
+
+    // Handlers for the various parts of an Apex model
+    //@formatter:off
+    private static final ModelHandler         MODEL_HANDLER          = new ModelHandler();
+    private static final KeyInfoHandler       KEY_INFO_HANDLER       = new KeyInfoHandler();
+    private static final ContextSchemaHandler CONTEXT_SCHEMA_HANDLER = new ContextSchemaHandler();
+    private static final ContextAlbumHandler  CONTEXT_ALBUM_HANDLER  = new ContextAlbumHandler();
+    private static final EventHandler         EVENT_HANDLER          = new EventHandler();
+    private static final TaskHandler          TASK_HANDLER           = new TaskHandler();
+    private static final PolicyHandler        POLICY_HANDLER         = new PolicyHandler();
+    //@formatter:on
+
+    // The ID of this session. This gets injected from the URL.
+    @PathParam("session")
+    private int sessionId = -1;
+
+    /**
+     * Creates a new session. Always call this method with sessionID -1, whereby a new sessionID will be allocated. If
+     * successful the new sessionID will be available in the first message in the result.
+     *
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}. This includes the session id
+     *         for this session.
+     */
+    @GET
+    @Path("Session/Create")
+    public ApexApiResult createSession() {
+        if (sessionId != -1) {
+            return new ApexApiResult(Result.FAILED, "Session ID must be set to -1 to create sessions: " + sessionId);
+        }
+
+        ApexApiResult result = new ApexApiResult();
+        SESSION_HANDLER.createSession(result);
+        return result;
+    }
+
+    /**
+     * Load the model from a JSON string for this session.
+     *
+     * @param jsonString the JSON string to be parsed. The returned value(s) will be similar to {@link AxPolicyModel},
+     *        with merged {@linkplain AxKeyInfo} for the root object.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @PUT
+    @Path("/Model/Load")
+    public ApexApiResult loadFromString(final String jsonString) {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.LOAD, jsonString);
+    }
+
+    /**
+     * Analyse the model and return analysis results. If successful the analysis results will be available in the
+     * messages in the result.
+     *
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Model/Analyse")
+    public ApexApiResult analyse() {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.ANALYSE);
+    }
+
+    /**
+     * Validate the model and return validation results. If successful the validation results will be available in the
+     * messages in the result.
+     *
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Model/Validate")
+    public ApexApiResult validate() {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.VALIDATE);
+    }
+
+    /**
+     * Creates the new model model for this session.
+     *
+     * @param jsonString the JSON string to be parsed containing the new model. See {@linkplain BeanModel}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @POST
+    @Path("Model/Create")
+    public ApexApiResult createModel(final String jsonString) {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.CREATE, jsonString);
+    }
+
+    /**
+     * Update the model for this session.
+     *
+     * @param jsonString the JSON string to be parsed containing the updated model. See {@linkplain BeanModel}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @PUT
+    @Path("Model/Update")
+    public ApexApiResult updateModel(final String jsonString) {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.UPDATE, jsonString);
+    }
+
+    /**
+     * Gets the key for the model for this session. If successful the model key will be available in the first message
+     * in the result. See {@linkplain AxKey}
+     *
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Model/GetKey")
+    public ApexApiResult getModelKey() {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.GET_KEY);
+    }
+
+    /**
+     * Retrieve the model for this session. If successful the model will be available in the first message in the
+     * result. The returned value will be similar to a {@link AxPolicyModel}, with merged {@linkplain AxKeyInfo} for the
+     * root object.
+     *
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Model/Get")
+    public ApexApiResult listModel() {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.LIST);
+    }
+
+    /**
+     * Download the model for this session as a String.
+     *
+     * @return the model represented as a JSON string. See {@linkplain AxPolicyModel}
+     */
+    @GET
+    @Path("Model/Download")
+    public String downloadModel() {
+        ApexApiResult result = processRestCommand(RestCommandType.MODEL, RestCommand.DOWNLOAD);
+        if (result != null && result.isOk()) {
+            return result.getMessage();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Delete the model for this session.
+     *
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @DELETE
+    @Path("Model/Delete")
+    public ApexApiResult deleteModel() {
+        return processRestCommand(RestCommandType.MODEL, RestCommand.DELETE);
+    }
+
+    /**
+     * List key information with the given key names/versions. If successful the result(s) will be available in the
+     * result messages. See {@linkplain AxKeyInfo}
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("KeyInformation/Get")
+    public ApexApiResult listKeyInformation(@QueryParam(NAME) final String name,
+                    @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.KEY_INFO, RestCommand.LIST, name, version);
+    }
+
+    /**
+     * Creates a context schema with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextSchema}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @POST
+    @Path("ContextSchema/Create")
+    public ApexApiResult createContextSchema(final String jsonString) {
+        return processRestCommand(RestCommandType.CONTEXT_SCHEMA, RestCommand.CREATE, jsonString);
+    }
+
+    /**
+     * Update a context schema with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextSchema}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @PUT
+    @Path("ContextSchema/Update")
+    public ApexApiResult updateContextSchema(final String jsonString) {
+        return processRestCommand(RestCommandType.CONTEXT_SCHEMA, RestCommand.UPDATE, jsonString);
+    }
+
+    /**
+     * List context schemas with the given key names/versions. If successful the result(s) will be available in the
+     * result messages. The returned value(s) will be similar to {@link AxContextSchema}, with merged
+     * {@linkplain AxKeyInfo} for the root object.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("ContextSchema/Get")
+    public ApexApiResult listContextSchemas(@QueryParam(NAME) final String name,
+                    @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.CONTEXT_SCHEMA, RestCommand.LIST, name, version);
+    }
+
+    /**
+     * Delete context schemas with the given key names/versions.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @DELETE
+    @Path("ContextSchema/Delete")
+    public ApexApiResult deleteContextSchema(@QueryParam(NAME) final String name,
+                    @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.CONTEXT_SCHEMA, RestCommand.DELETE, name, version);
+    }
+
+    /**
+     * Validate context schemas with the given key names/versions. The result(s) will be available in the result
+     * messages.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Validate/ContextSchema")
+    public ApexApiResult validateContextSchemas(@QueryParam(NAME) final String name,
+                    @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.CONTEXT_SCHEMA, RestCommand.VALIDATE, name, version);
+    }
+
+    /**
+     * Creates a context album with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextAlbum}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @POST
+    @Path("ContextAlbum/Create")
+    public ApexApiResult createContextAlbum(final String jsonString) {
+        return processRestCommand(RestCommandType.CONTEXT_ALBUM, RestCommand.CREATE, jsonString);
+    }
+
+    /**
+     * Update a context album with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextAlbum}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @PUT
+    @Path("ContextAlbum/Update")
+    public ApexApiResult updateContextAlbum(final String jsonString) {
+        return processRestCommand(RestCommandType.CONTEXT_ALBUM, RestCommand.UPDATE, jsonString);
+    }
+
+    /**
+     * List context albums with the given key names/versions. If successful the result(s) will be available in the
+     * result messages. The returned value(s) will be similar to {@link AxContextAlbum}, with merged
+     * {@linkplain AxKeyInfo} for the root object.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("ContextAlbum/Get")
+    public ApexApiResult listContextAlbums(@QueryParam(NAME) final String name,
+                    @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.CONTEXT_ALBUM, RestCommand.LIST, name, version);
+    }
+
+    /**
+     * Delete context albums with the given key names/versions.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @DELETE
+    @Path("ContextAlbum/Delete")
+    public ApexApiResult deleteContextAlbum(@QueryParam(NAME) final String name,
+                    @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.CONTEXT_ALBUM, RestCommand.DELETE, name, version);
+    }
+
+    /**
+     * Validate context albums with the given key names/versions. The result(s) will be available in the result
+     * messages.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Validate/ContextAlbum")
+    public ApexApiResult validateContextAlbums(@QueryParam(NAME) final String name,
+                    @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.CONTEXT_ALBUM, RestCommand.VALIDATE, name, version);
+    }
+
+    /**
+     * Creates an event with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanEvent}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @POST
+    @Path("Event/Create")
+    public ApexApiResult createEvent(final String jsonString) {
+        return processRestCommand(RestCommandType.EVENT, RestCommand.CREATE, jsonString);
+    }
+
+    /**
+     * Update an event with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanEvent}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @PUT
+    @Path("Event/Update")
+    public ApexApiResult updateEvent(final String jsonString) {
+        return processRestCommand(RestCommandType.EVENT, RestCommand.UPDATE, jsonString);
+    }
+
+    /**
+     * List events with the given key names/versions. If successful the result(s) will be available in the result
+     * messages. The returned value(s) will be similar to {@link AxEvent}, with merged {@linkplain AxKeyInfo} for the
+     * root object.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Event/Get")
+    public ApexApiResult listEvent(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.EVENT, RestCommand.LIST, name, version);
+    }
+
+    /**
+     * Delete events with the given key names/versions.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @DELETE
+    @Path("Event/Delete")
+    public ApexApiResult deleteEvent(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.EVENT, RestCommand.DELETE, name, version);
+    }
+
+    /**
+     * Validate events with the given key names/versions. The result(s) will be available in the result messages.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Validate/Event")
+    public ApexApiResult validateEvent(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.EVENT, RestCommand.VALIDATE, name, version);
+    }
+
+    /**
+     * Creates a task with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanTask}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @POST
+    @Path("Task/Create")
+    public ApexApiResult createTask(final String jsonString) {
+        return processRestCommand(RestCommandType.TASK, RestCommand.CREATE, jsonString);
+    }
+
+    /**
+     * Update a task with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanTask}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @PUT
+    @Path("Task/Update")
+    public ApexApiResult updateTask(final String jsonString) {
+        return processRestCommand(RestCommandType.TASK, RestCommand.UPDATE, jsonString);
+    }
+
+    /**
+     * List tasks with the given key names/versions. If successful the result(s) will be available in the result
+     * messages. The returned value(s) will be similar to {@link AxTask}, with merged {@linkplain AxKeyInfo} for the
+     * root object.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Task/Get")
+    public ApexApiResult listTask(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.TASK, RestCommand.LIST, name, version);
+    }
+
+    /**
+     * Delete tasks with the given key names/versions.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @DELETE
+    @Path("Task/Delete")
+    public ApexApiResult deleteTask(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.TASK, RestCommand.DELETE, name, version);
+    }
+
+    /**
+     * Validate tasks with the given key names/versions. The result(s) will be available in the result messages.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Validate/Task")
+    public ApexApiResult validateTask(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.TASK, RestCommand.VALIDATE, name, version);
+    }
+
+    // CHECKSTYLE:OFF: MethodLength
+    /**
+     * Creates a policy with the information in the JSON string passed.
+     *
+     * @param jsonString the JSON string to be parsed See {@linkplain BeanPolicy}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @POST
+    @Path("Policy/Create")
+    public ApexApiResult createPolicy(final String jsonString) {
+        return processRestCommand(RestCommandType.POLICY, RestCommand.CREATE, jsonString);
+    }
+
+    /**
+     * Update a policy with the information in the JSON string passed.
+     *
+     * @param firstStatePeriodic indicates if periodic event should be created and added to model
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanPolicy}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @PUT
+    @Path("Policy/Update")
+    public ApexApiResult updatePolicy(@QueryParam("firstStatePeriodic") final boolean firstStatePeriodic,
+                    final String jsonString) {
+
+        ApexApiResult result = processRestCommand(RestCommandType.POLICY, RestCommand.UPDATE, jsonString);
+        if (result != null && result.isOk() && firstStatePeriodic) {
+            result = createPeriodicEvent();
+        }
+        return result;
+    }
+
+    /**
+     * List policies with the given key names/versions. If successful the result(s) will be available in the result
+     * messages. The returned value(s) will be similar to {@link AxPolicy}, with merged {@linkplain AxKey Info} for the
+     * root object.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @GET
+    @Path("Policy/Get")
+    public ApexApiResult listPolicy(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.POLICY, RestCommand.LIST, name, version);
+    }
+
+    /**
+     * Delete policies with the given key names/versions.
+     *
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    @DELETE
+    @Path("Policy/Delete")
+    public ApexApiResult deletePolicy(@QueryParam(NAME) final String name, @QueryParam(VERSION) final String version) {
+        return processRestCommand(RestCommandType.POLICY, RestCommand.DELETE, name, version);
+    }
+
+    /**
+     * This method routes REST commands that take no parameters to their caller.
+     * 
+     * @param commandType the type of REST command to process
+     * @param command the REST command to process
+     * @return the result of the REST command
+     */
+    private ApexApiResult processRestCommand(final RestCommandType commandType, final RestCommand command) {
+        LOGGER.entry(commandType);
+        try {
+            ApexApiResult result = new ApexApiResult();
+            RestSession session = SESSION_HANDLER.getSession(sessionId, result);
+            if (session == null) {
+                return result;
+            }
+            result = executeRestCommand(session, commandType, command);
+            LOGGER.exit(SESSION_CREATE + (result != null && result.isOk() ? OK : NOT_OK));
+            return result;
+        } catch (final Exception e) {
+            LOGGER.catching(e);
+            LOGGER.exit(SESSION_CREATE_NOT_OK);
+            throw e;
+        }
+    }
+
+    /**
+     * This method routes REST commands that take a JSON string to their caller.
+     * 
+     * @param commandType the type of REST command to process
+     * @param command the REST command to process
+     * @param jsonString the JSON string received in the REST request
+     * @return the result of the REST command
+     */
+    private ApexApiResult processRestCommand(final RestCommandType commandType, final RestCommand command,
+                    final String jsonString) {
+        LOGGER.entry(commandType, jsonString);
+        try {
+            ApexApiResult result = new ApexApiResult();
+            RestSession session = SESSION_HANDLER.getSession(sessionId, result);
+            if (session == null) {
+                return result;
+            }
+            result = executeRestCommand(session, commandType, command, jsonString);
+            LOGGER.exit(SESSION_CREATE + (result != null && result.isOk() ? OK : NOT_OK));
+            return result;
+        } catch (final Exception e) {
+            LOGGER.catching(e);
+            LOGGER.exit(SESSION_CREATE_NOT_OK);
+            throw e;
+        }
+    }
+
+    /**
+     * This method routes REST commands that take a name and version to their caller.
+     * 
+     * @param commandType the type of REST command to process
+     * @param command the REST command to process
+     * @param name the name received in the REST request
+     * @param version the name received in the REST request
+     * @return the result of the REST command
+     */
+    private ApexApiResult processRestCommand(final RestCommandType commandType, final RestCommand command,
+                    final String name, final String version) {
+        LOGGER.entry(commandType, name, version);
+        try {
+            ApexApiResult result = new ApexApiResult();
+            RestSession session = SESSION_HANDLER.getSession(sessionId, result);
+            if (session == null) {
+                return result;
+            }
+            result = executeRestCommand(session, commandType, command, name, version);
+            LOGGER.exit(SESSION_CREATE + (result != null && result.isOk() ? OK : NOT_OK));
+            return result;
+        } catch (final Exception e) {
+            LOGGER.catching(e);
+            LOGGER.exit(SESSION_CREATE_NOT_OK);
+            throw e;
+        }
+    }
+
+    /**
+     * This method invokes callers to run REST commands that take no parameters.
+     *
+     * @param session the Apex editor session
+     * @param commandType the type of REST command to process
+     * @param command the REST command to process
+     * @return the result of the REST command
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        switch (commandType) {
+            case MODEL:
+                return MODEL_HANDLER.executeRestCommand(session, commandType, command);
+            case KEY_INFO:
+                return KEY_INFO_HANDLER.executeRestCommand(session, commandType, command);
+            case CONTEXT_SCHEMA:
+                return CONTEXT_SCHEMA_HANDLER.executeRestCommand(session, commandType, command);
+            case CONTEXT_ALBUM:
+                return CONTEXT_ALBUM_HANDLER.executeRestCommand(session, commandType, command);
+            case EVENT:
+                return EVENT_HANDLER.executeRestCommand(session, commandType, command);
+            case TASK:
+                return TASK_HANDLER.executeRestCommand(session, commandType, command);
+            case POLICY:
+                return POLICY_HANDLER.executeRestCommand(session, commandType, command);
+            default:
+                return new ApexApiResult(Result.FAILED, REST_COMMAND_NOT_RECOGNISED);
+        }
+    }
+
+    /**
+     * This method invokes callers to run REST commands that take a JSON string.
+     * 
+     * @param session the Apex editor session
+     * @param commandType the type of REST command to process
+     * @param command the REST command to process
+     * @param jsonString the JSON string received in the REST request
+     * @return the result of the REST command
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+        switch (commandType) {
+            case MODEL:
+                return MODEL_HANDLER.executeRestCommand(session, commandType, command, jsonString);
+            case KEY_INFO:
+                return KEY_INFO_HANDLER.executeRestCommand(session, commandType, command, jsonString);
+            case CONTEXT_SCHEMA:
+                return CONTEXT_SCHEMA_HANDLER.executeRestCommand(session, commandType, command, jsonString);
+            case CONTEXT_ALBUM:
+                return CONTEXT_ALBUM_HANDLER.executeRestCommand(session, commandType, command, jsonString);
+            case EVENT:
+                return EVENT_HANDLER.executeRestCommand(session, commandType, command, jsonString);
+            case TASK:
+                return TASK_HANDLER.executeRestCommand(session, commandType, command, jsonString);
+            case POLICY:
+                return POLICY_HANDLER.executeRestCommand(session, commandType, command, jsonString);
+            default:
+                return new ApexApiResult(Result.FAILED, REST_COMMAND_NOT_RECOGNISED);
+        }
+    }
+
+    /**
+     * This method invokes callers to run REST commands that take a name and version.
+     * 
+     * @param session the Apex editor session
+     * @param commandType the type of REST command to process
+     * @param command the REST command to process
+     * @param name the name received in the REST request
+     * @param version the name received in the REST request
+     * @return the result of the REST command
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+        switch (commandType) {
+            case MODEL:
+                return MODEL_HANDLER.executeRestCommand(session, commandType, command, name, version);
+            case KEY_INFO:
+                return KEY_INFO_HANDLER.executeRestCommand(session, commandType, command, name, version);
+            case CONTEXT_SCHEMA:
+                return CONTEXT_SCHEMA_HANDLER.executeRestCommand(session, commandType, command, name, version);
+            case CONTEXT_ALBUM:
+                return CONTEXT_ALBUM_HANDLER.executeRestCommand(session, commandType, command, name, version);
+            case EVENT:
+                return EVENT_HANDLER.executeRestCommand(session, commandType, command, name, version);
+            case TASK:
+                return TASK_HANDLER.executeRestCommand(session, commandType, command, name, version);
+            case POLICY:
+                return POLICY_HANDLER.executeRestCommand(session, commandType, command, name, version);
+            default:
+                return new ApexApiResult(Result.FAILED, REST_COMMAND_NOT_RECOGNISED);
+        }
+    }
+
+    /**
+     * Create a periodic event from the periodic event template.
+     */
+    private ApexApiResult createPeriodicEvent() {
+        String periodicEventJsonString;
+        try {
+            periodicEventJsonString = TextFileUtils.getTextFileAsString(PERIODIC_EVENT_TEMPLATE);
+        } catch (IOException ioException) {
+            String message = "read of periodic event tempalte from " + PERIODIC_EVENT_TEMPLATE + "failed: "
+                            + ioException.getMessage();
+            LOGGER.debug(message, ioException);
+            return new ApexApiResult(Result.FAILED, message);
+        }
+
+        return processRestCommand(RestCommandType.EVENT, RestCommand.CREATE, periodicEventJsonString);
+    }
+    
+    /*
+     * This method is used only for testing and is used to cause an exception on calls from unit test to test exception
+     * handling.
+     */
+    protected static int createCorruptSession() {
+        final ApexEditorRestResource apexEditorRestResource = new ApexEditorRestResource();
+        final ApexApiResult result = apexEditorRestResource.createSession();
+        final int corruptSessionId = Integer.parseInt(result.getMessages().get(0));
+
+        SESSION_HANDLER.setCorruptSession(corruptSessionId);
+
+        return corruptSessionId;
+    }
+
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ContextAlbumHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ContextAlbumHandler.java
new file mode 100644 (file)
index 0000000..30886db
--- /dev/null
@@ -0,0 +1,204 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanContextAlbum;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class handles commands on context albums in Apex models.
+ */
+public class ContextAlbumHandler implements RestCommandHandler {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ContextAlbumHandler.class);
+
+    // Recurring string constants
+    private static final String OK = ": OK";
+    private static final String NOT_OK = ": Not OK";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+        if (!RestCommandType.CONTEXT_ALBUM.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case CREATE:
+                return createContextAlbum(session, jsonString);
+            case UPDATE:
+                return updateContextAlbum(session, jsonString);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+        if (!RestCommandType.CONTEXT_ALBUM.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case LIST:
+                return listContextAlbums(session, name, version);
+            case DELETE:
+                return deleteContextAlbum(session, name, version);
+            case VALIDATE:
+                return validateContextAlbum(session, name, version);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * Creates a context album with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextAlbum}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createContextAlbum(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        session.editModel();
+
+        final BeanContextAlbum jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextAlbum.class);
+
+        ApexApiResult result = session.getApexModelEdited().createContextAlbum(jsonbean.getName(),
+                        jsonbean.getVersion(), jsonbean.getScope(), Boolean.toString(jsonbean.getWriteable()),
+                        jsonbean.getItemSchema().getName(), jsonbean.getItemSchema().getVersion(), jsonbean.getUuid(),
+                        jsonbean.getDescription());
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("ContextAlbum/Create" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Update a context album with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanContextAlbum}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult updateContextAlbum(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        session.editModel();
+
+        final BeanContextAlbum jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextAlbum.class);
+
+        ApexApiResult result = session.getApexModelEdited().updateContextAlbum(jsonbean.getName(),
+                        jsonbean.getVersion(), jsonbean.getScope(), Boolean.toString(jsonbean.getWriteable()),
+                        jsonbean.getItemSchema().getName(), jsonbean.getItemSchema().getVersion(), jsonbean.getUuid(),
+                        jsonbean.getDescription());
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("ContextAlbum/Update" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * List context albums with the given key names/versions. If successful the result(s) will be available in the
+     * result messages. The returned value(s) will be similar to {@link AxContextAlbum}, with merged
+     * {@linkplain AxKeyInfo} for the root object.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult listContextAlbums(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().listContextAlbum(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("ContextAlbum/Get" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Delete context albums with the given key names/versions.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult deleteContextAlbum(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().deleteContextAlbum(blank2Null(name), blank2Null(version));
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("ContextAlbum/Delete" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Validate context albums with the given key names/versions. The result(s) will be available in the result
+     * messages.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult validateContextAlbum(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().validateContextAlbum(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("Validate/ContextAlbum" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ContextSchemaHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ContextSchemaHandler.java
new file mode 100644 (file)
index 0000000..c65ca72
--- /dev/null
@@ -0,0 +1,191 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanContextSchema;
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class handles commands on context schemas in Apex models.
+ */
+public class ContextSchemaHandler implements RestCommandHandler {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ContextSchemaHandler.class);
+
+    // Recurring string constants
+    private static final String OK = ": OK";
+    private static final String NOT_OK = ": Not OK";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+        if (!RestCommandType.CONTEXT_SCHEMA.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case CREATE:
+                return createContextSchema(session, jsonString);
+            case UPDATE:
+                return updateContextSchema(session, jsonString);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+        if (!RestCommandType.CONTEXT_SCHEMA.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case LIST:
+                return listContextSchemas(session, name, version);
+            case DELETE:
+                return deleteContextSchema(session, name, version);
+            case VALIDATE:
+                return validateContextSchemas(session, name, version);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * Creates a context schema.
+     *
+     * @param session the session holding the Apex model
+     * @param jsonString the JSON string with the context schema parameters
+     * @return the result of the operation
+     */
+    private ApexApiResult createContextSchema(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        session.editModel();
+
+        final BeanContextSchema jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextSchema.class);
+        ApexApiResult result = session.getApexModelEdited().createContextSchema(jsonbean.getName(),
+                        jsonbean.getVersion(), jsonbean.getSchemaFlavour(), jsonbean.getSchemaDefinition(),
+                        jsonbean.getUuid(), jsonbean.getDescription());
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("ContextSchema/create" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Update a context schema.
+     *
+     * @param session the session holding the Apex model
+     * @param jsonString the JSON string with the context schema parameters
+     * @return the result of the operation
+     */
+    private ApexApiResult updateContextSchema(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        session.editModel();
+
+        final BeanContextSchema jsonbean = RestUtils.getJsonParameters(jsonString, BeanContextSchema.class);
+
+        ApexApiResult result = session.getApexModelEdited().updateContextSchema(jsonbean.getName(),
+                        jsonbean.getVersion(), jsonbean.getSchemaFlavour(), jsonbean.getSchemaDefinition(),
+                        jsonbean.getUuid(), jsonbean.getDescription());
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("ContextSchema/Update" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * List context schemas.
+     *
+     * @param session the session holding the Apex model
+     * @param name the context schema name to operate on
+     * @param version the context schema version to operate on
+     * @return the result of the operation
+     */
+    private ApexApiResult listContextSchemas(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().listContextSchemas(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("ContextSchema/Get" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Delete a context schema.
+     *
+     * @param session the session holding the Apex model
+     * @param name the context schema name to operate on
+     * @param version the context schema version to operate on
+     * @return the result of the operation
+     */
+    private ApexApiResult deleteContextSchema(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().deleteContextSchema(blank2Null(name), blank2Null(version));
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("ContextSchema/Delete" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Validate a context schema.
+     * 
+     * @param session the session holding the Apex model
+     * @param name the context schema name to operate on
+     * @param version the context schema version to operate on
+     * @return the result of the operation
+     */
+    private ApexApiResult validateContextSchemas(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().validateContextSchemas(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("Validate/ContextSchema" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/EventHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/EventHandler.java
new file mode 100644 (file)
index 0000000..08b4873
--- /dev/null
@@ -0,0 +1,264 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import java.util.Map.Entry;
+
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanEvent;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanField;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class handles commands on events in Apex models.
+ */
+public class EventHandler implements RestCommandHandler {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(EventHandler.class);
+
+    // Recurring string constants
+    private static final String OK = ": OK";
+    private static final String NOT_OK = ": Not OK";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+        if (!RestCommandType.EVENT.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case CREATE:
+                return createEvent(session, jsonString);
+            case UPDATE:
+                return updateEvent(session, jsonString);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+        if (!RestCommandType.EVENT.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case LIST:
+                return listEvents(session, name, version);
+            case DELETE:
+                return deleteEvent(session, name, version);
+            case VALIDATE:
+                return validateEvent(session, name, version);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * Creates an event with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanEvent}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createEvent(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        final BeanEvent jsonbean = RestUtils.getJsonParameters(jsonString, BeanEvent.class);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().createEvent(jsonbean.getName(), jsonbean.getVersion(),
+                        jsonbean.getNameSpace(), jsonbean.getSource(), jsonbean.getTarget(), jsonbean.getUuid(),
+                        jsonbean.getDescription());
+
+        if (result.isOk()) {
+            result = createEventParameters(session, jsonbean);
+        }
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Event/Create" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Create the parameters on an event.
+     * 
+     * @param session the Apex editor session
+     * @param jsonbean the JSON bean holding the parameters
+     * @param result the result of the parameter creation operation
+     * @return
+     */
+    private ApexApiResult createEventParameters(final RestSession session, final BeanEvent jsonbean) {
+        ApexApiResult result = new ApexApiResult();
+
+        if (jsonbean.getParameters() == null || jsonbean.getParameters().isEmpty()) {
+            return result;
+        }
+
+        for (final Entry<String, BeanField> parameterEntry : jsonbean.getParameters().entrySet()) {
+            if (parameterEntry.getValue() == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null event parameter information for parameter \"" + parameterEntry.getKey()
+                                + "\" in event " + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                + ". The event was created, but there was an error adding the event parameters."
+                                + " The event has only been partially defined.");
+                continue;
+            }
+
+            final ApexApiResult createParResult = session.getApexModelEdited().createEventPar(jsonbean.getName(),
+                            jsonbean.getVersion(), parameterEntry.getKey(), parameterEntry.getValue().getName(),
+                            parameterEntry.getValue().getVersion(), parameterEntry.getValue().getOptional());
+            if (createParResult.isNok()) {
+                result.setResult(createParResult.getResult());
+                result.addMessage("Failed to add event parameter information for parameter \"" + parameterEntry.getKey()
+                                + "\" in event " + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                + ". The event was created, but there was an error adding the event parameters."
+                                + " The event has only been partially defined.");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Update an event with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanEvent}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult updateEvent(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        final BeanEvent jsonbean = RestUtils.getJsonParameters(jsonString, BeanEvent.class);
+
+        if (blank2Null(jsonbean.getName()) == null || blank2Null(jsonbean.getVersion()) == null) {
+            LOGGER.exit("Event/Update" + NOT_OK);
+            return new ApexApiResult(Result.FAILED, "Null/Empty event name/version (\"" + jsonbean.getName() + ":"
+                            + jsonbean.getVersion() + "\" passed to UpdateEvent");
+        }
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().deleteEvent(blank2Null(jsonbean.getName()),
+                        blank2Null(jsonbean.getVersion()));
+
+        if (result.isOk()) {
+            result = session.getApexModelEdited().createEvent(jsonbean.getName(), jsonbean.getVersion(),
+                            jsonbean.getNameSpace(), jsonbean.getSource(), jsonbean.getTarget(), jsonbean.getUuid(),
+                            jsonbean.getDescription());
+
+            if (result.isOk() && jsonbean.getParameters() != null) {
+                result = createEventParameters(session, jsonbean);
+            }
+        }
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Event/Update" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * List events with the given key names/versions. If successful the result(s) will be available in the result
+     * messages. The returned value(s) will be similar to {@link AxEvent}, with merged {@linkplain AxKeyInfo} for the
+     * root object.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult listEvents(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().listEvent(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("Event/Get" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Delete events with the given key names/versions.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult deleteEvent(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().deleteEvent(blank2Null(name), blank2Null(version));
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Event/Delete" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Validate events with the given key names/versions. The result(s) will be available in the result messages.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult validateEvent(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().validateEvent(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("Validate/Event" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/KeyInfoHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/KeyInfoHandler.java
new file mode 100644 (file)
index 0000000..ffb8900
--- /dev/null
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+
+/**
+ * This class handles commands on key information in Apex models.
+ */
+public class KeyInfoHandler implements RestCommandHandler {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+
+        if (RestCommandType.KEY_INFO.equals(commandType) && RestCommand.LIST.equals(command)) {
+            return listKeyInformation(session, name, version);
+        }
+        else {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * Get the key information for a concept with the given name and version.
+     * @param session the editor session containing the Apex model
+     * @param name the name for the search
+     * @param version the version for the search
+     * @return the key information
+     */
+    private ApexApiResult listKeyInformation(final RestSession session, final String name, final String version) {
+        return session.getApexModel().listKeyInformation(blank2Null(name), blank2Null(version));
+    }
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ModelHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/ModelHandler.java
new file mode 100644 (file)
index 0000000..8b223ef
--- /dev/null
@@ -0,0 +1,446 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanModel;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class handles commands on Apex models.
+ */
+public class ModelHandler implements RestCommandHandler {
+
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(ModelHandler.class);
+
+    // Recurring string constants
+    private static final String OK = ": OK";
+    private static final String NOT_OK = ": Not OK";
+    private static final String KEY = "key";
+    private static final String NAME = "name";
+    private static final String VERSION = "version";
+    private static final String UUID = "uuid";
+    private static final String DESCRIPTION = "description";
+    private static final String POLICY_KEY = "policyKey";
+    private static final String APEX_KEY_INFO = "apexKeyInfo";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        if (!RestCommandType.MODEL.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case ANALYSE:
+                return analyse(session);
+            case VALIDATE:
+                return validate(session);
+            case GET_KEY:
+                return getModelKey(session);
+            case LIST:
+                return listModel(session);
+            case DOWNLOAD:
+                return downloadModel(session);
+            case DELETE:
+                return deleteModel(session);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+        if (!RestCommandType.MODEL.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case LOAD:
+                return loadFromString(session, jsonString);
+            case CREATE:
+                return createModel(session, jsonString);
+            case UPDATE:
+                return updateModel(session, jsonString);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * Load the model from a JSON string for this session.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. The returned value(s) will be similar to {@link AxPolicyModel},
+     *        with merged {@linkplain AxKeyInfo} for the root object.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult loadFromString(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().loadFromString(jsonString);
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Model/Load" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Analyse the model and return analysis results. If successful the analysis results will be available in the
+     * messages in the result.
+     *
+     * @param session the Apex model editing session
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult analyse(final RestSession session) {
+        LOGGER.entry();
+
+        ApexApiResult result = session.getApexModel().analyse();
+
+        LOGGER.exit("Model/Analyse" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Validate the model and return validation results. If successful the validation results will be available in the
+     * messages in the result.
+     *
+     * @param session the Apex model editing session
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult validate(final RestSession session) {
+        LOGGER.entry();
+
+        ApexApiResult result = session.getApexModel().validate();
+
+        LOGGER.exit("Model/Validate" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Creates the new model model for this session.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed containing the new model. See {@linkplain BeanModel}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createModel(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        final BeanModel jsonbean = RestUtils.getJsonParameters(jsonString, BeanModel.class);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().createModel(jsonbean.getName(), jsonbean.getVersion(),
+                        jsonbean.getUuid(), jsonbean.getDescription());
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Model/Create" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Update the model for this session.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed containing the updated model. See {@linkplain BeanModel}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult updateModel(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        final BeanModel jsonbean = RestUtils.getJsonParameters(jsonString, BeanModel.class);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().updateModel(jsonbean.getName(), jsonbean.getVersion(),
+                        jsonbean.getUuid(), jsonbean.getDescription());
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Model/Update" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Gets the key for the model for this session. If successful the model key will be available in the first message
+     * in the result. See {@linkplain AxKey}
+     *
+     * @param session the Apex model editing session
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult getModelKey(final RestSession session) {
+        LOGGER.entry();
+
+        ApexApiResult result = session.getApexModel().getModelKey();
+
+        LOGGER.exit("Model/GetKey" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Retrieve the model for this session. If successful the model will be available in the first message in the
+     * result. The returned value will be similar to a {@link AxPolicyModel}, with merged {@linkplain AxKeyInfo} for the
+     * root object.
+     *
+     * @param session the Apex model editing session
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult listModel(final RestSession session) {
+        LOGGER.entry();
+
+        ApexApiResult result = session.getApexModel().listModel();
+
+        result = addKeyInfo2Messages(session, result);
+
+        LOGGER.exit("Model/Get" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Download the model for this session as a String.
+     *
+     * @param session the Apex model editing session
+     * @return the model represented as a JSON string. See {@linkplain AxPolicyModel}
+     */
+    private ApexApiResult downloadModel(final RestSession session) {
+        LOGGER.entry();
+
+        ApexApiResult result = session.getApexModel().listModel();
+
+        LOGGER.exit("Model/Download" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Delete the model for this session.
+     *
+     * @param session the Apex model editing session
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult deleteModel(final RestSession session) {
+        LOGGER.entry();
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModel().deleteModel();
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Model/Delete" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * The json strings representing the objects listed, stored in result.messages[], does not contain the
+     * AxKeyInformation for that object. This utility method retrieves the AxKeyInfo for each object and adds it to the
+     * json for the object.
+     *
+     * @param session the Apex model editing session
+     * @param incomingResult The list result, containing JSON representations of objects stored in its "messages" array
+     * @return The list result, containing JSON augmented representations of objects stored in its "messages" array
+     */
+    private ApexApiResult addKeyInfo2Messages(final RestSession session, final ApexApiResult incomingResult) {
+        final ApexApiResult result = new ApexApiResult(incomingResult.getResult());
+        result.setMessages(incomingResult.getMessages());
+
+        final List<String> messages = incomingResult.getMessages();
+        final List<String> augmentedMessages = new ArrayList<>(messages.size());
+
+        for (final String message : messages) {
+            augmentedMessages.add(addKeyInfo2Message(session, message));
+        }
+        result.setMessages(augmentedMessages);
+
+        if (messages.size() != augmentedMessages.size()) {
+            result.setResult(Result.OTHER_ERROR);
+            result.addMessage("Failed to add KeyInfo to all results. Results are not complete");
+        }
+
+        return result;
+    }
+
+    /**
+     * Augment a message with key information.
+     * 
+     * @param session the Apex model editing session
+     * @param message The message to augment
+     * @return the augmented message
+     */
+    private String addKeyInfo2Message(final RestSession session, final String message) {
+        final Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
+
+        JsonObject jsonObject = gson.fromJson(message, JsonObject.class);
+        if (jsonObject == null) {
+            return message;
+        }
+
+        String name = readFieldFromJsonObject(jsonObject, NAME, null);
+        String version = readFieldFromJsonObject(jsonObject, VERSION, null);
+
+        if (name == null && version == null) {
+            JsonObject newJsonObject = getSubJsonObject(jsonObject);
+
+            if (newJsonObject != null) {
+                jsonObject = newJsonObject;
+                name = readFieldFromJsonObject(jsonObject, NAME, name);
+                version = readFieldFromJsonObject(jsonObject, VERSION, version);
+            }
+        }
+
+        if (name == null || version == null || !setUuidAndDescription(session, jsonObject, name, version)) {
+            jsonObject.addProperty(UUID, (String) null);
+            jsonObject.addProperty(DESCRIPTION, (String) null);
+        }
+
+        return gson.toJson(jsonObject);
+    }
+
+    /**
+     * Get an embedded JSON object for the given JSON object.
+     * 
+     * @param jsonObject the input JSON object
+     * @return the embedded JSON object
+     */
+    private JsonObject getSubJsonObject(JsonObject jsonObject) {
+        if (jsonObject.entrySet() != null && !jsonObject.entrySet().isEmpty()) {
+            return (JsonObject) jsonObject.entrySet().iterator().next().getValue();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Condition a field so its key information can be looked up.
+     * 
+     * @param jsonObject the object to query
+     * @param fieldTag the tag of the field to condition
+     * @param fieldValue the value of the field to condition
+     * @return
+     */
+    private String readFieldFromJsonObject(final JsonObject jsonObject, final String fieldTag, final String value) {
+        String lookedupValue = value;
+
+        if (jsonObject != null && jsonObject.get(KEY) != null && jsonObject.get(KEY).isJsonObject()
+                        && jsonObject.getAsJsonObject(KEY).get(fieldTag) != null) {
+            lookedupValue = jsonObject.getAsJsonObject(KEY).get(fieldTag).getAsString();
+        } else if (jsonObject != null && jsonObject.get(POLICY_KEY) != null && jsonObject.get(POLICY_KEY).isJsonObject()
+                        && jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag) != null) {
+            lookedupValue = jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag).getAsString();
+        }
+        return lookedupValue;
+    }
+
+    /**
+     * Look up the UUID and description in the key information for a concept.
+     * 
+     * @param session the Apex editor session
+     * @param jsonObject the JSON object to place the fields in
+     * @param name the concept name to look up
+     * @param version the concept version to look up
+     */
+    private boolean setUuidAndDescription(final RestSession session, JsonObject jsonObject, String name,
+                    String version) {
+        // Look up the key information for the name and version
+        JsonObject keyInfoJsonObject = lookupKeyInfo(session, name, version);
+        if (keyInfoJsonObject == null || keyInfoJsonObject.get(APEX_KEY_INFO) != null) {
+            return false;
+        }
+
+        if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID") != null) {
+            jsonObject.addProperty(UUID,
+                            keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID").getAsString());
+        } else {
+            jsonObject.addProperty(UUID, (String) null);
+        }
+
+        if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION) != null) {
+            jsonObject.addProperty(DESCRIPTION,
+                            keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION).getAsString());
+        } else {
+            jsonObject.addProperty(DESCRIPTION, (String) null);
+        }
+
+        return true;
+    }
+
+    /**
+     * Look up the key information for the given concept name and value.
+     * 
+     * @param session the Apex editor session
+     * @param name the concept name to look up
+     * @param version the concept version to look up
+     * @return a JSON version of the concept key information
+     */
+    private JsonObject lookupKeyInfo(final RestSession session, final String name, final String version) {
+        final ApexApiResult keyInfoResult = session.getApexModel().listKeyInformation(name, version);
+        final List<String> keyInfoMessages = keyInfoResult.getMessages();
+
+        if (keyInfoResult.isNok() || keyInfoMessages == null || keyInfoMessages.isEmpty()) {
+            return null;
+        }
+
+        final Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
+        final String keyInfoJson = keyInfoMessages.get(0);
+        return gson.fromJson(keyInfoJson, JsonObject.class);
+    }
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/PolicyHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/PolicyHandler.java
new file mode 100644 (file)
index 0000000..c1887b8
--- /dev/null
@@ -0,0 +1,578 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import java.util.Map;
+
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanKeyRef;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanLogic;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanPolicy;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanState;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanStateOutput;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanStateTaskRef;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class handles commands on policies in Apex models.
+ */
+public class PolicyHandler implements RestCommandHandler {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(PolicyHandler.class);
+
+    // Recurring string constants
+    private static final String OK = ": OK";
+    private static final String NOT_OK = ": Not OK";
+    private static final String POLICY_WAS_CREATED = "\". The policy was created, ";
+    private static final String POLICY_STATE_CREATED = "\". The policy and state were created, ";
+    private static final String POLICY_PARTIALLY_DEFINED = " The policy has only been partially defined.";
+    private static final String FOR_POLICY = "\" for policy \"";
+    private static final String IN_STATE = "\" in state \"";
+    private static final String POLICY_CREATED_STATE_ERROR = POLICY_WAS_CREATED
+                    + "but there was an error adding the state.";
+    private static final String POLICY_STATE_CREATED_OTHER_ERROR = POLICY_STATE_CREATED
+                    + "but there was an error adding the";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+
+        if (!RestCommandType.POLICY.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case CREATE:
+                return createPolicy(session, jsonString);
+            case UPDATE:
+                return updatePolicy(session, jsonString);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+        if (!RestCommandType.POLICY.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case LIST:
+                return listPolicies(session, name, version);
+            case DELETE:
+                return deletePolicy(session, name, version);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * Creates a policy with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed See {@linkplain BeanPolicy}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    public ApexApiResult createPolicy(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        final BeanPolicy jsonbean = RestUtils.getJsonParameters(jsonString, BeanPolicy.class);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().createPolicy(jsonbean.getName(), jsonbean.getVersion(),
+                        jsonbean.getTemplate(), jsonbean.getFirstState(), jsonbean.getUuid(),
+                        jsonbean.getDescription());
+
+        if (result.isOk()) {
+            result = createPolicyContent(session, jsonbean);
+        }
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Policy/Create" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Create the content of the policy.
+     * 
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed See {@linkplain BeanPolicy}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createPolicyContent(RestSession session, BeanPolicy jsonbean) {
+        ApexApiResult result = new ApexApiResult();
+
+        if (jsonbean.getStates() == null || jsonbean.getStates().isEmpty()) {
+            result.setResult(Result.FAILED);
+            result.addMessage("Null or empty state map; no states defined for policy \"" + jsonbean.getName() + ":"
+                            + jsonbean.getVersion()
+                            + "\". The policy was created, but there was an error adding states."
+                            + POLICY_PARTIALLY_DEFINED);
+            return result;
+        }
+
+        // States reference each other so all states must be created before they are populated
+        for (final Map.Entry<String, BeanState> stateEntry : jsonbean.getStates().entrySet()) {
+            ApexApiResult stateCreateResult = createState(session, jsonbean.getName(), jsonbean.getVersion(),
+                            stateEntry.getKey(), stateEntry.getValue());
+
+            if (stateCreateResult.isNok()) {
+                result.setResult(stateCreateResult.getResult());
+                result.addMessage(stateCreateResult.getMessage());
+            }
+        }
+
+        // Bale out if the state creation did not work
+        if (result.isNok()) {
+            return result;
+        }
+
+        // Now create the content of each state
+        for (final Map.Entry<String, BeanState> stateEntry : jsonbean.getStates().entrySet()) {
+            ApexApiResult stateContentCreateResult = createStateContent(session, jsonbean.getName(),
+                            jsonbean.getVersion(), stateEntry.getKey(), stateEntry.getValue());
+
+            if (stateContentCreateResult.isNok()) {
+                result.setResult(stateContentCreateResult.getResult());
+                result.addMessage(stateContentCreateResult.getMessage());
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create a state on the policy.
+     * 
+     * @param session the Apex model editing session
+     * @param policyName the policy name
+     * @param policVersion the policy version
+     * @param stateName the name of the state
+     * @param stateBean the information on the state to create
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createState(final RestSession session, final String policyName, final String policyVersion,
+                    final String stateName, final BeanState stateBean) {
+
+        if (stateBean == null) {
+            return new ApexApiResult(Result.FAILED,
+                            "Null or invalid state information for state \"" + stateName + FOR_POLICY + policyName + ":"
+                                            + policyVersion + POLICY_CREATED_STATE_ERROR + POLICY_PARTIALLY_DEFINED);
+        }
+
+        if (stateBean.getTrigger() == null) {
+            return new ApexApiResult(Result.FAILED,
+                            "Null or invalid state trigger for state \"" + stateName + FOR_POLICY + policyName + ":"
+                                            + policyVersion + POLICY_CREATED_STATE_ERROR + POLICY_PARTIALLY_DEFINED);
+        }
+
+        if (stateBean.getDefaultTask() == null) {
+            return new ApexApiResult(Result.FAILED, "Null or invalid default task for state \"" + stateName + FOR_POLICY
+                            + policyName + ":" + policyVersion + POLICY_CREATED_STATE_ERROR + POLICY_PARTIALLY_DEFINED);
+        }
+
+        return session.getApexModelEdited().createPolicyState(policyName, policyVersion, stateName,
+                        stateBean.getTrigger().getName(), stateBean.getTrigger().getVersion(),
+                        stateBean.getDefaultTask().getName(), stateBean.getDefaultTask().getVersion());
+    }
+
+    /**
+     * Create the content of a state on the policy.
+     * 
+     * @param session the Apex model editing session
+     * @param policyName the policy name
+     * @param policVersion the policy version
+     * @param stateName the name of the state
+     * @param stateBean the information on the state to create
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createStateContent(final RestSession session, final String policyName,
+                    final String policyVersion, final String stateName, final BeanState stateBean) {
+
+        ApexApiResult ret = createStateTaskSelectionLogic(session, policyName, policyVersion, stateName, stateBean);
+
+        if (ret.isOk()) {
+            ret = createStateContextReferences(session, policyName, policyVersion, stateName, stateBean);
+        }
+
+        if (ret.isOk()) {
+            ret = createStateFinalizers(session, policyName, policyVersion, stateName, stateBean);
+        }
+
+        if (ret.isOk()) {
+            ret = createStateOutputs(session, policyName, policyVersion, stateName, stateBean);
+        }
+
+        if (ret.isOk()) {
+            ret = createStateTaskReferences(session, policyName, policyVersion, stateName, stateBean);
+        }
+
+        return ret;
+    }
+
+    /**
+     * Create the task selection logic for the state.
+     * 
+     * @param session the Apex model editing session
+     * @param policyName the policy name
+     * @param policVersion the policy version
+     * @param stateName the name of the state
+     * @param stateBean the information on the state to create
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createStateTaskSelectionLogic(final RestSession session, final String policyName,
+                    final String policyVersion, final String stateName, final BeanState stateBean) {
+
+        final BeanLogic tsl = stateBean.getTaskSelectionLogic();
+        if (tsl == null) {
+            return new ApexApiResult();
+        }
+
+        ApexApiResult result = session.getApexModelEdited().createPolicyStateTaskSelectionLogic(policyName,
+                        policyVersion, stateName, tsl.getLogicFlavour(), tsl.getLogic());
+
+        if (result.isNok()) {
+            result.addMessage("Failed to add task selection logic for state \"" + stateName + "\" for" + " policy \""
+                            + policyName + ":" + policyVersion + POLICY_WAS_CREATED
+                            + "but there was an error adding the task selection logic "
+                            + "for the state. The policy has only been partially defined.");
+        }
+        return result;
+    }
+
+    /**
+     * Create the context references for the state.
+     * 
+     * @param session the Apex model editing session
+     * @param policyName the policy name
+     * @param policVersion the policy version
+     * @param stateName the name of the state
+     * @param stateBean the information on the state to create
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createStateContextReferences(final RestSession session, final String policyName,
+                    final String policyVersion, final String stateName, final BeanState stateBean) {
+
+        ApexApiResult result = new ApexApiResult();
+
+        final BeanKeyRef[] contextReferences = stateBean.getContexts();
+        if (contextReferences == null || contextReferences.length == 0) {
+            return result;
+        }
+
+        for (final BeanKeyRef contextReference : contextReferences) {
+            if (contextReference == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null or invalid context reference \"" + contextReference + "\" for" + " state \""
+                                + stateName + FOR_POLICY + policyName + ":" + policyVersion
+                                + "\". The policy was created, but there was an error adding the context "
+                                + "reference for the state. The policy has only been partially defined.");
+                continue;
+            }
+
+            ApexApiResult contextRefResult = session.getApexModelEdited().createPolicyStateContextRef(policyName,
+                            policyVersion, stateName, contextReference.getName(), contextReference.getVersion());
+
+            if (contextRefResult.isNok()) {
+                result.setResult(contextRefResult.getResult());
+                result.addMessage("Failed to add context reference \"" + contextReference + "\" for state \""
+                                + stateName + FOR_POLICY + policyName + ":" + policyVersion + POLICY_WAS_CREATED
+                                + "but there was an error adding the context reference "
+                                + "for the state. The policy has only been partially defined.");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the state finalizers for the state.
+     * 
+     * @param session the Apex model editing session
+     * @param policyName the policy name
+     * @param policVersion the policy version
+     * @param stateName the name of the state
+     * @param stateBean the information on the state to create
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createStateFinalizers(final RestSession session, final String policyName,
+                    final String policyVersion, final String stateName, final BeanState stateBean) {
+
+        ApexApiResult result = new ApexApiResult();
+
+        final Map<String, BeanLogic> finalizers = stateBean.getFinalizers();
+        if (finalizers == null || finalizers.isEmpty()) {
+            return result;
+        }
+
+        for (final Map.Entry<String, BeanLogic> finalizerEntry : finalizers.entrySet()) {
+            if (finalizerEntry.getKey() == null || finalizerEntry.getValue() == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null or invalid finalizer information for finalizer " + "named \""
+                                + finalizerEntry.getKey() + IN_STATE + stateName + FOR_POLICY + policyName + ":"
+                                + policyVersion + POLICY_STATE_CREATED_OTHER_ERROR + " finalizer. The policy has only "
+                                + "been partially defined.");
+                continue;
+            }
+
+            ApexApiResult finalizerResult = session.getApexModelEdited().createPolicyStateFinalizerLogic(policyName,
+                            policyVersion, stateName, finalizerEntry.getKey(),
+                            finalizerEntry.getValue().getLogicFlavour(), finalizerEntry.getValue().getLogic());
+
+            if (finalizerResult.isNok()) {
+                result.setResult(finalizerResult.getResult());
+                result.addMessage("Failed to add finalizer information for finalizer named \"" + finalizerEntry.getKey()
+                                + "\" in" + " state \"" + stateName + FOR_POLICY + policyName + ":" + policyVersion
+                                + POLICY_STATE_CREATED_OTHER_ERROR
+                                + " finalizer. The policy has only been partially defined.");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the state outputs for the state.
+     * 
+     * @param session the Apex model editing session
+     * @param policyName the policy name
+     * @param policVersion the policy version
+     * @param stateName the name of the state
+     * @param stateBean the information on the state to create
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createStateOutputs(final RestSession session, final String policyName,
+                    final String policyVersion, final String stateName, final BeanState stateBean) {
+
+        ApexApiResult result = new ApexApiResult();
+
+        final Map<String, BeanStateOutput> stateOutputs = stateBean.getStateOutputs();
+        if (stateOutputs == null || stateOutputs.isEmpty()) {
+            result.setResult(Result.FAILED);
+            result.addMessage("No state outputs have been defined in state \"" + stateName + FOR_POLICY + policyName
+                            + ":" + policyVersion
+                            + "\". The policy and state were created, but there was an error adding state"
+                            + " outputs. The policy has only been partially defined.");
+            return result;
+        }
+
+        for (final Map.Entry<String, BeanStateOutput> stateOutput : stateOutputs.entrySet()) {
+            final String outputName = stateOutput.getKey();
+            final BeanStateOutput output = stateOutput.getValue();
+
+            if (outputName == null || output == null || output.getEvent() == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null or invalid output information for output named \"" + outputName + IN_STATE
+                                + stateName + FOR_POLICY + policyName + ":" + policyVersion
+                                + POLICY_STATE_CREATED_OTHER_ERROR
+                                + " output. The policy has only been partially defined.");
+                continue;
+            }
+
+            ApexApiResult outputResult = session.getApexModelEdited().createPolicyStateOutput(policyName, policyVersion,
+                            stateName, outputName, output.getEvent().getName(), output.getEvent().getVersion(),
+                            output.getNextState());
+
+            if (outputResult.isNok()) {
+                result.setResult(outputResult.getResult());
+                result.addMessage("Failed to add output information for output named \"" + outputName + IN_STATE
+                                + stateName + FOR_POLICY + policyName + ":" + policyVersion + POLICY_STATE_CREATED
+                                + "but there was an error adding the output." + POLICY_PARTIALLY_DEFINED);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the task references for the state.
+     * 
+     * @param session the Apex model editing session
+     * @param policyName the policy name
+     * @param policVersion the policy version
+     * @param stateName the name of the state
+     * @param stateBean the information on the state to create
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createStateTaskReferences(final RestSession session, final String policyName,
+                    final String policyVersion, final String stateName, final BeanState stateBean) {
+
+        ApexApiResult result = new ApexApiResult();
+
+        final Map<String, BeanStateTaskRef> taskMap = stateBean.getTasks();
+        if (taskMap == null || taskMap.isEmpty()) {
+            result.setResult(Result.FAILED);
+            result.addMessage("No tasks have been defined in state \"" + stateName + FOR_POLICY + policyName + ":"
+                            + policyVersion
+                            + "\". The policy and state were created, but there was an error adding tasks."
+                            + POLICY_PARTIALLY_DEFINED);
+            return result;
+        }
+
+        for (final Map.Entry<String, BeanStateTaskRef> taskEntry : taskMap.entrySet()) {
+            final String taskLocalName = taskEntry.getKey();
+            final BeanStateTaskRef taskReference = taskEntry.getValue();
+
+            if (taskLocalName == null || taskReference == null || taskReference.getTask() == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null or invalid task information for task named \"" + taskLocalName + IN_STATE
+                                + stateName + "\" for for policy \"" + policyName + ":" + policyVersion
+                                + "\". The policy and state were created, but there was an error adding the "
+                                + "task. The policy has only been partially defined.");
+                continue;
+            }
+
+            ApexApiResult taskRefResult = session.getApexModelEdited().createPolicyStateTaskRef(policyName,
+                            policyVersion, stateName, taskLocalName, taskReference.getTask().getName(),
+                            taskReference.getTask().getVersion(), taskReference.getOutputType(),
+                            taskReference.getOutputName());
+
+            if (taskRefResult.isNok()) {
+                result.setResult(taskRefResult.getResult());
+                result.addMessage("Failed to add task reference \"" + taskEntry + "\" for state \"" + stateName
+                                + FOR_POLICY + policyName + ":" + policyVersion + POLICY_WAS_CREATED
+                                + "but there was an error adding the task reference for"
+                                + " the state. The policy has only been partially defined.");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Update a policy with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanPolicy}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult updatePolicy(final RestSession session, final String jsonString) {
+
+        LOGGER.entry(jsonString);
+
+        final BeanPolicy jsonbean = RestUtils.getJsonParameters(jsonString, BeanPolicy.class);
+
+        if (blank2Null(jsonbean.getName()) == null || blank2Null(jsonbean.getVersion()) == null) {
+            LOGGER.exit("Task/Update" + NOT_OK);
+            return new ApexApiResult(Result.FAILED, "Null/Empty Policy name/version (\"" + jsonbean.getName() + ":"
+                            + jsonbean.getVersion() + "\" passed to UpdatePolicy");
+        }
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().deletePolicy(jsonbean.getName(), jsonbean.getVersion());
+
+        if (result.isOk()) {
+            result = session.getApexModelEdited().createPolicy(jsonbean.getName(), jsonbean.getVersion(),
+                            jsonbean.getTemplate(), jsonbean.getFirstState(), jsonbean.getUuid(),
+                            jsonbean.getDescription());
+
+            if (result.isOk()) {
+                result = createPolicyContent(session, jsonbean);
+            }
+        }
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Policy/Update" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+
+    }
+
+    /**
+     * List policies with the given key names/versions. If successful the result(s) will be available in the result
+     * messages. The returned value(s) will be similar to {@link AxPolicy}, with merged {@linkplain AxKey Info} for the
+     * root object.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult listPolicies(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().listPolicy(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("Policy/Get" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Delete policies with the given key names/versions.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult deletePolicy(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        session.editModel();
+
+        // all input/output fields, parameters, logic, context references is "owned"/contained
+        // in the task, so
+        // deleting the task removes all of these
+        ApexApiResult result = session.getApexModelEdited().deletePolicy(blank2Null(name), blank2Null(version));
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Policy/Delete" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommand.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommand.java
new file mode 100644 (file)
index 0000000..7b1bc02
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+/**
+ * This enum maps REST calls to the handlers that process them.
+ *
+ */
+public enum RestCommand {
+    /**
+     * Create the target.
+     */
+    CREATE,
+    /**
+     * Update the target.
+     */
+    UPDATE,
+    /**
+     * List the target.
+     */
+    LIST,
+    /**
+     * Delete the target.
+     */
+    DELETE,
+    /**
+     * Validate the target.
+     */
+    VALIDATE,
+    /**
+     * Load the target.
+     */
+    LOAD,
+    /**
+     * Analyse the target.
+     */
+    ANALYSE,
+    /**
+     * Get the key of the currently loaded apex model.
+     */
+    GET_KEY,
+    /**
+     * Download the currently loaded apex model.
+     */
+    DOWNLOAD
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommandHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommandHandler.java
new file mode 100644 (file)
index 0000000..c4fd6d6
--- /dev/null
@@ -0,0 +1,102 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+
+// TODO: Auto-generated Javadoc
+/**
+ * This interface defines the methods that a REST handler must implement to handle REST editor commands.
+ *
+ */
+public interface RestCommandHandler {
+
+    /**
+     * Process a REST command.
+     *
+     * @param session the Apex editor session
+     * @param commandType the type of REST command to execute
+     * @param command the REST command to execute
+     * @return the apex api result the result of the execution
+     */
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command);
+
+    /**
+     * Process a REST command.
+     *
+     * @param session the Apex editor session
+     * @param commandType the type of REST command to execute
+     * @param command the REST command to execute
+     * @param jsonString the json string to use to execute the command
+     * @return the apex api result the result of the execution
+     */
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString);
+
+    /**
+     * Process a REST command.
+     *
+     * @param session the Apex editor session
+     * @param commandType the type of REST command to execute
+     * @param command the REST command to execute
+     * @param name the concept name on which to execute
+     * @param version the concept version the version on which to execute
+     * @return the apex api result the result of the execution
+     */
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version);
+
+    /**
+     * Get an unsupported command result message.
+     *
+     * @param session the Apex editor session
+     * @param commandType the type of REST command to execute
+     * @param command the REST command to execute
+     */
+    public default ApexApiResult getUnsupportedCommandResultMessage(final RestSession session,
+                    final RestCommandType commandType, final RestCommand command) {
+        return new ApexApiResult(Result.FAILED, "session " + session.getSessionId() + ", command type " + commandType
+                        + ", command" + command + " invalid");
+    }
+    
+    /**
+     * Convert blank incoming fields to nulls.
+     * 
+     * @param incomingField the field to check
+     * @return null if the field is blank, otherwise, the field trimmed
+     */
+    public default String blank2Null(final String incomingField) {
+        if (incomingField == null) {
+            return null;
+        }
+        
+        String trimmedField = incomingField.trim();
+        
+        if (trimmedField.isEmpty()) {
+            return null;
+        }
+        else {
+            return trimmedField;
+        }
+    }
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommandType.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestCommandType.java
new file mode 100644 (file)
index 0000000..c546cb0
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+/**
+ * This enum maps REST calls to the handlers that process them.
+ *
+ */
+public enum RestCommandType {
+    /**
+     * Model commands.
+     */
+    MODEL,
+    /**
+     * Key Information commands.
+     */
+    KEY_INFO,
+    /**
+     * Context schema commands.
+     */
+    CONTEXT_SCHEMA,
+    /**
+     * Context album commands.
+     */
+    CONTEXT_ALBUM,
+    /**
+     * Event Commands.
+     */
+    EVENT,
+    /**
+     * Task commands.
+     */
+    TASK,
+    /**
+     * Policy commands.
+     */
+    POLICY
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestSession.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestSession.java
new file mode 100644 (file)
index 0000000..3e616ef
--- /dev/null
@@ -0,0 +1,125 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+import org.onap.policy.apex.model.modelapi.ApexModel;
+import org.onap.policy.apex.model.modelapi.ApexModelFactory;
+
+/**
+ * This class represents an ongoing editor session in the Apex editor and holds the information for the session.
+ *
+ */
+public class RestSession {
+    // The ID of the session
+    private int sessionId;
+    
+    // The Apex policy model of the session
+    private ApexModel apexModel;
+
+    // The Apex policy model being edited
+    private ApexModel apexModelEdited;
+
+    public RestSession(final int sessionId) {
+        this.sessionId = sessionId;
+        this.apexModel = new ApexModelFactory().createApexModel(null, true);
+    }
+
+    /**
+     * Commence making changes to the Apex model.
+     * @return the result of the edit commencement operation
+     */
+    public synchronized ApexApiResult editModel() {
+        if (apexModelEdited != null) {
+            return new ApexApiResult(Result.FAILED, "model is already being edited");
+        }
+        
+        apexModelEdited = apexModel.clone();
+        return new ApexApiResult();
+    }
+    
+    /**
+     * Commit the changes to the Apex model.
+     * @return the result of the commit operation
+     */
+    public synchronized ApexApiResult commitChanges() {
+        if (apexModelEdited == null) {
+            return new ApexApiResult(Result.FAILED, "model is not being edited");
+        }
+        
+        apexModel = apexModelEdited;
+        apexModelEdited = null;
+        return new ApexApiResult();
+    }
+    
+    /**
+     * Discard the changes to the Apex model.
+     * @return the result of the discard operation
+     */
+    public synchronized ApexApiResult discardChanges() {
+        if (apexModelEdited == null) {
+            return new ApexApiResult(Result.FAILED, "model is not being edited");
+        }
+        
+        apexModelEdited = null;
+        return new ApexApiResult();
+    }
+    
+
+    /**
+     * Finish a session by committing or discarding the changes.
+     * 
+     * @param commitFlag if ture, commit changes otherwise discard them
+     */
+    public void finishSession(boolean commitFlag) {
+        if (commitFlag) {
+            commitChanges();
+        }
+        else {
+            discardChanges();
+        }
+    }
+
+    /**
+     * Get the session ID of the session.
+     * @return the sessionId
+     */
+    public int getSessionId() {
+        return sessionId;
+    }
+
+    /**
+     * Get the Apex model of the session.
+     * @return the apexModel
+     */
+    public ApexModel getApexModel() {
+        return apexModel;
+    }
+
+    /**
+     * Get the edited Apex model of the session.
+     * @return the apexModel
+     */
+    public ApexModel getApexModelEdited() {
+        return apexModelEdited;
+    }
+}
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestSessionHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/RestSessionHandler.java
new file mode 100644 (file)
index 0000000..b717944
--- /dev/null
@@ -0,0 +1,110 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class carries out session handling for Apex REST editor sessions.
+ */
+public class RestSessionHandler {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(RestSessionHandler.class);
+
+    // The next session will have this number, stating at 0
+    private AtomicInteger nextSessionId = new AtomicInteger();
+
+    // All REST editor sessions being handled by this handler
+    private final Map<Integer, RestSession> sessionMap = new TreeMap<>();
+
+    /**
+     * Create a new session.
+     * @param result the result of session creation
+     * @return the new session object
+     */
+    public RestSession createSession(ApexApiResult result) {
+        LOGGER.entry("creating session");
+        
+        // Create the session with the next session ID
+        final int newSessionId = nextSessionId.getAndIncrement();
+        sessionMap.put(newSessionId, new RestSession(newSessionId));
+
+        result.addMessage(Integer.toString(newSessionId));
+        
+        LOGGER.exit("created session with ID: " + newSessionId);
+        return sessionMap.get(newSessionId);
+    }
+
+    /**
+     * Get a session for the given session ID.
+     * @param sessionId the session ID of the session we require
+     * @param result the result of the session get
+     * @return the session
+     */
+    public RestSession getSession(final int sessionId, ApexApiResult result) {
+        LOGGER.entry("finding session: " + sessionId);
+
+        // Check for valid session IDs
+        if (sessionId < 0) {
+            result.setResult(Result.FAILED);
+            result.addMessage("Session ID  \"" + sessionId + "\" is negative");
+            LOGGER.exit(result.getMessage());
+            return null;
+        }
+
+        // Check if session exits
+        if (!sessionMap.containsKey(sessionId)) {
+            result.setResult(Result.FAILED);
+            result.addMessage("A session with session ID \"" + sessionId + "\" does not exist");
+            LOGGER.exit(result.getMessage());
+            return null;
+        }
+        
+        RestSession session = sessionMap.get(sessionId);
+        
+        // Check if session is valid
+        if (session == null) {
+            result.setResult(Result.FAILED);
+            result.addMessage("The session with session ID \"" + sessionId + "\" is corrupt");
+            LOGGER.exit(result.getMessage());
+            return null;
+        }
+        
+        // Return the session
+        LOGGER.exit("session found: " + sessionId);
+        return session;
+    }
+
+    /*
+     * This is a test method to set a corrupt session ID in the session map
+     * @param corruptSessionId the ID of the corrupt session
+     */
+    protected void setCorruptSession(int corruptSessionId) {
+        sessionMap.put(corruptSessionId, null);
+    }
+}
@@ -18,7 +18,7 @@
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.policy.apex.client.editor.rest;
+package org.onap.policy.apex.client.editor.rest.handling;
 
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonArray;
@@ -40,7 +40,7 @@ import javax.xml.bind.Unmarshaller;
 import javax.xml.transform.stream.StreamSource;
 
 import org.eclipse.persistence.jaxb.MarshallerProperties;
-import org.onap.policy.apex.client.editor.rest.bean.BeanBase;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanBase;
 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
 
 /**
diff --git a/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/TaskHandler.java b/client/client-editor/src/main/java/org/onap/policy/apex/client/editor/rest/handling/TaskHandler.java
new file mode 100644 (file)
index 0000000..efef440
--- /dev/null
@@ -0,0 +1,460 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 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.client.editor.rest.handling;
+
+import java.util.Map.Entry;
+
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanField;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanKeyRef;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanLogic;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanTask;
+import org.onap.policy.apex.client.editor.rest.handling.bean.BeanTaskParameter;
+import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
+import org.onap.policy.apex.model.modelapi.ApexApiResult;
+import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
+import org.onap.policy.apex.model.policymodel.concepts.AxTask;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class handles commands on tasks in Apex models.
+ */
+public class TaskHandler implements RestCommandHandler {
+    // Get a reference to the logger
+    private static final XLogger LOGGER = XLoggerFactory.getXLogger(TaskHandler.class);
+
+    // Recurring string constants
+    private static final String OK = ": OK";
+    private static final String NOT_OK = ": Not OK";
+    private static final String IN_TASK = "\" in task ";
+    private static final String TASK_PARTIALLY_DEFINED = " The task has only been partially defined.";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command) {
+        return getUnsupportedCommandResultMessage(session, commandType, command);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String jsonString) {
+        if (!RestCommandType.TASK.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case CREATE:
+                return createTask(session, jsonString);
+            case UPDATE:
+                return updateTask(session, jsonString);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
+                    final RestCommand command, final String name, final String version) {
+        if (!RestCommandType.TASK.equals(commandType)) {
+            return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+
+        switch (command) {
+            case LIST:
+                return listTasks(session, name, version);
+            case DELETE:
+                return deleteTask(session, name, version);
+            case VALIDATE:
+                return validateTask(session, name, version);
+            default:
+                return getUnsupportedCommandResultMessage(session, commandType, command);
+        }
+    }
+
+    /**
+     * Creates a task with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanTask}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createTask(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        final BeanTask jsonbean = RestUtils.getJsonParameters(jsonString, BeanTask.class);
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().createTask(jsonbean.getName(), jsonbean.getVersion(),
+                        jsonbean.getUuid(), jsonbean.getDescription());
+
+        if (result.isOk()) {
+            result = createTaskContent(session, jsonbean);
+        }
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Task/Create" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Create the content of the task.
+     * 
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanTask}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult createTaskContent(final RestSession session, final BeanTask jsonbean) {
+        ApexApiResult result = createInputFields(session, jsonbean);
+
+        if (result.isOk()) {
+            result = createOutputFields(session, jsonbean);
+        }
+
+        if (result.isOk()) {
+            result = createTaskLogic(session, jsonbean);
+        }
+
+        if (result.isOk()) {
+            result = createTaskParameters(session, jsonbean);
+        }
+
+        if (result.isOk()) {
+            result = createContextReferences(session, jsonbean);
+        }
+        return result;
+    }
+
+    /**
+     * Create the input fields for the task.
+     * 
+     * @param session the Apex model editing session
+     * @param jsonbean the ban containing the fields
+     * @return the result of the operation
+     */
+    private ApexApiResult createInputFields(final RestSession session, final BeanTask jsonbean) {
+        ApexApiResult result = new ApexApiResult();
+
+        if (jsonbean.getInputFields() == null || jsonbean.getInputFields().isEmpty()) {
+            return result;
+        }
+
+        for (final Entry<String, BeanField> fieldEntry : jsonbean.getInputFields().entrySet()) {
+            if (fieldEntry.getValue() == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null task input field information for field \"" + fieldEntry.getKey() + IN_TASK
+                                + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                + ". The task was created, but there was an error adding the input fields."
+                                + TASK_PARTIALLY_DEFINED);
+                continue;
+            }
+
+            if (fieldEntry.getKey() == null || !fieldEntry.getKey().equals(fieldEntry.getValue().getLocalName())) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Invalid task input field information for field \"" + fieldEntry.getKey() + IN_TASK
+                                + jsonbean.getName() + ":" + jsonbean.getVersion() + ". The localName of the field (\""
+                                + fieldEntry.getValue().getLocalName() + "\") is not the same as the field name. "
+                                + "The task was created, but there was an error adding the input fields."
+                                + TASK_PARTIALLY_DEFINED);
+            } else {
+                ApexApiResult fieldCreationResult = session.getApexModelEdited().createTaskInputField(
+                                jsonbean.getName(), jsonbean.getVersion(), fieldEntry.getKey(),
+                                fieldEntry.getValue().getName(), fieldEntry.getValue().getVersion(),
+                                fieldEntry.getValue().getOptional());
+
+                if (fieldCreationResult.isNok()) {
+                    result.setResult(fieldCreationResult.getResult());
+                    result.addMessage("Failed to add task input field information for field \"" + fieldEntry.getKey()
+                                    + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                    + ". The task was created, but there was an error adding the input fields."
+                                    + TASK_PARTIALLY_DEFINED);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the output fields for the task.
+     * 
+     * @param session the Apex model editing session
+     * @param jsonbean the ban containing the fields
+     * @return the result of the operation
+     */
+    private ApexApiResult createOutputFields(final RestSession session, final BeanTask jsonbean) {
+        ApexApiResult result = new ApexApiResult();
+
+        if (jsonbean.getOutputFields() == null || jsonbean.getOutputFields().isEmpty()) {
+            return result;
+        }
+
+        for (final Entry<String, BeanField> fieldEntry : jsonbean.getOutputFields().entrySet()) {
+            if (fieldEntry.getValue() == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null task output field information for field \"" + fieldEntry.getKey() + IN_TASK
+                                + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                + ". The task was created, but there was an error adding the output fields."
+                                + TASK_PARTIALLY_DEFINED);
+                continue;
+            }
+
+            if (fieldEntry.getKey() == null || !fieldEntry.getKey().equals(fieldEntry.getValue().getLocalName())) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Invalid task output field information for field \"" + fieldEntry.getKey() + IN_TASK
+                                + jsonbean.getName() + ":" + jsonbean.getVersion() + ". The localName of the field (\""
+                                + fieldEntry.getValue().getLocalName() + "\") is not the same as the field name. "
+                                + "The task was created, but there was an error adding the output fields."
+                                + TASK_PARTIALLY_DEFINED);
+            } else {
+                ApexApiResult fieldCreationResult = session.getApexModelEdited().createTaskOutputField(
+                                jsonbean.getName(), jsonbean.getVersion(), fieldEntry.getKey(),
+                                fieldEntry.getValue().getName(), fieldEntry.getValue().getVersion(),
+                                fieldEntry.getValue().getOptional());
+                if (fieldCreationResult.isNok()) {
+                    result.setResult(fieldCreationResult.getResult());
+                    result.addMessage("Failed to add task output field information for field \"" + fieldEntry.getKey()
+                                    + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                    + ". The task was created, but there was an error adding the output fields."
+                                    + TASK_PARTIALLY_DEFINED);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the task logic for the task.
+     * 
+     * @param session the Apex model editing session
+     * @param jsonbean the bean containing the logic
+     * @return the result of the operation
+     */
+    private ApexApiResult createTaskLogic(final RestSession session, final BeanTask jsonbean) {
+        ApexApiResult result = new ApexApiResult();
+
+        if (jsonbean.getTaskLogic() == null) {
+            return result;
+        }
+
+        final BeanLogic logic = jsonbean.getTaskLogic();
+        result = session.getApexModelEdited().createTaskLogic(jsonbean.getName(), jsonbean.getVersion(),
+                        logic.getLogicFlavour(), logic.getLogic());
+
+        if (result.isNok()) {
+            result.addMessage("Failed to add task logic in task " + jsonbean.getName() + ":" + jsonbean.getVersion()
+                            + ". The task was created, but there was an error adding the logic."
+                            + TASK_PARTIALLY_DEFINED);
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the task parameters for the task.
+     * 
+     * @param session the Apex model editing session
+     * @param jsonbean the bean containing the parameters
+     * @return the result of the operation
+     */
+    private ApexApiResult createTaskParameters(final RestSession session, final BeanTask jsonbean) {
+        ApexApiResult result = new ApexApiResult();
+
+        if (jsonbean.getParameters() == null || jsonbean.getParameters().isEmpty()) {
+            return result;
+        }
+
+        for (final Entry<String, BeanTaskParameter> parameterEntry : jsonbean.getParameters().entrySet()) {
+            if (parameterEntry.getKey() == null || parameterEntry.getValue() == null
+                            || !parameterEntry.getKey().equals(parameterEntry.getValue().getParameterName())) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null or invalid task parameter information for parameter \""
+                                + parameterEntry.getKey() + IN_TASK + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                + ". The task was created, " + "but there was an error adding the parameters."
+                                + TASK_PARTIALLY_DEFINED);
+                continue;
+            }
+            ApexApiResult createParResult = session.getApexModelEdited().createTaskParameter(jsonbean.getName(),
+                            jsonbean.getVersion(), parameterEntry.getValue().getParameterName(),
+                            parameterEntry.getValue().getDefaultValue());
+            if (createParResult.isNok()) {
+                result.setResult(createParResult.getResult());
+                result.addMessage("Failed to add task parameter \"" + parameterEntry.getKey() + IN_TASK
+                                + jsonbean.getName() + ":" + jsonbean.getVersion()
+                                + ". The task was created, but there was an error adding the parameters."
+                                + TASK_PARTIALLY_DEFINED);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the context references for the task.
+     * 
+     * @param session the Apex model editing session
+     * @param jsonbean the bean containing the context references
+     * @return the result of the operation
+     */
+    private ApexApiResult createContextReferences(final RestSession session, final BeanTask jsonbean) {
+        ApexApiResult result = new ApexApiResult();
+
+        if (jsonbean.getContexts() == null || jsonbean.getContexts().length == 0) {
+            return result;
+        }
+
+        for (final BeanKeyRef contextalbum : jsonbean.getContexts()) {
+            if (contextalbum.getName() == null || contextalbum.getVersion() == null) {
+                result.setResult(Result.FAILED);
+                result.addMessage("Null or invalid context album reference information in task " + jsonbean.getName()
+                                + ":" + jsonbean.getVersion()
+                                + ". The task was created, but there was an error adding the"
+                                + " context album reference. " + "The task has only been partially defined.");
+                continue;
+            }
+            ApexApiResult createRefResult = session.getApexModelEdited().createTaskContextRef(jsonbean.getName(),
+                            jsonbean.getVersion(), contextalbum.getName(), contextalbum.getVersion());
+            if (createRefResult.isNok()) {
+                result.setResult(createRefResult.getResult());
+                result.addMessage("Failed to add context album reference information in task " + jsonbean.getName()
+                                + ":" + jsonbean.getVersion()
+                                + ". The task was created, but there was an error adding the"
+                                + " context album reference. " + "The task has only been partially defined.");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Update a task with the information in the JSON string passed.
+     *
+     * @param session the Apex model editing session
+     * @param jsonString the JSON string to be parsed. See {@linkplain BeanTask}
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult updateTask(final RestSession session, final String jsonString) {
+        LOGGER.entry(jsonString);
+
+        final BeanTask jsonbean = RestUtils.getJsonParameters(jsonString, BeanTask.class);
+
+        if (blank2Null(jsonbean.getName()) == null || blank2Null(jsonbean.getVersion()) == null) {
+            LOGGER.exit("Task/Update" + NOT_OK);
+            return new ApexApiResult(Result.FAILED, "Null/Empty task name/version (\"" + jsonbean.getName() + ":"
+                            + jsonbean.getVersion() + "\" passed to UpdateTask");
+        }
+
+        session.editModel();
+
+        ApexApiResult result = session.getApexModelEdited().deleteTask(jsonbean.getName(), jsonbean.getVersion());
+
+        if (result.isOk()) {
+            result = session.getApexModelEdited().createTask(jsonbean.getName(), jsonbean.getVersion(),
+                            jsonbean.getUuid(), jsonbean.getDescription());
+
+            if (result.isOk()) {
+                result = createTaskContent(session, jsonbean);
+            }
+        }
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Task/Update" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * List tasks with the given key names/versions. If successful the result(s) will be available in the result
+     * messages. The returned value(s) will be similar to {@link AxTask}, with merged {@linkplain AxKeyInfo} for the
+     * root object.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult listTasks(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().listTask(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("Task/Get" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Delete tasks with the given key names/versions.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult deleteTask(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        session.editModel();
+
+        // all input/output fields, parameters, logic, context references is "owned"/contained
+        // in the task, so
+        // deleting the task removes all of these
+        ApexApiResult result = session.getApexModelEdited().deleteTask(blank2Null(name), blank2Null(version));
+
+        session.finishSession(result.isOk());
+
+        LOGGER.exit("Task/Delete" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+
+    /**
+     * Validate tasks with the given key names/versions. The result(s) will be available in the result messages.
+     *
+     * @param session the Apex model editing session
+     * @param name the name to search for. If null or empty, then all names will be queried
+     * @param version the version to search for. If null then all versions will be searched for.
+     * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
+     *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
+     */
+    private ApexApiResult validateTask(final RestSession session, final String name, final String version) {
+        LOGGER.entry(name, version);
+
+        ApexApiResult result = session.getApexModel().validateTask(blank2Null(name), blank2Null(version));
+
+        LOGGER.exit("Validate/Task" + (result != null && result.isOk() ? OK : NOT_OK));
+        return result;
+    }
+}
diff --git a/client/client-editor/src/main/resources/templates/PeriodicEventTemplate.json b/client/client-editor/src/main/resources/templates/PeriodicEventTemplate.json
new file mode 100644 (file)
index 0000000..a265651
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "name": "PeriodicEvent",
+    "version": "0.0.1",
+    "uuid": "40f28ab0-bc27-11e8-a355-529269fb1459",
+    "description": "Default Periodic Event",
+    "source": "System",
+    "target": "Apex",
+    "nameSpace": "org.onap.policy.apex.domains.aadm.events",
+    "parameters": {
+    }
+}
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.policy.apex.client.editor.rest;
+package org.onap.policy.apex.client.editor.rest.handling;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertNotNull;
 
 import java.io.IOException;
 
@@ -146,26 +146,17 @@ public class TestApexEditorRestResource extends JerseyTest {
         result = target("editor/12345/Model/Get").request().get(ApexApiResult.class);
         assertEquals(Result.FAILED, result.getResult());
 
-        try {
-            result = target("editor/" + corruptSessionId + "/Model/Download").request().get(ApexApiResult.class);
-        } catch (final Exception e) {
-            assertEquals("HTTP 500 Request failed.", e.getMessage());
-        }
+        String resultString = target("editor/" + corruptSessionId + "/Model/Download").request().get(String.class);
+        assertEquals("", resultString);
 
-        result = target("editor/" + sessionId + "/Model/Download").request().get(ApexApiResult.class);
-        assertEquals(Result.SUCCESS, result.getResult());
-        try {
-            target("editor/-12345/Model/Download").request().get(ApexApiResult.class);
-            fail("test should throw an exception here");
-        } catch (final Exception e) {
-            assertEquals("HTTP 500 Request failed.", e.getMessage());
-        }
-        try {
-            target("editor/12345/Model/Download").request().get(ApexApiResult.class);
-            fail("test should throw an exception here");
-        } catch (final Exception e) {
-            assertEquals("HTTP 500 Request failed.", e.getMessage());
-        }
+        resultString = target("editor/" + sessionId + "/Model/Download").request().get(String.class);
+        assertNotNull(resultString);
+
+        resultString = target("editor/-12345/Model/Download").request().get(String.class);
+        assertEquals("", resultString);
+
+        resultString = target("editor/12345/Model/Download").request().get(String.class);
+        assertEquals("", resultString);
 
         try {
             result = target("editor/" + corruptSessionId + "/KeyInformation/Get").request().get(ApexApiResult.class);
@@ -347,11 +338,11 @@ public class TestApexEditorRestResource extends JerseyTest {
         }
 
         result = target("editor/" + sessionId + "/Validate/ContextAlbum").request().get(ApexApiResult.class);
-        assertEquals(ApexApiResult.Result.SUCCESS, result.getResult());
+        assertEquals(ApexApiResult.Result.CONCEPT_DOES_NOT_EXIST, result.getResult());
 
         result = target("editor/" + sessionId + "/Validate/ContextAlbum").queryParam("name", (String) null)
                 .queryParam("version", (String) null).request().get(ApexApiResult.class);
-        assertEquals(ApexApiResult.Result.SUCCESS, result.getResult());
+        assertEquals(ApexApiResult.Result.CONCEPT_DOES_NOT_EXIST, result.getResult());
 
         result = target("editor/" + sessionId + "/Validate/ContextAlbum").queryParam("name", "%%%$£")
                 .queryParam("version", (String) null).request().get(ApexApiResult.class);
@@ -471,7 +462,7 @@ public class TestApexEditorRestResource extends JerseyTest {
         assertEquals(ApexApiResult.Result.FAILED, result.getResult());
 
         result = target("editor/" + sessionId + "/Validate/Event").request().get(ApexApiResult.class);
-        assertEquals(ApexApiResult.Result.SUCCESS, result.getResult());
+        assertEquals(ApexApiResult.Result.CONCEPT_DOES_NOT_EXIST, result.getResult());
 
         try {
             target("editor/" + corruptSessionId + "/Validate/Event").request().get(ApexApiResult.class);
@@ -481,7 +472,7 @@ public class TestApexEditorRestResource extends JerseyTest {
 
         result = target("editor/" + sessionId + "/Validate/Event").queryParam("name", (String) null)
                 .queryParam("version", (String) null).request().get(ApexApiResult.class);
-        assertEquals(ApexApiResult.Result.SUCCESS, result.getResult());
+        assertEquals(ApexApiResult.Result.CONCEPT_DOES_NOT_EXIST, result.getResult());
 
         result = target("editor/" + sessionId + "/Validate/Event").queryParam("name", "%%%$£")
                 .queryParam("version", (String) null).request().get(ApexApiResult.class);
@@ -666,7 +657,7 @@ public class TestApexEditorRestResource extends JerseyTest {
         assertEquals(ApexApiResult.Result.FAILED, result.getResult());
 
         result = target("editor/" + sessionId + "/Validate/Task").request().get(ApexApiResult.class);
-        assertEquals(ApexApiResult.Result.SUCCESS, result.getResult());
+        assertEquals(ApexApiResult.Result.CONCEPT_DOES_NOT_EXIST, result.getResult());
 
         try {
             target("editor/" + corruptSessionId + "/Validate/Task").request().get(ApexApiResult.class);
@@ -676,7 +667,7 @@ public class TestApexEditorRestResource extends JerseyTest {
 
         result = target("editor/" + sessionId + "/Validate/Task").queryParam("name", (String) null)
                 .queryParam("version", (String) null).request().get(ApexApiResult.class);
-        assertEquals(ApexApiResult.Result.SUCCESS, result.getResult());
+        assertEquals(ApexApiResult.Result.CONCEPT_DOES_NOT_EXIST, result.getResult());
 
         result = target("editor/" + sessionId + "/Validate/Task").queryParam("name", "%%%$£")
                 .queryParam("version", (String) null).request().get(ApexApiResult.class);
@@ -885,7 +876,7 @@ public class TestApexEditorRestResource extends JerseyTest {
                 + "\"description\"      : \"A description of hello\"" + "}";
         entity = Entity.entity(entityString, MediaType.APPLICATION_JSON);
         result = target("editor/" + sessionId + "/Task/Create").request().post(entity, ApexApiResult.class);
-        assertEquals(ApexApiResult.Result.FAILED, result.getResult());
+        assertEquals(ApexApiResult.Result.CONCEPT_DOES_NOT_EXIST, result.getResult());
 
         entityString = "{" + "\"name\"             : \"Howdy5\"," + "\"version\"          : \"0.0.2\","
                 + "\"contexts\"         : [{\"name\" : null, \"version\" : \"0.0.1\"}],"
@@ -18,7 +18,7 @@
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.policy.apex.client.editor.rest.bean;
+package org.onap.policy.apex.client.editor.rest.handling.bean;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
index b551a06..bfdd082 100644 (file)
@@ -30,6 +30,7 @@ import org.onap.policy.apex.context.parameters.ContextParameterConstants;
 import org.onap.policy.apex.context.parameters.ContextParameters;
 import org.onap.policy.apex.context.parameters.SchemaParameters;
 import org.onap.policy.apex.core.engine.EngineParameters;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
 import org.onap.policy.apex.plugins.executor.java.JavaExecutorParameters;
 import org.onap.policy.common.parameters.ParameterService;
@@ -98,6 +99,7 @@ public class TestApexEngineJava {
     @Test
     public void testApexEngineJava() throws InterruptedException, IOException, ApexException {
         new TestApexEngine("JAVA", engineParameters);
+        ThreadUtilities.sleep(5000);
         new TestApexEngine("JAVA", engineParameters);
     }
 }
index 51e39cf..05068fc 100644 (file)
@@ -30,6 +30,7 @@ import org.onap.policy.apex.context.parameters.ContextParameterConstants;
 import org.onap.policy.apex.context.parameters.ContextParameters;
 import org.onap.policy.apex.context.parameters.SchemaParameters;
 import org.onap.policy.apex.core.engine.EngineParameters;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
 import org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters;
 import org.onap.policy.common.parameters.ParameterService;
@@ -97,6 +98,7 @@ public class TestApexEngineJavascript {
     public void testApexEngineJavascript() throws ApexException, InterruptedException, IOException {
 
         new TestApexEngine("JAVASCRIPT", engineParameters);
+        ThreadUtilities.sleep(5000);
         new TestApexEngine("JAVASCRIPT", engineParameters);
     }
 }
index 163a60d..12a28e2 100644 (file)
@@ -30,6 +30,7 @@ import org.onap.policy.apex.context.parameters.ContextParameterConstants;
 import org.onap.policy.apex.context.parameters.ContextParameters;
 import org.onap.policy.apex.context.parameters.SchemaParameters;
 import org.onap.policy.apex.core.engine.EngineParameters;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
 import org.onap.policy.apex.plugins.executor.jython.JythonExecutorParameters;
 import org.onap.policy.common.parameters.ParameterService;
@@ -96,6 +97,7 @@ public class TestApexEngineJython {
     @Test
     public void testApexEngineJython() throws ApexException, InterruptedException, IOException {
         new TestApexEngine("JYTHON", engineParameters);
+        ThreadUtilities.sleep(5000);
         new TestApexEngine("JYTHON", engineParameters);
     }
 }
index 604105a..7b4d05a 100644 (file)
@@ -30,6 +30,7 @@ import org.onap.policy.apex.context.parameters.ContextParameterConstants;
 import org.onap.policy.apex.context.parameters.ContextParameters;
 import org.onap.policy.apex.context.parameters.SchemaParameters;
 import org.onap.policy.apex.core.engine.EngineParameters;
+import org.onap.policy.apex.core.infrastructure.threading.ThreadUtilities;
 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
 import org.onap.policy.apex.plugins.executor.mvel.MvelExecutorParameters;
 import org.onap.policy.common.parameters.ParameterService;
@@ -48,12 +49,12 @@ public class TestApexEngineMvel {
     @Before
     public void beforeTest() {
         schemaParameters = new SchemaParameters();
-        
+
         schemaParameters.setName(ContextParameterConstants.SCHEMA_GROUP_NAME);
         schemaParameters.getSchemaHelperParameterMap().put("JAVA", new JavaSchemaHelperParameters());
 
         ParameterService.register(schemaParameters);
-        
+
         contextParameters = new ContextParameters();
 
         contextParameters.setName(ContextParameterConstants.MAIN_GROUP_NAME);
@@ -65,7 +66,7 @@ public class TestApexEngineMvel {
         ParameterService.register(contextParameters.getDistributorParameters());
         ParameterService.register(contextParameters.getLockManagerParameters());
         ParameterService.register(contextParameters.getPersistorParameters());
-        
+
         engineParameters = new EngineParameters();
         engineParameters.getExecutorParameterMap().put("MVEL", new MvelExecutorParameters());
         ParameterService.register(engineParameters);
@@ -77,7 +78,7 @@ public class TestApexEngineMvel {
     @After
     public void afterTest() {
         ParameterService.deregister(engineParameters);
-        
+
         ParameterService.deregister(contextParameters.getDistributorParameters());
         ParameterService.deregister(contextParameters.getLockManagerParameters());
         ParameterService.deregister(contextParameters.getPersistorParameters());
@@ -96,6 +97,7 @@ public class TestApexEngineMvel {
     @Test
     public void testApexEngineMvel() throws ApexException, InterruptedException, IOException {
         new TestApexEngine("MVEL", engineParameters);
+        ThreadUtilities.sleep(5000);
         new TestApexEngine("MVEL", engineParameters);
     }
 }