Loading Dockerfile +2 −2 Original line number Diff line number Diff line FROM ibm-semeru-runtimes:open-17.0.7_7-jdk # RUN mkdir /opt/shareclasses RUN mkdir -p /opt/openslice/lib/ COPY target/org.etsi.osl.tmf.api-1.3.0-exec.jar /opt/openslice/lib/ CMD ["java", "-Xshareclasses:cacheDir=/opt/shareclasses", "-jar", "/opt/openslice/lib/org.etsi.osl.tmf.api-1.3.0-exec.jar"] COPY target/org.etsi.osl.tmf.api-1.4.0-exec.jar /opt/openslice/lib/ CMD ["java", "-Xshareclasses:cacheDir=/opt/shareclasses", "-jar", "/opt/openslice/lib/org.etsi.osl.tmf.api-1.4.0-exec.jar"] EXPOSE 13082 No newline at end of file pom.xml +1 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ <parent> <groupId>org.etsi.osl</groupId> <artifactId>org.etsi.osl.main</artifactId> <version>2025Q4</version> <version>2026Q2</version> <relativePath>../org.etsi.osl.main</relativePath> </parent> Loading src/main/java/org/etsi/osl/tmf/ri639/api/ResourceApiRouteBuilder.java +9 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,9 @@ public class ResourceApiRouteBuilder extends RouteBuilder { @Value("${CATALOG_RESOURCES_OF_PARTNERS}") private String CATALOG_RESOURCES_OF_PARTNERS = ""; @Value("${CATALOG_GET_RESOURCES_BY_FILTER}") private String CATALOG_GET_RESOURCES_BY_FILTER = ""; @Autowired private ProducerTemplate template; Loading Loading @@ -110,6 +113,12 @@ public class ResourceApiRouteBuilder extends RouteBuilder { .bean( resourceRepoService, "addOrUpdateResourceByNameCategoryVersion(${header.aname},${header.acategory}, ${header.aversion}, ${body})") .marshal().json( JsonLibrary.Jackson) .convertBodyTo( String.class ); from( CATALOG_GET_RESOURCES_BY_FILTER ) .log(LoggingLevel.DEBUG, log, CATALOG_GET_RESOURCES_BY_FILTER + " message received!") .to("log:DEBUG?showBody=true&showHeaders=true") .convertBodyTo( String.class ) .bean( resourceRepoService, "findResourcesByFilter(${body})"); } Loading src/main/java/org/etsi/osl/tmf/ri639/reposervices/ResourceFilter.java 0 → 100644 +43 −0 Original line number Diff line number Diff line package org.etsi.osl.tmf.ri639.reposervices; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** * Filter DTO for querying resources via the CATALOG_GET_RESOURCES_BY_FILTER JMS route. * Example: {"specId":null,"namePattern":null,"vendor":null,"location":null,"status":"AVAILABLE","page":0,"pageSize":20} */ @JsonIgnoreProperties(ignoreUnknown = true) public class ResourceFilter { private String specId; private String namePattern; /** Matched against a resource characteristic named "vendor" */ private String vendor; /** Matched against place.name */ private String location; /** Matched against resourceStatus enum value (e.g. "AVAILABLE") */ private String status; private int page = 0; private int pageSize = 20; public String getSpecId() { return specId; } public void setSpecId(String specId) { this.specId = specId; } public String getNamePattern() { return namePattern; } public void setNamePattern(String namePattern) { this.namePattern = namePattern; } public String getVendor() { return vendor; } public void setVendor(String vendor) { this.vendor = vendor; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } } src/main/java/org/etsi/osl/tmf/ri639/reposervices/ResourceRepoService.java +128 −41 Original line number Diff line number Diff line /*- * ========================LICENSE_START================================= * org.etsi.osl.tmf.api * %% * 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.tmf.ri639.reposervices; import java.io.UnsupportedEncodingException; Loading @@ -25,6 +6,7 @@ import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; Loading Loading @@ -57,6 +39,7 @@ import org.etsi.osl.tmf.ri639.model.ResourceCreateNotification; import org.etsi.osl.tmf.ri639.model.ResourceRelationship; import org.etsi.osl.tmf.ri639.model.ResourceStateChangeEvent; import org.etsi.osl.tmf.ri639.model.ResourceStateChangeNotification; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; import org.etsi.osl.tmf.ri639.model.ResourceUpdate; import org.etsi.osl.tmf.ri639.repo.ResourceRepository; import org.etsi.osl.tmf.sim638.model.Service; Loading Loading @@ -476,29 +459,24 @@ public class ResourceRepoService { @Transactional public Resource getResourceEager(String id) { Resource s = null; try(Session session = sessionFactory.openSession()) { Transaction tx = session.beginTransaction(); s = (Resource) session.get(Resource.class, id); if (s == null) { return this.findByUuid(id);// last resort if (id == null || id.equals("")) { return null; } Hibernate.initialize(s.getRelatedParty()); Hibernate.initialize(s.getNote()); Hibernate.initialize(s.getResourceCharacteristic()); Hibernate.initialize(s.getResourceSpecification()); Hibernate.initialize(s.getResourceRelationship()); Hibernate.initialize(s.getAttachment()); Hibernate.initialize(s.getActivationFeature()); Resource r = this.findByUuid(id);; tx.commit(); } catch (Exception e) { e.printStackTrace(); if (r == null) { return null; } Hibernate.initialize(r.getRelatedParty()); Hibernate.initialize(r.getNote()); Hibernate.initialize(r.getResourceCharacteristic()); Hibernate.initialize(r.getResourceSpecification()); Hibernate.initialize(r.getResourceRelationship()); Hibernate.initialize(r.getAttachment()); Hibernate.initialize(r.getActivationFeature()); return s; return r; } Loading Loading @@ -575,6 +553,113 @@ public class ResourceRepoService { } /** * Find resources matching the given filter. * Returns JSON: {"resources":[...],"totalCount":N,"continuationToken":"<nextPage>" or null} * Filter fields: specId, namePattern, vendor (characteristic), location (place.name), status, page, pageSize. */ @Transactional public String findResourcesByFilter(String filterJson) throws JsonProcessingException { ResourceFilter filter; try { filter = objectMapper.readValue(filterJson, ResourceFilter.class); } catch (Exception e) { logger.error("Cannot parse ResourceFilter JSON: " + filterJson, e); return emptyBrowseResult(); } Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); try { boolean joinVendorChar = filter.getVendor() != null; List<String> conditions = new ArrayList<>(); Map<String, Object> params = new HashMap<>(); if (filter.getSpecId() != null) { conditions.add("srv.resourceSpecification.uuid = :specId"); params.put("specId", filter.getSpecId()); } if (filter.getNamePattern() != null) { conditions.add("srv.name LIKE :namePattern"); params.put("namePattern", "%" + filter.getNamePattern() + "%"); } if (joinVendorChar) { conditions.add("vendorChar.name = 'vendor' AND vendorChar.value.value = :vendor"); params.put("vendor", filter.getVendor()); } if (filter.getLocation() != null) { conditions.add("srv.place.name LIKE :location"); params.put("location", "%" + filter.getLocation() + "%"); } if (filter.getStatus() != null) { ResourceStatusType statusEnum = ResourceStatusType.fromValue(filter.getStatus().toLowerCase()); if (statusEnum != null) { conditions.add("srv.resourceStatus = :status"); params.put("status", statusEnum); } else { logger.warn("Unknown resourceStatus filter value: " + filter.getStatus()); } } String whereClause = conditions.isEmpty() ? "" : "WHERE " + String.join(" AND ", conditions) + " "; String joinClause = joinVendorChar ? "JOIN srv.resourceCharacteristic vendorChar " : ""; // COUNT query for totalCount String countHql = "SELECT COUNT(DISTINCT srv) FROM RIResource srv " + joinClause + whereClause; org.hibernate.query.Query<Long> countQuery = session.createQuery(countHql, Long.class); params.forEach(countQuery::setParameter); long totalCount = countQuery.uniqueResult(); // Data query with pagination String dataHql = "SELECT DISTINCT srv FROM RIResource srv " + joinClause + whereClause + "ORDER BY srv.name ASC"; org.hibernate.query.Query<Resource> query = session.createQuery(dataHql, Resource.class); params.forEach(query::setParameter); int pageSize = filter.getPageSize() > 0 ? filter.getPageSize() : 20; int page = filter.getPage() >= 0 ? filter.getPage() : 0; query.setFirstResult(page * pageSize); query.setMaxResults(pageSize); List<Resource> resources = query.list(); List<Map<String, Object>> resourceList = new ArrayList<>(); for (Resource r : resources) { Hibernate.initialize(r.getResourceCharacteristic()); Hibernate.initialize(r.getResourceSpecification()); Map<String, Object> entry = new LinkedHashMap<>(); entry.put("id", r.getUuid()); entry.put("@type", r.getType()); entry.put("name", r.getName()); entry.put("category", r.getCategory()); entry.put("description", r.getDescription()); entry.put("resourceStatus", r.getResourceStatus() != null ? r.getResourceStatus().toString() : null); if (r.getResourceSpecification() != null) { entry.put("resourceSpecificationId", r.getResourceSpecification().getUuid()); entry.put("resourceSpecificationName", r.getResourceSpecification().getName()); } resourceList.add(entry); } boolean hasMore = (long) (page + 1) * pageSize < totalCount; String continuationToken = hasMore ? String.valueOf(page + 1) : null; Map<String, Object> browseResult = new LinkedHashMap<>(); browseResult.put("resources", resourceList); browseResult.put("totalCount", totalCount); browseResult.put("continuationToken", continuationToken); tx.commit(); return objectMapper.writeValueAsString(browseResult); } catch (Exception e) { logger.error("Error querying resources by filter", e); tx.rollback(); return emptyBrowseResult(); } finally { session.close(); } } @Transactional public Resource addOrUpdateResourceByNameCategoryVersion(String aName, String aCategory, String aVersion, ResourceCreate aesourceCreate) { Loading Loading @@ -606,6 +691,8 @@ public class ResourceRepoService { return result; } private String emptyBrowseResult() { return "{\"resources\":[],\"totalCount\":0,\"continuationToken\":null}"; } } Loading
Dockerfile +2 −2 Original line number Diff line number Diff line FROM ibm-semeru-runtimes:open-17.0.7_7-jdk # RUN mkdir /opt/shareclasses RUN mkdir -p /opt/openslice/lib/ COPY target/org.etsi.osl.tmf.api-1.3.0-exec.jar /opt/openslice/lib/ CMD ["java", "-Xshareclasses:cacheDir=/opt/shareclasses", "-jar", "/opt/openslice/lib/org.etsi.osl.tmf.api-1.3.0-exec.jar"] COPY target/org.etsi.osl.tmf.api-1.4.0-exec.jar /opt/openslice/lib/ CMD ["java", "-Xshareclasses:cacheDir=/opt/shareclasses", "-jar", "/opt/openslice/lib/org.etsi.osl.tmf.api-1.4.0-exec.jar"] EXPOSE 13082 No newline at end of file
pom.xml +1 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ <parent> <groupId>org.etsi.osl</groupId> <artifactId>org.etsi.osl.main</artifactId> <version>2025Q4</version> <version>2026Q2</version> <relativePath>../org.etsi.osl.main</relativePath> </parent> Loading
src/main/java/org/etsi/osl/tmf/ri639/api/ResourceApiRouteBuilder.java +9 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,9 @@ public class ResourceApiRouteBuilder extends RouteBuilder { @Value("${CATALOG_RESOURCES_OF_PARTNERS}") private String CATALOG_RESOURCES_OF_PARTNERS = ""; @Value("${CATALOG_GET_RESOURCES_BY_FILTER}") private String CATALOG_GET_RESOURCES_BY_FILTER = ""; @Autowired private ProducerTemplate template; Loading Loading @@ -110,6 +113,12 @@ public class ResourceApiRouteBuilder extends RouteBuilder { .bean( resourceRepoService, "addOrUpdateResourceByNameCategoryVersion(${header.aname},${header.acategory}, ${header.aversion}, ${body})") .marshal().json( JsonLibrary.Jackson) .convertBodyTo( String.class ); from( CATALOG_GET_RESOURCES_BY_FILTER ) .log(LoggingLevel.DEBUG, log, CATALOG_GET_RESOURCES_BY_FILTER + " message received!") .to("log:DEBUG?showBody=true&showHeaders=true") .convertBodyTo( String.class ) .bean( resourceRepoService, "findResourcesByFilter(${body})"); } Loading
src/main/java/org/etsi/osl/tmf/ri639/reposervices/ResourceFilter.java 0 → 100644 +43 −0 Original line number Diff line number Diff line package org.etsi.osl.tmf.ri639.reposervices; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** * Filter DTO for querying resources via the CATALOG_GET_RESOURCES_BY_FILTER JMS route. * Example: {"specId":null,"namePattern":null,"vendor":null,"location":null,"status":"AVAILABLE","page":0,"pageSize":20} */ @JsonIgnoreProperties(ignoreUnknown = true) public class ResourceFilter { private String specId; private String namePattern; /** Matched against a resource characteristic named "vendor" */ private String vendor; /** Matched against place.name */ private String location; /** Matched against resourceStatus enum value (e.g. "AVAILABLE") */ private String status; private int page = 0; private int pageSize = 20; public String getSpecId() { return specId; } public void setSpecId(String specId) { this.specId = specId; } public String getNamePattern() { return namePattern; } public void setNamePattern(String namePattern) { this.namePattern = namePattern; } public String getVendor() { return vendor; } public void setVendor(String vendor) { this.vendor = vendor; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } }
src/main/java/org/etsi/osl/tmf/ri639/reposervices/ResourceRepoService.java +128 −41 Original line number Diff line number Diff line /*- * ========================LICENSE_START================================= * org.etsi.osl.tmf.api * %% * 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.tmf.ri639.reposervices; import java.io.UnsupportedEncodingException; Loading @@ -25,6 +6,7 @@ import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; Loading Loading @@ -57,6 +39,7 @@ import org.etsi.osl.tmf.ri639.model.ResourceCreateNotification; import org.etsi.osl.tmf.ri639.model.ResourceRelationship; import org.etsi.osl.tmf.ri639.model.ResourceStateChangeEvent; import org.etsi.osl.tmf.ri639.model.ResourceStateChangeNotification; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; import org.etsi.osl.tmf.ri639.model.ResourceUpdate; import org.etsi.osl.tmf.ri639.repo.ResourceRepository; import org.etsi.osl.tmf.sim638.model.Service; Loading Loading @@ -476,29 +459,24 @@ public class ResourceRepoService { @Transactional public Resource getResourceEager(String id) { Resource s = null; try(Session session = sessionFactory.openSession()) { Transaction tx = session.beginTransaction(); s = (Resource) session.get(Resource.class, id); if (s == null) { return this.findByUuid(id);// last resort if (id == null || id.equals("")) { return null; } Hibernate.initialize(s.getRelatedParty()); Hibernate.initialize(s.getNote()); Hibernate.initialize(s.getResourceCharacteristic()); Hibernate.initialize(s.getResourceSpecification()); Hibernate.initialize(s.getResourceRelationship()); Hibernate.initialize(s.getAttachment()); Hibernate.initialize(s.getActivationFeature()); Resource r = this.findByUuid(id);; tx.commit(); } catch (Exception e) { e.printStackTrace(); if (r == null) { return null; } Hibernate.initialize(r.getRelatedParty()); Hibernate.initialize(r.getNote()); Hibernate.initialize(r.getResourceCharacteristic()); Hibernate.initialize(r.getResourceSpecification()); Hibernate.initialize(r.getResourceRelationship()); Hibernate.initialize(r.getAttachment()); Hibernate.initialize(r.getActivationFeature()); return s; return r; } Loading Loading @@ -575,6 +553,113 @@ public class ResourceRepoService { } /** * Find resources matching the given filter. * Returns JSON: {"resources":[...],"totalCount":N,"continuationToken":"<nextPage>" or null} * Filter fields: specId, namePattern, vendor (characteristic), location (place.name), status, page, pageSize. */ @Transactional public String findResourcesByFilter(String filterJson) throws JsonProcessingException { ResourceFilter filter; try { filter = objectMapper.readValue(filterJson, ResourceFilter.class); } catch (Exception e) { logger.error("Cannot parse ResourceFilter JSON: " + filterJson, e); return emptyBrowseResult(); } Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); try { boolean joinVendorChar = filter.getVendor() != null; List<String> conditions = new ArrayList<>(); Map<String, Object> params = new HashMap<>(); if (filter.getSpecId() != null) { conditions.add("srv.resourceSpecification.uuid = :specId"); params.put("specId", filter.getSpecId()); } if (filter.getNamePattern() != null) { conditions.add("srv.name LIKE :namePattern"); params.put("namePattern", "%" + filter.getNamePattern() + "%"); } if (joinVendorChar) { conditions.add("vendorChar.name = 'vendor' AND vendorChar.value.value = :vendor"); params.put("vendor", filter.getVendor()); } if (filter.getLocation() != null) { conditions.add("srv.place.name LIKE :location"); params.put("location", "%" + filter.getLocation() + "%"); } if (filter.getStatus() != null) { ResourceStatusType statusEnum = ResourceStatusType.fromValue(filter.getStatus().toLowerCase()); if (statusEnum != null) { conditions.add("srv.resourceStatus = :status"); params.put("status", statusEnum); } else { logger.warn("Unknown resourceStatus filter value: " + filter.getStatus()); } } String whereClause = conditions.isEmpty() ? "" : "WHERE " + String.join(" AND ", conditions) + " "; String joinClause = joinVendorChar ? "JOIN srv.resourceCharacteristic vendorChar " : ""; // COUNT query for totalCount String countHql = "SELECT COUNT(DISTINCT srv) FROM RIResource srv " + joinClause + whereClause; org.hibernate.query.Query<Long> countQuery = session.createQuery(countHql, Long.class); params.forEach(countQuery::setParameter); long totalCount = countQuery.uniqueResult(); // Data query with pagination String dataHql = "SELECT DISTINCT srv FROM RIResource srv " + joinClause + whereClause + "ORDER BY srv.name ASC"; org.hibernate.query.Query<Resource> query = session.createQuery(dataHql, Resource.class); params.forEach(query::setParameter); int pageSize = filter.getPageSize() > 0 ? filter.getPageSize() : 20; int page = filter.getPage() >= 0 ? filter.getPage() : 0; query.setFirstResult(page * pageSize); query.setMaxResults(pageSize); List<Resource> resources = query.list(); List<Map<String, Object>> resourceList = new ArrayList<>(); for (Resource r : resources) { Hibernate.initialize(r.getResourceCharacteristic()); Hibernate.initialize(r.getResourceSpecification()); Map<String, Object> entry = new LinkedHashMap<>(); entry.put("id", r.getUuid()); entry.put("@type", r.getType()); entry.put("name", r.getName()); entry.put("category", r.getCategory()); entry.put("description", r.getDescription()); entry.put("resourceStatus", r.getResourceStatus() != null ? r.getResourceStatus().toString() : null); if (r.getResourceSpecification() != null) { entry.put("resourceSpecificationId", r.getResourceSpecification().getUuid()); entry.put("resourceSpecificationName", r.getResourceSpecification().getName()); } resourceList.add(entry); } boolean hasMore = (long) (page + 1) * pageSize < totalCount; String continuationToken = hasMore ? String.valueOf(page + 1) : null; Map<String, Object> browseResult = new LinkedHashMap<>(); browseResult.put("resources", resourceList); browseResult.put("totalCount", totalCount); browseResult.put("continuationToken", continuationToken); tx.commit(); return objectMapper.writeValueAsString(browseResult); } catch (Exception e) { logger.error("Error querying resources by filter", e); tx.rollback(); return emptyBrowseResult(); } finally { session.close(); } } @Transactional public Resource addOrUpdateResourceByNameCategoryVersion(String aName, String aCategory, String aVersion, ResourceCreate aesourceCreate) { Loading Loading @@ -606,6 +691,8 @@ public class ResourceRepoService { return result; } private String emptyBrowseResult() { return "{\"resources\":[],\"totalCount\":0,\"continuationToken\":null}"; } }