Skip to content

Commit

Permalink
Adds draft of createAAS Method with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
FriedJannik committed Sep 16, 2024
1 parent 7fffd7b commit 1627a40
Show file tree
Hide file tree
Showing 11 changed files with 394 additions and 11 deletions.
16 changes: 16 additions & 0 deletions basyx.gateway/basyx.gateway-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,25 @@
<name>BaSyx Gateway HTTP</name>
<description>BaSyx Gateway HTTP</description>
<dependencies>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.aas4j</groupId>
<artifactId>aas4j-model</artifactId>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>5.15.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-client-java</artifactId>
<version>5.15.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*******************************************************************************
* Copyright (C) 2024 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.gateway.core;

import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
import org.eclipse.digitaltwin.basyx.gateway.core.exception.BaSyxComponentNotHealthyException;
import org.eclipse.digitaltwin.basyx.gateway.core.feature.Gateway;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class DefaultGateway implements Gateway {

private Logger logger = LoggerFactory.getLogger(DefaultGateway.class);

@Override
public void createAAS(AssetAdministrationShell aas, String aasRepository, String aasRegistry) throws BaSyxComponentNotHealthyException{
throwExceptionIfIsUnhealthyBaSyxComponent(aasRepository);
if(aasRegistry != null){
throwExceptionIfIsUnhealthyBaSyxComponent(aasRegistry);
}
}

private void throwExceptionIfIsUnhealthyBaSyxComponent(String componentURL) {
componentURL = formatURL(componentURL);

if (isBaSyxComponent(componentURL) && !isHealthy(componentURL)) {
throw new BaSyxComponentNotHealthyException(componentURL + " is not healthy");
}
}

private String formatURL(String componentURL) {
try {
URL url = new URL(componentURL);
String protocol = url.getProtocol();
String host = url.getHost();
int port = url.getPort();
if (port == -1) { // no port specified, use default port
port = url.getDefaultPort();
}
componentURL = protocol + "://" + host + ":" + port;
} catch (Exception e) {
logger.error(e.getMessage());
}
return componentURL;
}

private boolean isBaSyxComponent(String componentURL) {
try {
HttpURLConnection connection = getRequest(componentURL, "/shells");

String aasMiddleware = connection.getHeaderField("AASMiddleware");

return "BaSyx".equals(aasMiddleware);
} catch (Exception e) {
logger.error(e.getMessage());
return false;
}
}

private boolean isHealthy(String componentURL){
try {
HttpURLConnection connection = getRequest(componentURL, "/actuator/health");

String body = new String(connection.getInputStream().readAllBytes());

return connection.getResponseCode() == 200 && body.equals("{'status':'UP'}");

} catch (Exception e) {
logger.error(e.getMessage());
return false;
}
}

private static HttpURLConnection getRequest(String componentURL, String path) throws IOException {
URL url = new URL(componentURL + path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
return connection;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.eclipse.digitaltwin.basyx.gateway.core;

import org.eclipse.digitaltwin.basyx.gateway.core.feature.Gateway;

public interface GatewayFactory {
public Gateway create();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (C) 2024 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.gateway.core.exception;

public class BaSyxComponentNotHealthyException extends RuntimeException{

public BaSyxComponentNotHealthyException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.eclipse.digitaltwin.basyx.gateway.core.feature;

import org.eclipse.digitaltwin.basyx.core.BaSyxFeature;
import org.eclipse.digitaltwin.basyx.gateway.core.GatewayFactory;

public interface GatewayFeature extends BaSyxFeature<GatewayFactory> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*******************************************************************************
* Copyright (C) 2024 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.gateway;

import org.apache.http.HttpStatus;
import org.eclipse.digitaltwin.basyx.gateway.core.DefaultGateway;
import org.eclipse.digitaltwin.basyx.gateway.core.exception.BaSyxComponentNotHealthyException;
import org.eclipse.digitaltwin.basyx.gateway.core.feature.Gateway;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockserver.client.MockServerClient;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.verify.VerificationTimes;

public class TestGateway {

public static ClientAndServer mockBaSyxAasRepository;
public static ClientAndServer mockAasRegistry;
private Gateway gateway;

@Before
public void setUp(){
mockBaSyxAasRepository = ClientAndServer.startClientAndServer(6006);
gateway = new DefaultGateway();
}

@After
public void tearDown(){
mockBaSyxAasRepository.stop();
}

@Test
public void testCreateAASWithHealthyBaSyxComponent(){
new MockServerClient("localhost", 6006)
.when(org.mockserver.model.HttpRequest.request()
.withMethod("GET")
.withPath("/shells"))
.respond(org.mockserver.model.HttpResponse.response()
.withStatusCode(HttpStatus.SC_OK)
.withHeader("AASMiddleware","BaSyx")
.withBody("{}"));
new MockServerClient("localhost", 6006)
.when(org.mockserver.model.HttpRequest.request()
.withMethod("GET")
.withPath("/actuator/health"))
.respond(org.mockserver.model.HttpResponse.response()
.withStatusCode(HttpStatus.SC_OK)
.withBody("{'status':'UP'}"));
gateway.createAAS(null, "http://localhost:6006", null);
verifyCall("/shells",1);
verifyCall("/actuator/health",1);
}

@Test(expected = BaSyxComponentNotHealthyException.class)
public void testCreateAASWithUnhealthyBaSyxComponent(){
new MockServerClient("localhost", 6006)
.when(org.mockserver.model.HttpRequest.request()
.withMethod("GET")
.withPath("/shells"))
.respond(org.mockserver.model.HttpResponse.response()
.withStatusCode(HttpStatus.SC_OK)
.withHeader("AASMiddleware","BaSyx")
.withBody("{}"));
new MockServerClient("localhost", 6006)
.when(org.mockserver.model.HttpRequest.request()
.withMethod("GET")
.withPath("/actuator/health"))
.respond(org.mockserver.model.HttpResponse.response()
.withStatusCode(HttpStatus.SC_OK)
.withBody("{'status':'DOWN'}"));
gateway.createAAS(null, "http://localhost:6006", null);
}

@Test
public void testCreateAASWithNonBaSyxComponent(){
new MockServerClient("localhost", 6006)
.when(org.mockserver.model.HttpRequest.request()
.withMethod("GET")
.withPath("/shells"))
.respond(org.mockserver.model.HttpResponse.response()
.withStatusCode(HttpStatus.SC_OK)
.withBody("{}"));
new MockServerClient("localhost", 6006)
.when(org.mockserver.model.HttpRequest.request()
.withMethod("GET")
.withPath("/actuator/health"))
.respond(org.mockserver.model.HttpResponse.response()
.withStatusCode(HttpStatus.SC_OK)
.withBody("{'status':'UP'}"));
gateway.createAAS(null, "http://localhost:6006", null);
verifyCall("/shells",1);
verifyCall("/actuator/health",0);
}

private void verifyCall(String path, int timesCalled) {
new MockServerClient("localhost", 6006).verify(org.mockserver.model.HttpRequest.request().withMethod("GET")
.withPath(path)
, VerificationTimes.exactly(timesCalled));
}
}
8 changes: 6 additions & 2 deletions basyx.gateway/basyx.gateway.component/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@

<dependencies>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.gateway-http</artifactId>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.gateway-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.gateway-http</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

package org.eclipse.digitaltwin.basyx.gateway.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
Expand All @@ -35,6 +37,7 @@

@Component
public class ConfigurationGuard implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(ConfigurationGuard.class);

@Value("${basyx.gateway.aas-repository:#{null}}")
public String aasRepositoryURL;
Expand All @@ -52,20 +55,20 @@ public void afterPropertiesSet() throws Exception {
printWarning(missingNonRequiredProperties);
}

System.out.println("\n:::::::::::::::: BaSyx Gateway Configuration ::::::::::::::::");
logger.info("\n:::::::::::::::: BaSyx Gateway Configuration ::::::::::::::::");
if (aasRepositoryURL != null) {
System.out.println(":: Default AAS Repository URL: " + aasRepositoryURL);
logger.info(":: Default AAS Repository URL: " + aasRepositoryURL);
}
if (submodelRepositoryURL != null) {
System.out.println(":: Default Submodel Repository URL: " + submodelRepositoryURL);
logger.info(":: Default Submodel Repository URL: " + submodelRepositoryURL);
}
if (aasRegistryURL != null) {
System.out.println(":: Default AAS Registry URL: " + aasRegistryURL);
logger.info(":: Default AAS Registry URL: " + aasRegistryURL);
}
if (submodelRegistryURL != null) {
System.out.println(":: Default Submodel Registry URL: " + submodelRegistryURL);
logger.info(":: Default Submodel Registry URL: " + submodelRegistryURL);
}
System.out.println(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n");
logger.info(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n");
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@

package org.eclipse.digitaltwin.basyx.gateway.component;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(
scanBasePackages = "org.eclipse.digitaltwin.basyx",
Expand Down
Loading

0 comments on commit 1627a40

Please sign in to comment.