diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000000000000000000000000000000000000..e7c4f49ac2055aac6978f0bd949528595cff19cd
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..40be386b981d8564ef04539edebb44dc6a389d39
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,40 @@
+include:
+ - project: osl/code/org.etsi.osl.main
+ ref: main
+ file:
+ - ci-templates/default.yml
+ - ci-templates/build.yml
+ rules:
+ - if: '$CI_COMMIT_REF_NAME == "main"'
+
+ - project: osl/code/org.etsi.osl.main
+ ref: develop
+ file:
+ - ci-templates/default.yml
+ - ci-templates/build.yml
+ rules:
+ - if: '$CI_COMMIT_REF_NAME == "develop"'
+
+ - project: osl/code/org.etsi.osl.main
+ ref: $CI_COMMIT_REF_NAME
+ file:
+ - ci-templates/default.yml
+ - ci-templates/build.yml
+ rules:
+ - if: '$CI_COMMIT_REF_PROTECTED == "true" && $CI_COMMIT_REF_NAME != "main" && $CI_COMMIT_REF_NAME != "develop"'
+
+ - project: osl/code/org.etsi.osl.main
+ ref: develop
+ file:
+ - ci-templates/default.yml
+ - ci-templates/build_unprotected.yml
+ rules:
+ - if: '$CI_COMMIT_REF_NAME != "main" && $CI_COMMIT_REF_NAME != "develop" && $CI_COMMIT_REF_PROTECTED == "false"'
+
+maven_build:
+ extends: .maven_build
+
+docker_build:
+ extends: .docker_build
+ needs:
+ - maven_build
diff --git a/.project b/.project
new file mode 100644
index 0000000000000000000000000000000000000000..ec91655dce6f23bb621faebfc80549036fb2499c
--- /dev/null
+++ b/.project
@@ -0,0 +1,23 @@
+
+
+ org.etsi.osl.mcp.server
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..29abf999564110a0d6aca109f55f439c72b7031c
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,6 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..3328195d65370652055cb326fd9d76eb1bee1841
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,16 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=17
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=17
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..f897a7f1cb2389f85fe6381425d29f0a9866fb65
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..0767d5782e2b836774b53e55734470bfa21cccc5
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,8 @@
+FROM ibm-semeru-runtimes:open-17.0.7_7-jdk
+MAINTAINER osl.etsi.org
+
+RUN mkdir /opt/osl
+
+COPY target/org.etsi.osl.mcp.server-1.0.0-exec.jar /opt/osl
+CMD ["java", "-jar", "/opt/osl/org.etsi.osl.mcp.server-1.0.0-exec.jar"]
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/ci_settings.xml b/ci_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..69ad06ed6c63795d191555afde6ea2d1da4e133d
--- /dev/null
+++ b/ci_settings.xml
@@ -0,0 +1,16 @@
+
+
+
+ gitlab-maven
+
+
+
+ Job-Token
+ ${CI_JOB_TOKEN}
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a5a1572a083f677f8df4ff5b265c400a22d9d96b
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,333 @@
+
+ 4.0.0
+
+
+ org.etsi.osl
+ org.etsi.osl.main
+ 2025Q2
+ ../org.etsi.osl.main
+
+
+ org.etsi.osl
+ org.etsi.osl.mcp.server
+ ${org.etsi.osl.mcp.server.version}
+ org.etsi.osl.mcp.server
+
+
+ OpenSlice by ETSI
+ https://osl.etsi.org
+
+
+
+
+
+ UTF-8
+ UTF-8
+ 3.4.5
+ 1.0.0-M7
+ 1.18.28
+ 2.1.0
+ 1.5.3.Final
+ 17
+ 4.11.0
+ 2.8.11
+ 2.0.0
+ apache_v2
+ 1.7.0
+ 1.7.0
+
+
+
+
+
+ gitlab-maven
+ https://labs.etsi.org/rep/api/v4/groups/260/-/packages/maven
+
+
+
+
+ gitlab-maven
+ ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/maven
+
+
+ gitlab-maven
+ ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/maven
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot-version}
+ pom
+ import
+
+
+ org.springframework.ai
+ spring-ai-bom
+ ${spring-ai.version}
+ pom
+ import
+
+
+
+ org.apache.camel.springboot
+ camel-spring-boot-dependencies
+ ${camel.version}
+ pom
+ import
+
+
+
+ com.google.guava
+ guava
+ 32.0.0-jre
+
+
+
+
+
+
+
+
+
+ org.springframework.ai
+ spring-ai-starter-mcp-server-webflux
+
+
+
+
+
+
+
+
+
+
+ org.projectlombok
+ lombok
+ provided
+ ${lombok-version}
+
+
+ org.openapitools
+ jackson-databind-nullable
+ 0.2.6
+
+
+
+
+
+ org.etsi.osl
+ org.etsi.osl.model.tmf
+ ${org.etsi.osl.model.tmf.version}
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+
+
+
+
+
+
+
+
+
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+
+
+
+ javax.annotation
+ javax.annotation-api
+ 1.3.2
+ compile
+
+
+ jakarta.validation
+ jakarta.validation-api
+ 3.0.2
+
+
+ org.jetbrains
+ annotations
+ 13.0
+ compile
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-activemq
+
+
+ org.apache.activemq
+ activemq-amqp
+ test
+
+
+ org.apache.qpid
+ proton-j
+
+
+
+
+ org.messaginghub
+ pooled-jms
+
+
+
+
+ org.apache.camel.springboot
+ camel-spring-boot-starter
+
+
+ org.apache.activemq
+ activemq-pool
+
+
+ org.apache.camel
+ camel-activemq
+
+
+ org.apache.activemq
+ activemq-broker
+
+
+
+
+ org.apache.camel.springboot
+ camel-service-starter
+
+
+
+ org.apache.camel.springboot
+ camel-http-starter
+
+
+ org.apache.camel
+ camel-jackson
+
+
+ org.apache.camel
+ camel-stream
+
+
+
+ dk.brics.automaton
+ automaton
+ 1.11-8
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+
+ -parameters
+
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+
+
+ org.projectlombok
+ lombok
+ ${lombok-version}
+
+
+
+ org.projectlombok
+ lombok-mapstruct-binding
+ 0.2.0
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ license-maven-plugin
+ ${maven-license-plugin.version}
+
+ false
+ ========================LICENSE_START=================================
+ =========================LICENSE_END==================================
+ *.json
+
+
+
+ generate-license-headers
+
+ update-file-header
+
+ process-sources
+
+ ${license.licenseName}
+
+
+
+
+ download-licenses
+
+ download-licenses
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot-version}
+
+
+
+ repackage
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot-version}
+
+ exec
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/etsi/osl/mcp/server/ActiveMQComponentConfig.java b/src/main/java/org/etsi/osl/mcp/server/ActiveMQComponentConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3bef57e2a02080ee6f38ee96c4c356b87a578f5
--- /dev/null
+++ b/src/main/java/org/etsi/osl/mcp/server/ActiveMQComponentConfig.java
@@ -0,0 +1,41 @@
+/*-
+ * ========================LICENSE_START=================================
+ * org.etsi.osl.bugzilla
+ * %%
+ * Copyright (C) 2019 openslice.io
+ * %%
+ * 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.
+ * =========================LICENSE_END==================================
+ */
+package org.etsi.osl.mcp.server;
+
+import org.apache.camel.component.activemq.ActiveMQComponent;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import jakarta.jms.ConnectionFactory;
+
+/**
+ * @author ctranoris
+ *
+ */
+@Configuration
+public class ActiveMQComponentConfig {
+
+ @Bean(name = "activemq")
+ public ActiveMQComponent createComponent(ConnectionFactory factory) {
+ ActiveMQComponent activeMQComponent = new ActiveMQComponent();
+ activeMQComponent.setConnectionFactory(factory);
+ return activeMQComponent;
+ }
+}
diff --git a/src/main/java/org/etsi/osl/mcp/server/JsonMassage.java b/src/main/java/org/etsi/osl/mcp/server/JsonMassage.java
new file mode 100644
index 0000000000000000000000000000000000000000..d83e6f964a3526141e1141c12fd7e2d125e880d5
--- /dev/null
+++ b/src/main/java/org/etsi/osl/mcp/server/JsonMassage.java
@@ -0,0 +1,100 @@
+package org.etsi.osl.mcp.server;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @author ctranoris
+ */
+public class JsonMassage {
+
+ /**
+ * Filters a JSON object to include only keys that match any token in the provided array.
+ *
+ * @param json JSON string to filter
+ * @param tokens Array of tokens to match against keys
+ * @return A new JSON string containing only matched keys
+ * @throws Exception If there's an error processing the JSON
+ */
+ public static String filterJsonByTokens(String json, String[] tokens) throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode rootNode = mapper.readTree(json);
+
+ Set tokenSet = new HashSet<>(Arrays.asList(tokens));
+ JsonNode filteredNode = filterNode(rootNode, tokenSet);
+
+ return mapper.writeValueAsString(filteredNode);
+ }
+
+ public static JsonNode filterJsonByTokens(Object object, String[] tokens) throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ // Convert the Java object to JsonNode
+ JsonNode rootNode = mapper.valueToTree(object);
+
+ Set tokenSet = new HashSet<>(Arrays.asList(tokens));
+ JsonNode filteredNode = filterNode(rootNode, tokenSet);
+
+ //return mapper.writeValueAsString(filteredNode);
+ return filteredNode;
+ }
+
+ public static JsonNode filterNode(JsonNode node, Set tokens) {
+ ObjectMapper mapper = new ObjectMapper();
+
+ if (node.isObject()) {
+ ObjectNode resultNode = mapper.createObjectNode();
+ Iterator fieldNames = node.fieldNames();
+
+ while (fieldNames.hasNext()) {
+ String fieldName = fieldNames.next();
+ JsonNode fieldValue = node.get(fieldName);
+
+ // Check if the field name matches any token
+ if (tokens.contains(fieldName)) {
+ resultNode.set(fieldName, fieldValue.deepCopy());
+ }
+
+ // If it's an object or array, process it recursively and include if not empty
+ if (fieldValue.isObject() || fieldValue.isArray()) {
+ JsonNode filteredChild = filterNode(fieldValue, tokens);
+
+ // Only add non-empty objects/arrays when they contain matches
+ if ((filteredChild.isObject() && filteredChild.size() > 0) ||
+ (filteredChild.isArray() && filteredChild.size() > 0)) {
+ resultNode.set(fieldName, filteredChild);
+ }
+ }
+ }
+
+ return resultNode;
+ } else if (node.isArray()) {
+ ArrayNode resultArray = mapper.createArrayNode();
+
+ for (JsonNode element : node) {
+ JsonNode filteredElement = filterNode(element, tokens);
+
+ // Only add non-empty objects/arrays
+ if ((filteredElement.isObject() || filteredElement.isArray()) &&
+ filteredElement.size() > 0) {
+ resultArray.add(filteredElement);
+ } else if (!filteredElement.isObject() && !filteredElement.isArray()) {
+ resultArray.add(filteredElement);
+ }
+ }
+
+ return resultArray;
+ } else {
+ // For primitive values, return as is
+ return node;
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/etsi/osl/mcp/server/OSLMCPServerApplication.java b/src/main/java/org/etsi/osl/mcp/server/OSLMCPServerApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d75775f85c92a514bd2f9ee82ed1b72f8303ff6
--- /dev/null
+++ b/src/main/java/org/etsi/osl/mcp/server/OSLMCPServerApplication.java
@@ -0,0 +1,101 @@
+package org.etsi.osl.mcp.server;
+
+import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.ToolCallbackProvider;
+import org.springframework.ai.tool.function.FunctionToolCallback;
+import org.springframework.ai.tool.method.MethodToolCallbackProvider;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import io.modelcontextprotocol.server.McpServerFeatures;
+import io.modelcontextprotocol.spec.McpSchema;
+import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
+import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
+import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
+import io.modelcontextprotocol.spec.McpSchema.Role;
+import io.modelcontextprotocol.spec.McpSchema.TextContent;
+
+/**
+ * @author ctranoris
+ *
+ */
+@SpringBootApplication
+public class OSLMCPServerApplication {
+
+ private static final Logger logger = LoggerFactory.getLogger(OSLMCPServerApplication.class);
+
+
+ public static void main(String[] args) {
+ SpringApplication.run(OSLMCPServerApplication.class, args);
+ }
+
+ @Bean
+ public ToolCallbackProvider serviceTools( ServiceCatalogTools oslServices) {
+ return MethodToolCallbackProvider.builder().toolObjects( oslServices ).build();
+ }
+
+
+
+ @Bean
+ public ToolCallbackProvider productTools( ProductCatalogTools oslProducts) {
+ return MethodToolCallbackProvider.builder().toolObjects( oslProducts ).build();
+ }
+
+
+
+ public record TextInput(String input) {
+ }
+
+// @Bean
+// public ToolCallback toUpperCase() {
+// return FunctionToolCallback.builder("toUpperCase", (TextInput input) -> input.input().toUpperCase())
+// .inputType(TextInput.class)
+// .description("Put the text to upper case")
+// .build();
+// }
+
+ @Bean
+ public List myResources() {
+ logger.info("calling myResources()");
+ var systemInfoResource = new McpSchema.Resource("custom://resource", "name", "description", "mime-type", null);
+ var resourceSpecification = new McpServerFeatures.SyncResourceSpecification(systemInfoResource, (exchange, request) -> {
+ try {
+ var systemInfo = Map.of( );
+ String jsonContent = new ObjectMapper().writeValueAsString(systemInfo);
+ return new McpSchema.ReadResourceResult(
+ List.of(new McpSchema.TextResourceContents(request.uri(), "application/json", jsonContent)));
+ }
+ catch (Exception e) {
+ throw new RuntimeException("Failed to generate system info", e);
+ }
+ });
+
+ return List.of(resourceSpecification);
+
+ }
+
+ @Bean
+ public List myPrompts() {
+ var prompt = new McpSchema.Prompt("greeting", "A friendly greeting prompt",
+ List.of(new McpSchema.PromptArgument("name", "The name to greet", true)));
+
+ var promptSpecification = new McpServerFeatures.SyncPromptSpecification(prompt, (exchange, getPromptRequest) -> {
+ String nameArgument = (String) getPromptRequest.arguments().get("name");
+ if (nameArgument == null) { nameArgument = "friend"; }
+ var userMessage = new PromptMessage(Role.USER, new TextContent("Hello " + nameArgument + "! How can I assist you today?"));
+ return new GetPromptResult("A personalized greeting message", List.of(userMessage));
+ });
+
+ return List.of(promptSpecification);
+ }
+
+
+
+
+}
diff --git a/src/main/java/org/etsi/osl/mcp/server/ProductCatalogQClient.java b/src/main/java/org/etsi/osl/mcp/server/ProductCatalogQClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..56a16bc0657a9721d02eba4bc6528deca88ddba1
--- /dev/null
+++ b/src/main/java/org/etsi/osl/mcp/server/ProductCatalogQClient.java
@@ -0,0 +1,379 @@
+package org.etsi.osl.mcp.server;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.etsi.osl.tmf.common.model.service.ServiceSpecificationRef;
+import org.etsi.osl.tmf.pcm620.model.Catalog;
+import org.etsi.osl.tmf.pcm620.model.Category;
+import org.etsi.osl.tmf.pcm620.model.ProductOffering;
+import org.etsi.osl.tmf.pcm620.model.ProductSpecification;
+import org.etsi.osl.tmf.pcm620.model.ProductSpecificationRef;
+import org.etsi.osl.tmf.pim637.model.Product;
+import org.etsi.osl.tmf.pim637.model.ProductUpdate;
+import org.etsi.osl.tmf.po622.model.ProductOrder;
+import org.etsi.osl.tmf.po622.model.ProductOrderCreate;
+import org.etsi.osl.tmf.ri639.model.LogicalResource;
+import org.etsi.osl.tmf.ri639.model.Resource;
+import org.etsi.osl.tmf.scm633.model.ServiceCatalog;
+import org.etsi.osl.tmf.scm633.model.ServiceCategory;
+import org.etsi.osl.tmf.scm633.model.ServiceSpecification;
+import org.etsi.osl.tmf.sim638.model.ServiceUpdate;
+import org.etsi.osl.tmf.so641.model.ServiceOrder;
+import org.etsi.osl.tmf.so641.model.ServiceOrderCreate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * @author ctranoris
+ * Class to exchange information with TMF API services
+ *
+ */
+@Service
+public class ProductCatalogQClient extends RouteBuilder {
+
+
+ private static final Logger logger = LoggerFactory.getLogger(ProductCatalogQClient.class);
+
+ @Autowired
+ private ProducerTemplate template;
+
+
+
+ @Value("${CATALOG_ADD_PRODUCTORDER}")
+ private String CATALOG_ADD_PRODUCTORDER = "";
+
+
+ @Value("${CATALOG_GET_PRODUCTSPEC_BY_ID}")
+ private String CATALOG_GET_PRODUCTSPEC_BY_ID = "";
+
+
+ @Value("${CATALOG_GET_PRODUCTORDER_BY_ID}")
+ private String CATALOG_GET_PRODUCTORDER_BY_ID = "";
+
+ @Value("${CATALOG_GET_PRODUCTCATALOGS}")
+ private String CATALOG_GET_PRODUCTCATALOGS = "";
+
+ @Value("${CATALOG_GET_PRODUCTCATALOG_BY_NAME}")
+ private String CATALOG_GET_PRODUCTCATALOG_BY_NAME = "";
+
+ @Value("${CATALOG_GET_PRODUCTCATEGORIES}")
+ private String CATALOG_GET_PRODUCTCATEGORIES = "";
+
+ @Value("${CATALOG_GET_PRODUCTCATEGORY_BY_ID}")
+ private String CATALOG_GET_PRODUCTCATEGORY_BY_ID = "";
+
+
+ @Value("${CATALOG_GET_PRODUCTOFFERING_BY_ID}")
+ private String CATALOG_GET_PRODUCTOFFERING_BY_ID = "";
+
+ @Value("${CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID}")
+ private String CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID = "";
+
+ @Value("${CATALOG_SEARCH_PRODUCTOFFERINGS}")
+ private String CATALOG_SEARCH_PRODUCTOFFERINGS = "";
+
+
+ @Override
+ public void configure() throws Exception {
+
+
+
+ }
+
+ /**
+ * get product spec by id from model via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public ProductSpecification retrieveProductSpec(String specid) {
+ logger.info("will retrieve Product Specification from catalog orderid=" + specid );
+
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_PRODUCTSPEC_BY_ID, specid);
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Specification object is wrong.");
+ return null;
+ }
+ ProductSpecification sor = toJsonObj( (String)response, ProductSpecification.class);
+ //logger.debug("retrieveSpec response is: " + response);
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Product Specification details from catalog. " + e.toString());
+ }
+ return null;
+ }
+
+
+ public ProductOffering retrieveProductOffering(String productOfferingId) {
+ logger.info("will retrieve Product Specification from catalog orderid=" + productOfferingId );
+
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_PRODUCTOFFERING_BY_ID, productOfferingId);
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Specification object is wrong.");
+ return null;
+ }
+ ProductOffering sor = toJsonObj( (String)response, ProductOffering.class);
+ //logger.debug("retrieveSpec response is: " + response);
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Product Specification details from catalog. " + e.toString());
+ }
+ return null;
+ }
+
+
+
+ public ProductOrder createProductOrder(ProductOrderCreate productOrderCreate) {
+ logger.info("will create Product Order ");
+ try {
+
+
+ try {
+ Object response =
+ template.requestBody(CATALOG_ADD_PRODUCTORDER, toJsonString(productOrderCreate));
+
+ if (!(response instanceof String)) {
+ logger.error("Product Order object is wrong.");
+ return null;
+ }
+ logger.debug("createProductOrder response is: " + response);
+ ProductOrder sor = toJsonObj((String) response, ProductOrder.class);
+
+ return sor;
+
+ } catch (Exception e) {
+ logger.error("Cannot createProductOrder details to catalog. " + e.toString());
+ }
+ return null;
+
+
+
+ } catch (Exception e) {
+ logger.error("Cannot createProductOrder to catalog. " + e.toString());
+ }
+ return null;
+
+ }
+
+ /**
+ * get product order by id from model via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public ProductOrder retrieveProductOrder( String orderid) {
+ logger.info("will retrieve Product Order from catalog orderid=" + orderid );
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_PRODUCTORDER_BY_ID, orderid);
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Order object is wrong.");
+ return null;
+ }
+ logger.debug("retrieveProductOrder response is: " + response);
+ ProductOrder sor = toJsonObj( (String)response, ProductOrder.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Product Order details from catalog. " + e.toString());
+ }
+ return null;
+ }
+
+
+
+
+
+
+ /**
+ * get product Catalogs via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public List retrieveProductCatalogs() {
+ logger.info("will retrieve Product Catalogs " );
+
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_PRODUCTCATALOGS, "" );
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Catalogs object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+ //logger.debug("retrieveSpec response is: " + response);
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve ProductCatalogs. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * get product Catalog via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public Catalog retrieveProductCatalog(String catalogName) {
+ logger.info("will retrieve Product Catalog details " + catalogName );
+
+ try {
+
+ Map map = new HashMap<>();
+ map.put("catalogName", catalogName );
+
+ Object response = template.requestBodyAndHeaders( CATALOG_GET_PRODUCTCATALOG_BY_NAME, "", map);
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Catalog object is wrong.");
+ return null;
+ }
+ Catalog sor = toJsonObj( (String)response, Catalog.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve ProductCatalog. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * get product Categories via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public List retrieveProductCategoriesDetailsOfCatalog(String catalogName) {
+ logger.info("will retrieve Product Categories Details Of " + catalogName );
+
+ try {
+
+ Map map = new HashMap<>();
+ map.put("catalogName", catalogName );
+
+ Object response = template.requestBodyAndHeaders( CATALOG_GET_PRODUCTCATEGORIES, "", map);
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Catalog object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Product Categories. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * get product Categories via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public List retrieveProductOfferingsByCategoryId(String categoryId) {
+ logger.info("will retrieve Product Offering Details Of category " + categoryId );
+
+ try {
+
+ Map map = new HashMap<>();
+ map.put("categoryId", categoryId );
+
+ Object response = template.requestBodyAndHeaders( CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID, "", map);
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Specs object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Product Specs. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ public List searchProductOfferings(List searchText) {
+ logger.info("will search Product Offerings " + searchText );
+
+ try {
+
+ //Map map = new HashMap<>();
+ //map.put("searchText", searchText );
+ String body = toJsonString(searchText);
+ Object response = template.requestBody( CATALOG_SEARCH_PRODUCTOFFERINGS, body );
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Product Specs object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Product Specs. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ static String toJsonString(Object object) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ return mapper.writeValueAsString(object);
+ }
+
+ static T toJsonObj(String content, Class valueType) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ return mapper.readValue(content, valueType);
+ }
+
+
+
+
+}
diff --git a/src/main/java/org/etsi/osl/mcp/server/ProductCatalogTools.java b/src/main/java/org/etsi/osl/mcp/server/ProductCatalogTools.java
new file mode 100644
index 0000000000000000000000000000000000000000..f47f1597ade0ed3ec23628835a282b5ea9d57a54
--- /dev/null
+++ b/src/main/java/org/etsi/osl/mcp/server/ProductCatalogTools.java
@@ -0,0 +1,297 @@
+package org.etsi.osl.mcp.server;
+
+import java.io.IOException;
+import java.time.OffsetDateTime;
+import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.etsi.osl.tmf.common.model.Any;
+import org.etsi.osl.tmf.common.model.service.Characteristic;
+import org.etsi.osl.tmf.common.model.service.Note;
+import org.etsi.osl.tmf.pcm620.model.Catalog;
+import org.etsi.osl.tmf.pcm620.model.Category;
+import org.etsi.osl.tmf.pcm620.model.ProductOffering;
+import org.etsi.osl.tmf.pcm620.model.ProductOfferingRef;
+import org.etsi.osl.tmf.pcm620.model.ProductSpecification;
+import org.etsi.osl.tmf.pcm620.model.ProductSpecificationRef;
+import org.etsi.osl.tmf.pim637.model.Product;
+import org.etsi.osl.tmf.pim637.model.ProductUpdate;
+import org.etsi.osl.tmf.po622.model.OrderItemActionType;
+import org.etsi.osl.tmf.po622.model.ProductOrder;
+import org.etsi.osl.tmf.po622.model.ProductOrderCreate;
+import org.etsi.osl.tmf.po622.model.ProductOrderItem;
+import org.etsi.osl.tmf.po622.model.ProductOrderStateType;
+import org.etsi.osl.tmf.prm669.model.RelatedParty;
+import org.etsi.osl.tmf.ri639.model.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ *
+ * @author ctranoris
+ */
+@org.springframework.stereotype.Service
+public class ProductCatalogTools {
+
+
+ private static final Logger logger = LoggerFactory.getLogger(ProductCatalogTools.class);
+
+
+ //private final RestClient restClient;
+
+ @Autowired
+ ProductCatalogQClient aCatalogClient;
+
+
+ @Tool(description = "Get a list of all published OSL OpenSlice product catalogs."
+ + "Each catalog contains product categories, that we can search individually to get the details and contents of each category.")
+ public JsonNode getOSLProductCatalogs() {
+
+ logger.info("getOSLProductCatalogs");
+ List serviceCatalogs = aCatalogClient.retrieveProductCatalogs();
+
+
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "@type"};
+ JsonNode filtered = JsonMassage.filterJsonByTokens( serviceCatalogs, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( serviceCatalogs );
+ return rootNode;
+ }
+
+ @Tool(description = "Get OSL product categories in product catalog providing a catalog name")
+ public JsonNode getOSLProductCategories(String catalogName) {
+
+ logger.info("getOSLProductCategories {}", catalogName);
+
+ List productCategories = aCatalogClient.retrieveProductCategoriesDetailsOfCatalog(catalogName);
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "@type"};
+ JsonNode filtered = JsonMassage.filterJsonByTokens( productCategories, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( productCategories );
+ return rootNode;
+ }
+
+
+ @Tool(description = "Get a list of OSL product offerings in a product category, given a category ID")
+ public JsonNode getOSLProductOfferingsInCategory(String categoryId) {
+
+ logger.info("getOSLProductOfferingsInCategory {}", categoryId);
+ List productCategories = aCatalogClient.retrieveProductOfferingsByCategoryId(categoryId);
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description"};
+ JsonNode filtered = JsonMassage.filterJsonByTokens( productCategories, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( productCategories );
+ return rootNode;
+
+
+ }
+
+ @Tool(description = "Get all the details of an OSL product offering give a product offering Id")
+ public JsonNode getOSLProductOfferingByProductOfferingId(String productOfferingId) {
+
+ logger.info("getOSLProductOfferingByProductOfferingId {}", productOfferingId);
+
+ ProductOffering spec = aCatalogClient.retrieveProductOffering(productOfferingId);
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "isBundle", "@type", "configurable", "valueType", "isBundle" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( spec, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( spec );
+ return rootNode;
+
+ }
+
+ @Tool(description = "Get all the details of an OSL product specification give a product Specification Id")
+ public JsonNode getOSLProductByProductSpecificationId(String productSpecId) {
+
+ logger.info("getOSLProductByProductSpecificationId {}", productSpecId);
+
+ ProductSpecification spec = aCatalogClient.retrieveProductSpec(productSpecId);
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "isBundle", "@type", "configurable", "valueType", "isBundle",
+ "productNumber", "brand", "isBundle", "isBundle", "isBundle", "isBundle" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( spec, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( spec );
+ return rootNode;
+ }
+
+
+ @Tool(description = "Search for OSL product Offerings that are published and available for product ordering in all categories")
+ public JsonNode searchOSLProductOfferings( List searchStrings) {
+
+ logger.info("searchOSLProductOfferings containing workds: {}", searchStrings);
+
+ List spec = aCatalogClient.searchProductOfferings( searchStrings );
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "isBundle", "@type", "configurable", "valueType", "isBundle" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( spec, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( spec );
+ return rootNode;
+ }
+
+ @Tool(description = "Create a product order given a Product Offering id, the Start date an end date of the order. "
+ + "The user can provide also characteristics of product in the map with format key, value"
+ + "Date Time has the format YYYY-MM-DDTHH:mm:ss+00:00")
+ public String createProductOrder(String productOfferingId, String startDate, String endDate, Map characteristics) {
+
+ logger.info("createProductOrder {} {} {} {}", productOfferingId, startDate, endDate, characteristics.toString());
+
+ ProductOrderCreate ponew = new ProductOrderCreate();
+
+ OffsetDateTime sDate;
+ OffsetDateTime eDate;
+ if (startDate == null) {
+ sDate = OffsetDateTime.now();
+ } else {
+ sDate = OffsetDateTime.parse(startDate);
+ }
+ ponew.setRequestedStartDate( sDate );
+
+
+ if (endDate == null) {
+ eDate = OffsetDateTime.now().plusDays(1);
+ } else {
+ eDate = OffsetDateTime.parse(endDate);
+ }
+ ponew.setRequestedCompletionDate( eDate );
+
+ ponew.setCategory("Automated order from MCP");
+ ponew.setDescription("Automatically from MCP ");
+
+ if (ponew.getRelatedParty() == null) {
+ RelatedParty rp = new RelatedParty();
+ rp.setName("MCP");
+ rp.setRole("REQUESTER");
+ ponew.addRelatedPartyItem(rp);
+ }
+
+ if (ponew.getNote() == null) {
+ Note n = new Note();
+
+ n.setText( "Order created by MCP");
+
+ ponew.addNoteItem(n);
+ }
+
+
+ ProductOfferingRef prodOffRef = new ProductOfferingRef();
+ prodOffRef.setId( productOfferingId );
+
+ ProductOrderItem poi = new ProductOrderItem();
+ poi.action(OrderItemActionType.ADD).productOffering(prodOffRef);
+
+
+ ponew.getProductOrderItem().add(poi);
+
+
+ if (characteristics!=null) {
+ for (String charKey : characteristics.keySet()) {
+ Characteristic servChar = new Characteristic();
+ servChar.setUuid(null);
+ servChar.setName(charKey);
+ servChar.setValue( new Any( characteristics.get(charKey) ));
+
+ }
+ }
+
+
+
+ ProductOrder so = aCatalogClient.createProductOrder(ponew);
+
+
+ return "Product Order created with id :" + so.getId() ;
+
+ }
+
+
+ @Tool(description = "Provide details for a product order given a Product Order id. "
+ + "Focus attention to:"
+ + "- the state of the product order"
+ + "- and each order item. Especially for each order item focus to the product and especially: status, characteristics and supporting products."
+ + "- For each supporting product we can retrieve more information by using the product id.")
+ public JsonNode getProductOrder(String productOrderId) {
+
+ logger.info("productOrderId {} {} {} {}", productOrderId);
+ ProductOrder so = aCatalogClient.retrieveProductOrder(productOrderId);
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "orderDate", "completionDate",
+ "expectedCompletionDate", "requestedCompletionDate" , "requestedStartDate" , "startDate" , "category" , "state" , "action" , "value" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( so, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( so );
+ return rootNode;
+ }
+
+
+
+
+}
diff --git a/src/main/java/org/etsi/osl/mcp/server/ServiceCatalogQClient.java b/src/main/java/org/etsi/osl/mcp/server/ServiceCatalogQClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9756afa7689eb68870245bd9929f8d63663ad80
--- /dev/null
+++ b/src/main/java/org/etsi/osl/mcp/server/ServiceCatalogQClient.java
@@ -0,0 +1,461 @@
+package org.etsi.osl.mcp.server;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.etsi.osl.tmf.common.model.service.ServiceSpecificationRef;
+import org.etsi.osl.tmf.rcm634.model.LogicalResourceSpecification;
+import org.etsi.osl.tmf.ri639.model.LogicalResource;
+import org.etsi.osl.tmf.ri639.model.Resource;
+import org.etsi.osl.tmf.scm633.model.ServiceCatalog;
+import org.etsi.osl.tmf.scm633.model.ServiceCategory;
+import org.etsi.osl.tmf.scm633.model.ServiceSpecification;
+import org.etsi.osl.tmf.sim638.model.ServiceUpdate;
+import org.etsi.osl.tmf.so641.model.ServiceOrder;
+import org.etsi.osl.tmf.so641.model.ServiceOrderCreate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * @author ctranoris
+ * Class to exchange information with TMF API services
+ *
+ */
+@Service
+public class ServiceCatalogQClient extends RouteBuilder {
+
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceCatalogQClient.class);
+
+ @Autowired
+ private ProducerTemplate template;
+
+
+
+ @Value("${CATALOG_ADD_SERVICEORDER}")
+ private String CATALOG_ADD_SERVICEORDER = "";
+
+
+ @Value("${CATALOG_GET_SERVICESPEC_BY_ID}")
+ private String CATALOG_GET_SERVICESPEC_BY_ID = "";
+
+ @Value("${CATALOG_GET_RESOURCESPEC_BY_ID}")
+ private String CATALOG_GET_RESOURCESPEC_BY_ID = "";
+
+
+
+ @Value("${CATALOG_GET_SERVICEORDER_BY_ID}")
+ private String CATALOG_GET_SERVICEORDER_BY_ID = "";
+
+
+ @Value("${CATALOG_UPD_SERVICE}")
+ private String CATALOG_UPD_SERVICE = "";
+
+
+ @Value("${CATALOG_GET_SERVICE_BY_ID}")
+ private String CATALOG_GET_SERVICE_BY_ID = "";
+
+
+ @Value("${CATALOG_GET_RESOURCE_BY_ID}")
+ private String CATALOG_GET_RESOURCE_BY_ID = "";
+
+
+ @Value("${CATALOG_GET_SERVICECATALOGS}")
+ private String CATALOG_GET_SERVICECATALOGS = "";
+
+
+
+ @Value("${CATALOG_GET_SERVICECATALOG_BY_NAME}")
+ private String CATALOG_GET_SERVICECATALOG_BY_NAME = "";
+
+ @Value("${CATALOG_GET_SERVICECATEGORIES}")
+ private String CATALOG_GET_SERVICECATEGORIES = "";
+
+ @Value("${CATALOG_GET_SERVICECATEGORY_BY_ID}")
+ private String CATALOG_GET_SERVICECATEGORY_BY_ID = "";
+
+
+ @Value("${CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID}")
+ private String CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID = "";
+
+ @Value("${CATALOG_SEARCH_SERVICESPECREFS}")
+ private String CATALOG_SEARCH_SERVICESPECREFS = "";
+
+
+ @Override
+ public void configure() throws Exception {
+
+
+
+ }
+
+ /**
+ * get service spec by id from model via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public ServiceSpecification retrieveServiceSpec(String specid) {
+ logger.info("will retrieve Service Specification from catalog orderid=" + specid );
+
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_SERVICESPEC_BY_ID, specid);
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Specification object is wrong.");
+ return null;
+ }
+ ServiceSpecification sor = toJsonObj( (String)response, ServiceSpecification.class);
+ //logger.debug("retrieveSpec response is: " + response);
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Service Specification details from catalog. " + e.toString());
+ }
+ return null;
+ }
+
+
+
+ public ServiceOrder createServiceOrder(ServiceOrderCreate serviceOrderCreate) {
+ logger.info("will create Service Order ");
+ try {
+
+
+ try {
+ Object response =
+ template.requestBody(CATALOG_ADD_SERVICEORDER, toJsonString(serviceOrderCreate));
+
+ if (!(response instanceof String)) {
+ logger.error("Service Order object is wrong.");
+ return null;
+ }
+ logger.debug("createServiceOrder response is: " + response);
+ ServiceOrder sor = toJsonObj((String) response, ServiceOrder.class);
+
+ return sor;
+
+ } catch (Exception e) {
+ logger.error("Cannot createServiceOrder details to catalog. " + e.toString());
+ }
+ return null;
+
+
+
+ } catch (Exception e) {
+ logger.error("Cannot createServiceOrder to catalog. " + e.toString());
+ }
+ return null;
+
+ }
+
+ /**
+ * get service order by id from model via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public ServiceOrder retrieveServiceOrder( String orderid) {
+ logger.info("will retrieve Service Order from catalog orderid=" + orderid );
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_SERVICEORDER_BY_ID, orderid);
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Order object is wrong.");
+ return null;
+ }
+ logger.debug("retrieveServiceOrder response is: " + response);
+ ServiceOrder sor = toJsonObj( (String)response, ServiceOrder.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Service Order details from catalog. " + e.toString());
+ }
+ return null;
+ }
+
+ /**
+ * @param serviceId
+ * @param s
+ * @param triggerServiceActionQueue is a cryptic thing. However it is used as follows: if FALSE, to just update the service status in catalog without further taking any action.
+ * if TRUE then the ServiceUpdate will trigger a ServiceActionQueue to further process the update. So this is needed to avoid these kinds of deadlocks
+ * @return
+ */
+ public org.etsi.osl.tmf.sim638.model.Service updateService(String serviceId, ServiceUpdate s, boolean triggerServiceActionQueue) {
+ logger.info("will update Service : " + serviceId );
+ try {
+ Map map = new HashMap<>();
+ map.put("serviceid", serviceId );
+ map.put("triggerServiceActionQueue", triggerServiceActionQueue );
+
+ Object response = template.requestBodyAndHeaders( CATALOG_UPD_SERVICE, toJsonString(s), map);
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Instance object is wrong.");
+ }
+
+ org.etsi.osl.tmf.sim638.model.Service serviceInstance = toJsonObj( (String)response, org.etsi.osl.tmf.sim638.model.Service.class);
+ //logger.debug("createService response is: " + response);
+ return serviceInstance;
+
+
+ }catch (Exception e) {
+ logger.error("Cannot update Service: " + serviceId + ": " + e.toString());
+ }
+ return null;
+
+ }
+
+ /**
+ * Ger service instance via bus
+ * @param serviceID
+ * @return
+ */
+ public org.etsi.osl.tmf.sim638.model.Service retrieveService(String serviceID) {
+ logger.info("will retrieve Service instance from catalog serviceID=" + serviceID );
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_SERVICE_BY_ID, serviceID);
+
+ if ( !(response instanceof String)) {
+ logger.error("Service object is wrong.");
+ return null;
+ }
+ org.etsi.osl.tmf.sim638.model.Service serviceInstance = toJsonObj( (String)response, org.etsi.osl.tmf.sim638.model.Service.class);
+ //logger.debug("retrieveService response is: " + response);
+ return serviceInstance;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Service details from catalog. " + e.toString());
+ }
+ return null;
+ }
+
+ public Resource retrieveResource(@NotNull String resourceID) {
+ logger.info("will retrieve Resource instance from catalog resourceID=" + resourceID );
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_RESOURCE_BY_ID, resourceID);
+
+ if ( !(response instanceof String)) {
+ logger.error("resource object is wrong.");
+ return null;
+ }
+ LogicalResource rInstance = toJsonObj( (String)response, LogicalResource.class);
+
+ return rInstance;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve LogicalResource details from catalog. " + e.toString());
+ }
+ return null;
+
+ }
+
+
+ public LogicalResourceSpecification retrieveResourceSpec(@NotNull String resourceSpecID) {
+ logger.info("will retrieve Resource Specification from catalog resourceSpecID=" + resourceSpecID );
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_RESOURCESPEC_BY_ID, resourceSpecID);
+
+ if ( !(response instanceof String)) {
+ logger.error("resource object is wrong.");
+ return null;
+ }
+ LogicalResourceSpecification rInstance = toJsonObj( (String)response, LogicalResourceSpecification.class);
+
+ return rInstance;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve LogicalResource details from catalog. " + e.toString());
+ }
+ return null;
+
+ }
+
+
+
+ /**
+ * get service Catalogs via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public List retrieveServiceCatalogs() {
+ logger.info("will retrieve Service Catalogs " );
+
+ try {
+ Object response = template.
+ requestBody( CATALOG_GET_SERVICECATALOGS, "" );
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Catalogs object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+ //logger.debug("retrieveSpec response is: " + response);
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve ServiceCatalogs. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * get service Catalog via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public ServiceCatalog retrieveServiceCatalog(String catalogName) {
+ logger.info("will retrieve Service Catalog details " + catalogName );
+
+ try {
+
+ Map map = new HashMap<>();
+ map.put("catalogName", catalogName );
+
+ Object response = template.requestBodyAndHeaders( CATALOG_GET_SERVICECATALOG_BY_NAME, "", map);
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Catalog object is wrong.");
+ return null;
+ }
+ ServiceCatalog sor = toJsonObj( (String)response, ServiceCatalog.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve ServiceCatalog. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * get service Categories via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public List retrieveServiceCategoriesDetailsOfCatalog(String catalogName) {
+ logger.info("will retrieve Service Categories Details Of " + catalogName );
+
+ try {
+
+ Map map = new HashMap<>();
+ map.put("catalogName", catalogName );
+
+ Object response = template.requestBodyAndHeaders( CATALOG_GET_SERVICECATEGORIES, "", map);
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Catalog object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Service Categories. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * get service Categories via bus
+ * @param id
+ * @return
+ * @throws IOException
+ */
+ public List retrieveServiceSpecsByCategoryId(String categoryId) {
+ logger.info("will retrieve Service Specs Details Of category " + categoryId );
+
+ try {
+
+ Map map = new HashMap<>();
+ map.put("categoryId", categoryId );
+
+ Object response = template.requestBodyAndHeaders( CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID, "", map);
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Specs object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Service Specs. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ public List searchServiceSpecs(List searchText) {
+ logger.info("will search Service Specs " + searchText );
+
+ try {
+
+ //Map map = new HashMap<>();
+ //map.put("searchText", searchText );
+ String body = toJsonString(searchText);
+ Object response = template.requestBody( CATALOG_SEARCH_SERVICESPECREFS, body );
+
+
+ if ( !(response instanceof String)) {
+ logger.error("Service Specs object is wrong.");
+ return null;
+ }
+ List sor = toJsonObj( (String)response, ArrayList.class);
+
+ return sor;
+
+ }catch (Exception e) {
+ logger.error("Cannot retrieve Service Specs. " + e.toString());
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ static String toJsonString(Object object) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ return mapper.writeValueAsString(object);
+ }
+
+ static T toJsonObj(String content, Class valueType) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ return mapper.readValue(content, valueType);
+ }
+
+
+
+}
diff --git a/src/main/java/org/etsi/osl/mcp/server/ServiceCatalogTools.java b/src/main/java/org/etsi/osl/mcp/server/ServiceCatalogTools.java
new file mode 100644
index 0000000000000000000000000000000000000000..365fb6b54b7263769d48ab95ca93c06c99dde720
--- /dev/null
+++ b/src/main/java/org/etsi/osl/mcp/server/ServiceCatalogTools.java
@@ -0,0 +1,391 @@
+package org.etsi.osl.mcp.server;
+
+import java.io.IOException;
+import java.time.OffsetDateTime;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.etsi.osl.tmf.common.model.Any;
+import org.etsi.osl.tmf.common.model.service.Characteristic;
+import org.etsi.osl.tmf.common.model.service.Note;
+import org.etsi.osl.tmf.common.model.service.ServiceSpecificationRef;
+import org.etsi.osl.tmf.prm669.model.RelatedParty;
+import org.etsi.osl.tmf.rcm634.model.LogicalResourceSpecification;
+import org.etsi.osl.tmf.ri639.model.Resource;
+import org.etsi.osl.tmf.scm633.model.ServiceCandidate;
+import org.etsi.osl.tmf.scm633.model.ServiceCatalog;
+import org.etsi.osl.tmf.scm633.model.ServiceCategory;
+import org.etsi.osl.tmf.scm633.model.ServiceCategoryRef;
+import org.etsi.osl.tmf.scm633.model.ServiceSpecification;
+import org.etsi.osl.tmf.sim638.model.Service;
+import org.etsi.osl.tmf.sim638.model.ServiceUpdate;
+import org.etsi.osl.tmf.so641.model.ServiceOrder;
+import org.etsi.osl.tmf.so641.model.ServiceOrderCreate;
+import org.etsi.osl.tmf.so641.model.ServiceOrderItem;
+import org.etsi.osl.tmf.so641.model.ServiceOrderStateType;
+import org.etsi.osl.tmf.so641.model.ServiceRestriction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.web.client.RestClient;
+import jakarta.validation.Valid;
+
+/**
+ *
+ * @author ctranoris
+ */
+@org.springframework.stereotype.Service
+public class ServiceCatalogTools {
+
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceCatalogTools.class);
+
+
+ //private final RestClient restClient;
+
+ @Autowired
+ ServiceCatalogQClient aCatalogClient;
+
+
+ @Tool(description = "Get a list of all published OSL OpenSlice service catalogs."
+ + "Each catalog contains service categories, that we can search individually to get the details and contents of each category.")
+ public JsonNode getOSLServiceCatalogs() {
+
+ logger.info("getOSLServiceCatalogs");
+ List serviceCatalogs = aCatalogClient.retrieveServiceCatalogs();
+
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "@type"};
+ JsonNode filtered = JsonMassage.filterJsonByTokens( serviceCatalogs, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( serviceCatalogs );
+ return rootNode;
+
+ }
+
+ @Tool(description = "Get OSL categories in catalog providing a catalog name")
+ public JsonNode getOSLServiceCategories(String catalogName) {
+
+ logger.info("getOSLServiceCategories {}", catalogName);
+
+ List serviceCategories = aCatalogClient.retrieveServiceCategoriesDetailsOfCatalog(catalogName);
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "@type"};
+ JsonNode filtered = JsonMassage.filterJsonByTokens( serviceCategories, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( serviceCategories );
+ return rootNode;
+ }
+
+
+ @Tool(description = "Get a list of OSL service specification references in a service category, given a category ID")
+ public JsonNode getOSLServiceSpecsInCategory(String categoryId) {
+
+ logger.info("getOSLServiceSpecsInCategory {}", categoryId);
+
+
+ List serviceCategories = aCatalogClient.retrieveServiceSpecsByCategoryId(categoryId);
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description"};
+ JsonNode filtered = JsonMassage.filterJsonByTokens( serviceCategories, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( serviceCategories );
+ return rootNode;
+
+
+
+
+ }
+
+ @Tool(description = "Get all the details of an OSL service specification given a service Specification Id")
+ public JsonNode getOSLServiceSpecificationByServiceSpecificationId(String serviceSpecId) {
+
+ logger.info("getOSLServiceByServiceSpecificationId {}", serviceSpecId);
+
+ ServiceSpecification spec = aCatalogClient.retrieveServiceSpec(serviceSpecId);
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "isBundle", "@type", "configurable", "valueType", "isBundle" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( spec, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( spec );
+ return rootNode;
+ }
+
+
+
+ @Tool(description = "Get all the details of an OSL resource specification given a resource Specification Id")
+ public JsonNode getOSLResourceSpecificationByResourceSpecificationId(String resourceSpecId) {
+
+ logger.info("getOSLResourceSpecificationByResourceSpecificationId {}", resourceSpecId);
+
+ LogicalResourceSpecification spec = aCatalogClient.retrieveResourceSpec(resourceSpecId);
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "@type", "configurable", "valueType", "isBundle" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( spec, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( spec );
+ return rootNode;
+ }
+
+
+
+ @Tool(description = "Search for OSL service specifications that are published and available for service ordering in all categories")
+ public JsonNode searchOSLServiceSpecifications( List searchStrings) {
+
+ logger.info("searchOSLServiceSpecifications containing words: {}", searchStrings);
+
+ List spec = aCatalogClient.searchServiceSpecs( searchStrings );
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "@type", "configurable", "valueType", "isBundle" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( spec, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( spec );
+ return rootNode;
+ }
+
+ @Tool(description = "Create a service order given a Service Specification id, the Start date an end date of the order. "
+ + "The user can provide also characteristics of service in the map with format key, value"
+ + "Date Time has the format YYYY-MM-DDTHH:mm:ss+00:00")
+ public String createServiceOrder(String serviceSpecId, String startDate, String endDate, Map characteristics) {
+
+ logger.info("createServiceOrder {} {} {} {}", serviceSpecId, startDate, endDate, characteristics.toString());
+
+ ServiceOrderCreate sonew = new ServiceOrderCreate();
+
+ OffsetDateTime sDate;
+ OffsetDateTime eDate;
+ if (startDate == null) {
+ sDate = OffsetDateTime.now();
+ } else {
+ sDate = OffsetDateTime.parse(startDate);
+ }
+ sonew.setRequestedStartDate( sDate );
+
+
+ if (endDate == null) {
+ eDate = OffsetDateTime.now().plusDays(1);
+ } else {
+ eDate = OffsetDateTime.parse(endDate);
+ }
+ sonew.setRequestedCompletionDate( eDate );
+
+ sonew.setCategory("Automated order from MCP");
+ sonew.setDescription("Automatically from MCP ");
+
+ if (sonew.getRelatedParty() == null) {
+ RelatedParty rp = new RelatedParty();
+ rp.setName("MCP");
+ rp.setRole("REQUESTER");
+ sonew.addRelatedPartyItem(rp);
+ }
+
+ if (sonew.getNote() == null) {
+ Note n = new Note();
+
+ n.setText( "Order created by MCP");
+
+ sonew.addNoteItem(n);
+ }
+
+
+ ServiceOrderItem soi = new ServiceOrderItem();
+ sonew.getOrderItem().add(soi);
+ soi.setState(ServiceOrderStateType.ACKNOWLEDGED);
+
+
+ ServiceSpecification serviceSpec = aCatalogClient.retrieveServiceSpec(serviceSpecId);
+
+ ServiceRestriction serviceRestriction = new ServiceRestriction();
+ ServiceSpecificationRef aServiceSpecificationRef = new ServiceSpecificationRef();
+ aServiceSpecificationRef.setId( serviceSpecId );
+ aServiceSpecificationRef.setName( serviceSpec.getName());
+ aServiceSpecificationRef.setVersion( serviceSpec.getVersion());
+
+ serviceRestriction.setServiceSpecification(aServiceSpecificationRef);
+
+
+ if (characteristics!=null) {
+ for (String charKey : characteristics.keySet()) {
+ Characteristic servChar = new Characteristic();
+ servChar.setUuid(null);
+ servChar.setName(charKey);
+ servChar.setValue( new Any( characteristics.get(charKey) ));
+ serviceRestriction.addServiceCharacteristicItem(servChar);
+ }
+ }
+
+ soi.setService(serviceRestriction);
+
+
+ ServiceOrder so = aCatalogClient.createServiceOrder(sonew);
+
+
+ return "Service Order created with id :" + so.getId() ;
+
+ }
+
+
+ @Tool(description = "Provide details for a service order given a Service Order id. "
+ + "Focus attention to:"
+ + "- the state of the service order"
+ + "- and each order item. Especially for each order item focus to the service and especially: status, characteristics and supporting services."
+ + "- For each supporting service we can retrieve more information by using the service id.")
+ public JsonNode getServiceOrder(String serviceOrderId) {
+
+ logger.info("serviceOrderId {} {} {} {}", serviceOrderId);
+ ServiceOrder so = aCatalogClient.retrieveServiceOrder(serviceOrderId);
+
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "orderDate", "completionDate",
+ "expectedCompletionDate", "requestedCompletionDate" , "requestedStartDate" , "startDate" , "category" , "state" , "action" , "value" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( so, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( so );
+ return rootNode;
+
+
+ }
+
+ @Tool(description = "Provide details for a service given a Service id. Especially for name, state, characteristics, supporting Services and supporting Resources."
+ + "We can get details for each supporting service using the service id."
+ + "and for each supporting resource using the resource id.")
+ public JsonNode getService(String serviceId) {
+ logger.info("getService {} {} {} {}", serviceId);
+ Service s = aCatalogClient.retrieveService(serviceId);
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description",
+ "category" , "serviceDate" , "serviceType" , "state" , "value" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( s, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( s );
+ return rootNode;
+
+ }
+
+ @Tool(description = "Provide details for a resource given a Resourceid. Especially for name, status, characteristics."
+ + "We can get details for each supporting resource using the resource id.")
+ public JsonNode getResource(String resourceId) {
+ logger.info("getResource {} {} {} {}", resourceId);
+ Resource r = aCatalogClient.retrieveResource ( resourceId);
+ // Filter and get result as JSON string
+ try {
+
+ String[] tokens = {"id", "name", "description", "startOperatingDate", "endOperatingDate",
+ "category" , "resourceStatus" , "state" , "value" , "valueType" };
+ JsonNode filtered = JsonMassage.filterJsonByTokens( r, tokens);
+ return filtered;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ //return mapper.writeValueAsString(serviceCatalogs);
+ JsonNode rootNode = mapper.valueToTree( r );
+ return rootNode;
+ }
+
+
+ @Tool(description = "Update and change a service given a Service id."
+ + "We provide also characteristics of service in the map with format key, value")
+ public String updateService(String serviceId, Map characteristics) {
+ logger.info("updateService {} {} {} {}", serviceId);
+
+ ServiceUpdate su = new ServiceUpdate();
+
+ if (characteristics!=null) {
+ for (String charKey : characteristics.keySet()) {
+ Characteristic servChar = new Characteristic();
+ servChar.setUuid(null);
+ servChar.setName(charKey);
+ servChar.setValue( new Any( characteristics.get(charKey) ));
+ su.addServiceCharacteristicItem(servChar);
+ }
+ }
+
+
+ Service r = aCatalogClient.updateService(serviceId, su, true);
+ try {
+ return ServiceCatalogQClient.toJsonString(r);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d31c35db973a5ce2f3b1ce3941492d79b4ca61be
--- /dev/null
+++ b/src/main/resources/application.yaml
@@ -0,0 +1,199 @@
+# Using spring-ai-starter-mcp-server-webmvc
+
+
+server:
+ port: 13015
+
+spring:
+ autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
+ ai:
+ mcp:
+ server:
+ name: org.etsi.osl.mcp.server
+ version: 0.0.1
+ type: SYNC
+ sse-message-endpoint: /mcp/messages
+ stdio: false
+ resource-change-notification: true
+ tool-change-notification: true
+ prompt-change-notification: true
+ activemq:
+ brokerUrl: tcp://localhost:61616?jms.watchTopicAdvisories=false
+ user: artemis
+ password: artemis
+ pool:
+ enabled: true
+ max-connections: 100
+ packages:
+ trust-all: true
+ security:
+ oauth2:
+ resourceserver:
+ jwt:
+ issuer-uri: http://keycloak:8080/auth/realms/openslice
+ jwk-set-uri: http://keycloak:8080/auth/realms/openslice/.well-known/openid-configuration
+
+
+logging:
+ level:
+ root: INFO
+ org.etsi.osl.*: DEBUG
+ org.springframework: INFO
+ org.apache.camel: INFO
+ com.zaxxer.hikari: INFO
+ pattern:
+ console: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
+ file: "%d %p %c{1.} [%t] %m%n"
+
+
+#QUEUE MESSAGES
+CATALOG_GET_SERVICESPEC_BY_ID: "jms:queue:CATALOG.GET.SERVICESPEC_BY_ID"
+CATALOG_ADD_SERVICESPEC: "jms:queue:CATALOG.ADD.SERVICESPEC"
+CATALOG_UPD_SERVICESPEC: "jms:queue:CATALOG.UPD.SERVICESPEC"
+CATALOG_UPDADD_SERVICESPEC: "jms:queue:CATALOG.UPDADD.SERVICESPEC"
+CATALOG_SERVICE_QUEUE_ITEMS_GET: "jms:queue:CATALOG.SERVICEQUEUEITEMS.GET"
+CATALOG_SERVICE_QUEUE_ITEM_UPD: "jms:queue:CATALOG.SERVICEQUEUEITEM.UPDATE"
+CATALOG_SERVICE_QUEUE_ITEM_DELETE: "jms:queue:CATALOG.SERVICEQUEUEITEM.DELETE"
+CATALOG_GET_PARTNER_ORGANIZATON_BY_ID: "jms:queue:CATALOG.GET.PARTNER_ORGANIZATION_BY_ID"
+CATALOG_UPDATE_PARTNER_ORGANIZATION: "jms:queue:CATALOG.UPD.PARTNER_ORGANIZATION"
+CATALOG_SERVICES_TO_TERMINATE: "jms:queue:CATALOG.GET.SERVICETOTERMINATE"
+CATALOG_SERVICES_OF_PARTNERS: "jms:queue:CATALOG.GET.SERVICESOFPARTNERS"
+CATALOG_GET_EXTERNAL_SERVICE_PARTNERS: "jms:queue:CATALOG.GET.EXTERNALSERVICEPARTNERS"
+CATALOG_UPD_EXTERNAL_SERVICESPEC: "jms:queue:CATALOG.UPD.EXTERNAL_SERVICESPEC"
+
+#SERVICE_INVENTORY
+CATALOG_ADD_SERVICE: "jms:queue:CATALOG.ADD.SERVICE"
+CATALOG_UPD_SERVICE: "jms:queue:CATALOG.UPD.SERVICE"
+CATALOG_GET_SERVICE_BY_ID: "jms:queue:CATALOG.GET.SERVICE"
+CATALOG_GET_SERVICE_BY_ORDERID: "jms:queue:CATALOG.GET.SERVICE_BY_ORDERID"
+
+
+#SERVICE ORDERS
+CATALOG_GET_SERVICEORDERS: "jms:queue:CATALOG.GET.SERVICEORDERS"
+CATALOG_GET_SERVICEORDER_BY_ID: "jms:queue:CATALOG.GET.SERVICEORDER_BY_ID"
+CATALOG_ADD_SERVICEORDER: "jms:queue:CATALOG.ADD.SERVICEORDER"
+CATALOG_UPD_SERVICEORDER_BY_ID: "jms:queue:CATALOG.UPD.SERVICEORDER_BY_ID"
+CATALOG_GET_INITIAL_SERVICEORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_SERVICEORDERS"
+CATALOG_GET_SERVICEORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_SERVICEORDERS"
+
+
+#SERVICE CATALOGS, CATEGORIES
+CATALOG_GET_SERVICECATALOGS: "jms:queue:CATALOG.GET.SERVICECATALOGS"
+CATALOG_GET_SERVICECATALOG_BY_ID: "jms:queue:CATALOG.GET.SERVICECATALOG_BY_ID"
+CATALOG_GET_SERVICECATALOG_BY_NAME: "jms:queue:CATALOG.GET.SERVICECATALOG_BY_NAME"
+
+CATALOG_GET_SERVICECATEGORIES: "jms:queue:CATALOG.GET.SERVICECATEGORIES"
+CATALOG_GET_SERVICECATEGORY_BY_ID: "jms:queue:CATALOG.GET.SERVICECATEGORY_BY_ID"
+
+CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID: "jms:queue:CATALOG.GETSERVICESPECREFS.SERVICECATEGORY_BY_ID"
+CATALOG_SEARCH_SERVICESPECREFS: "jms:queue:CATALOG.CATALOG_SEARCH_SERVICESPECREFS"
+
+
+#PRODUCT CATALOGS
+CATALOG_GET_PRODUCTSPEC_BY_ID: "jms:queue:CATALOG.GET.PRODUCTSPEC_BY_ID"
+CATALOG_ADD_PRODUCTSPEC: "jms:queue:CATALOG.ADD.PRODUCTSPEC"
+CATALOG_UPD_PRODUCTSPEC: "jms:queue:CATALOG.UPD.PRODUCTSPEC"
+CATALOG_UPDADD_PRODUCTSPEC: "jms:queue:CATALOG.UPDADD.PRODUCTSPEC"
+CATALOG_GET_PRODUCTOFFERING_BY_ID: "jms:queue:CATALOG.GET.PRODUCTOFFERING_BY_ID"
+CATALOG_GET_PRODUCTORDERS: "jms:queue:CATALOG.GET.PRODUCTORDERS"
+CATALOG_GET_PRODUCTORDER_BY_ID: "jms:queue:CATALOG.GET.PRODUCTORDER_BY_ID"
+CATALOG_ADD_PRODUCTORDER: "jms:queue:CATALOG.ADD.PRODUCTORDER"
+CATALOG_UPD_PRODUCTORDER_BY_ID: "jms:queue:CATALOG.UPD.PRODUCTORDER_BY_ID"
+CATALOG_GET_INITIAL_PRODUCTORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_PRODUCTORDERS"
+CATALOG_GET_PRODUCTORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_PRODUCTORDERS"
+CATALOG_GET_PRODUCTCATALOGS: "jms:queue:CATALOG.GET.PRODUCTCATALOGS"
+CATALOG_GET_PRODUCTCATALOG_BY_ID: "jms:queue:CATALOG.GET.PRODUCTCATALOG_BY_ID"
+CATALOG_GET_PRODUCTCATALOG_BY_NAME: "jms:queue:CATALOG.GET.PRODUCTCATALOG_BY_NAME"
+CATALOG_GET_PRODUCTCATEGORIES: "jms:queue:CATALOG.GET.PRODUCTCATEGORIES"
+CATALOG_GET_PRODUCTCATEGORY_BY_ID: "jms:queue:CATALOG.GET.PRODUCTCATEGORY_BY_ID"
+CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID: "jms:queue:CATALOG.GET.PRODUCTOFFERINGS.CATEGORY_ID"
+CATALOG_SEARCH_PRODUCTOFFERINGS: "jms:queue:CATALOG.CATALOG_SEARCH_PRODUCTOFFERINGS"
+
+
+
+
+#PM_MEASUREMENT_COLLECTION
+PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.GET_BY_ID"
+PM_MEASUREMENT_COLLECTION_JOBS_GET: "jms:queue:PM.MEASUREMENTCOLLECTIONJOBS.GET"
+PM_MEASUREMENT_COLLECTION_JOB_ADD: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.ADD"
+PM_MEASUREMENT_COLLECTION_JOB_CREATED: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.CREATED"
+PM_MEASUREMENT_COLLECTION_JOB_UPDATE: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.UPDATE"
+PM_MEASUREMENT_COLLECTION_JOB_GET_INPRORGESS_OR_PENDING: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.GET_INPRORGESS_OR_PENDING"
+
+#ALARMS
+ALARMS_ADD_ALARM: "jms:queue:ALARMS.ADD.ALARM"
+ALARMS_UPDATE_ALARM: "jms:queue:ALARMS.UPDATE.ALARM"
+ALARMS_GET_ALARM: "jms:queue:ALARMS.GET.ALARM"
+
+#EVENT TOPICS IN Message Bus
+EVENT_SERVICE_CREATE: "jms:topic:EVENT.SERVICE.CREATE"
+EVENT_SERVICE_STATE_CHANGED: "jms:topic:EVENT.SERVICE.STATECHANGED"
+EVENT_SERVICE_DELETE: "jms:topic:EVENT.SERVICE.DELETE"
+EVENT_SERVICE_ATTRIBUTE_VALUE_CHANGED: "jms:topic:EVENT.SERVICE.ATTRCHANGED"
+EVENT_SERVICE_ORDER_CREATE: "jms:topic:EVENT.SERVICEORDER.CREATE"
+EVENT_SERVICE_ORDER_STATE_CHANGED: "jms:topic:EVENT.SERVICEORDER.STATECHANGED"
+EVENT_SERVICE_ORDER_DELETE: "jms:topic:EVENT.SERVICEORDER.DELETE"
+EVENT_SERVICE_ORDER_ATTRIBUTE_VALUE_CHANGED: "jms:topic:EVENT.SERVICEORDER.ATTRCHANGED"
+EVENT_CUSTOMER_CREATE: "jms:topic:EVENT.CUSTOMER.CREATE"
+EVENT_CUSTOMER_CHANGED: "jms:topic:EVENT.CUSTOMER.CHANGE"
+EVENT_INDIVIDUAL_CREATE: "jms:topic:EVENT.INDIVIDUAL.CREATE"
+EVENT_INDIVIDUAL_CHANGED: "jms:topic:EVENT.INDIVIDUAL.CHANGE"
+EVENT_ORGANIZATION_CREATE: "jms:topic:EVENT.ORGANIZATION.CREATE"
+EVENT_ORGANIZATION_CHANGED: "jms:topic:EVENT.ORGANIZATION.CHANGE"
+EVENT_ALARM_CREATE: "jms:topic:EVENT.ALARM.CREATE"
+EVENT_MEASUREMENT_COLLECTION_JOB_CREATE: "jms:topic:EVENT.MEASUREMENTCOLLECTIONJOB.CREATE"
+EVENT_MEASUREMENT_COLLECTION_JOB_EXECUTION_STATE_CHANGED: "jms:topic:EVENT.MEASUREMENTCOLLECTIONJOB.STATECHANGED"
+EVENT_MEASUREMENT_COLLECTION_JOB_DELETE: "jms:topic:EVENT.MEASUREMENTCOLLECTIONJOB.DELETE"
+EVENT_MEASUREMENT_COLLECTION_JOB_ATTRIBUTE_VALUE_CHANGED: "jms:topic:EVENT.MEASUREMENTCOLLECTIONJOB.ATTRCHANGED"
+
+EVENT_PRODUCT_ORDER_CREATE: "jms:topic:EVENT.PRODUCTORDER.CREATE"
+EVENT_PRODUCT_ORDER_STATE_CHANGED: "jms:topic:EVENT.PRODUCTORDER.STATECHANGED"
+EVENT_PRODUCT_ORDER_DELETE: "jms:topic:EVENT.PRODUCTORDER.DELETE"
+EVENT_PRODUCT_ORDER_ATTRIBUTE_VALUE_CHANGED: "jms:topic:EVENT.PRODUCTORDER.ATTRCHANGED"
+
+#QUEUE MESSSAGES WITH VNFNSD CATALOG
+NFV_CATALOG_GET_NSD_BY_ID: "jms:queue:NFVCATALOG.GET.NSD_BY_ID"
+
+#MISC
+GET_USER_BY_USERNAME: "jms:queue:GET.USER_BY_USERNAME"
+
+#RESOURCES MESSAGES
+CATALOG_ADD_RESOURCE: "jms:queue:CATALOG.ADD.RESOURCE"
+CATALOG_UPD_RESOURCE: "jms:queue:CATALOG.UPD.RESOURCE"
+CATALOG_UPDADD_RESOURCE: "jms:queue:CATALOG.UPDADD.RESOURCE"
+CATALOG_GET_RESOURCE_BY_ID: "jms:queue:CATALOG.GET.RESOURCE"
+CATALOG_ADD_RESOURCESPEC: "jms:queue:CATALOG.ADD.RESOURCESPEC"
+CATALOG_UPD_RESOURCESPEC: "jms:queue:CATALOG.UPD.RESOURCESPEC"
+CATALOG_UPDADD_RESOURCESPEC: "jms:queue:CATALOG.UPDADD.RESOURCESPEC"
+CATALOG_GET_RESOURCESPEC_BY_ID: "jms:queue:CATALOG.GET.RESOURCESPEC_BY_ID"
+CATALOG_GET_RESOURCESPEC_BY_NAME_CATEGORY: "jms:queue:CATALOG.GET.RESOURCESPEC_BY_NAME_CATEGORY"
+EVENT_RESOURCE_CREATE: "jms:topic:EVENT.RESOURCE.CREATE"
+EVENT_RESOURCE_STATE_CHANGED: "jms:topic:EVENT.RESOURCE.STATECHANGED"
+EVENT_RESOURCE_DELETE: "jms:topic:EVENT.SERVICE.RESOURCE"
+EVENT_RESOURCE_ATTRIBUTE_VALUE_CHANGED: "jms:topic:EVENT.RESOURCE.ATTRCHANGED"
+CATALOG_RESOURCES_OF_PARTNERS: "jms:queue:CATALOG.GET.SERVICESOFPARTNERS"
+
+#RESOURCE_ACTIVATION
+CATALOG_ADD_RESOURCEACTIVATION: "jms:queue:CATALOG.ADD.RESOURCEACTIVATION"
+CATALOG_UPD_RESOURCEACTIVATION: "jms:queue:CATALOG.UPD.RESOURCEACTIVATION"
+CATALOG_UPDADD_RESOURCEACTIVATION: "jms:queue:CATALOG.UPDADD.RESOURCEACTIVATION"
+CATALOG_GET_RESOURCEACTIVATION_BY_ID: "jms:queue:CATALOG.GET.RESOURCEACTIVATION"
+
+#LCM MESSAGES
+CATALOG_GET_LCMRULE_BY_ID: "jms:queue:CATALOG.GET.LCMRULE"
+CATALOG_GET_LCMRULES_BY_SPECID_PHASE: "jms:queue:CATALOG.GET.LCMRULES_BY_SPECID_PHASE"
+
+
+#SERVICE_TEST
+CATALOG_GET_SERVICETESTSPEC_BY_ID: "jms:queue:CATALOG.GET.SERVICETESTSPEC_BY_ID"
+CATALOG_ADD_SERVICETEST: "jms:queue:CATALOG.ADD.SERVICETEST"
+CATALOG_UPD_SERVICETEST: "jms:queue:CATALOG.UPD.SERVICETEST"
+CATALOG_GET_SERVICETEST_BY_ID: "jms:queue:CATALOG.GET.SERVICETEST"
+
+#NS ACTIONS
+NFV_CATALOG_NSACTIONS_SCALE: "jms:queue:NSACTIONS.SCALE"
+NFV_CATALOG_NS_LCMCHANGED: "jms:topic:NFV_CATALOG_NS_LCMCHANGED"
+
+#RESERVATION_API
+RESERVATION_CREATE: "jms:queue:RESERVATION.ADD"
+RESERVATION_AVAILABILITY_CHECK: "jms:queue:RESERVATION.AVAILABILITYCHECK"
\ No newline at end of file
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
new file mode 100644
index 0000000000000000000000000000000000000000..74229cd400fb31f76673214d76c0256f438e4ccc
--- /dev/null
+++ b/src/main/resources/banner.txt
@@ -0,0 +1,11 @@
+ ___ ____ _ _
+ / _ \ _ __ ___ _ __ / ___|| (_) ___ ___
+ | | | | '_ \ / _ \ '_ \\___ \| | |/ __/ _ \
+ | |_| | |_) | __/ | | |___) | | | (_| __/
+ \___/| .__/ \___|_| |_|____/|_|_|\___\___|
+ |_|
+ __ __________________
+ / / __ __ / __/_ __/ __/ _/
+ / _ \/ // / / _/ / / _\ \_/ /
+ /_.__/\_, / /___/ /_/ /___/___/
+ /___/
\ No newline at end of file