blob: 505018d66cc33babf69786dba701449c960a2345 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2021 the Eclipse BaSyx Authors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
******************************************************************************/
package org.eclipse.basyx.examples.snippets.undoc.aas.embedhttp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import org.eclipse.basyx.vab.backend.server.utils.JSONProvider;
import org.eclipse.basyx.vab.core.IModelProvider;
import org.eclipse.basyx.vab.core.tools.VABPathTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
/**
* Implements an embedded HTTP server
*
* @author kuhn
*
*/
public class EmbeddedHTTPServer implements HttpHandler {
/**
* Initiates a logger using the current class
*/
private static final Logger logger = LoggerFactory.getLogger(EmbeddedHTTPServer.class);
/**
* Reference to IModelProvider backend
*/
protected JSONProvider<IModelProvider> providerBackend = null;
/**
* HTTP server instance
*/
protected HttpServer server = null;
/**
* Constructor
*/
public EmbeddedHTTPServer(String context, IModelProvider provider) {
// Create HTTP server instance
try {
// Create server and set context
server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext(context, this);
// - Create a default executor
server.setExecutor(null);
} catch (IOException e) {
e.printStackTrace();
}
// Store provider reference
providerBackend = new JSONProvider<IModelProvider>(provider);
}
/**
* Handle a HTTP request
*/
@Override
public void handle(HttpExchange t) throws IOException {
// Switch based on request method
switch (t.getRequestMethod()) {
// Process HTTP GET request (implement "Get" operation)
case "GET": {
// Get path to element
String path = extractPath(t);
// Setup HTML response header
Headers responseHeaders = t.getResponseHeaders();
responseHeaders.set("Content-Type", "application/json; charset=utf-8");
t.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0);
// Process get request
providerBackend.processBaSysGet(path, new PrintWriter(t.getResponseBody()));
// End processing
break;
}
// Process HTTP POST request (Creates a new Property, Operation, Event, Submodel or AAS or invokes an operation)
case "POST": {
// Get path to element and de-serialize value
String path = extractPath(t);
String serValue = extractSerializedValue(t);
// Setup HTML response header
Headers responseHeaders = t.getResponseHeaders();
responseHeaders.set("Content-Type", "application/json; charset=utf-8");
t.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0);
// Check if request is for property creation or operation invoke
if (VABPathTools.isOperationPath(path)) {
// Invoke BaSys VAB 'invoke' primitive
providerBackend.processBaSysInvoke(path, serValue, new PrintWriter(t.getResponseBody()));
} else {
// Invoke the BaSys 'create' primitive
providerBackend.processBaSysCreate(path, serValue, new PrintWriter(t.getResponseBody()));
}
// End processing
break;
}
// Process HTTP PUT operation (implement "Set" operation)
case "PUT": {
// Get path to element and de-serialize value
String path = extractPath(t);
String serValue = extractSerializedValue(t);
// Process put request
providerBackend.processBaSysSet(path, serValue.toString(), new PrintWriter(t.getResponseBody()));
// End processing
break;
}
// Process HTTP PATCH operation (Updates a map or collection)
case "PATCH": {
// Get path to element and de-serialize value
String path = extractPath(t);
String serValue = extractSerializedValue(t);
// Process patch request
providerBackend.processBaSysDelete(path, serValue.toString(), new PrintWriter(t.getResponseBody()));
// End processing
break;
}
// Process HTTP DELETE operation (Deletes any resource under the given path)
case "DELETE": {
// Get path to element
String path = extractPath(t);
// No parameter to read! Provide serialized null
String nullParam = "";
// Process delete request
providerBackend.processBaSysDelete(path, nullParam, new PrintWriter(t.getResponseBody()));
// End processing
break;
}
// Handle unknown HTTP request methods
default:
logger.debug(" - Unknown Method:"+t.getRequestMethod());
break;
}
// Close output stream
OutputStream os = t.getResponseBody();
os.close();
}
/**
* Extract a path from a HTTP request
*/
private String extractPath(HttpExchange req) throws UnsupportedEncodingException {
// Extract path
String uri = req.getRequestURI().getPath();
String contextPath = req.getHttpContext().getPath();
String path = uri.substring(contextPath.length() + 1);
// Add leading "/" to path if necessary
if (!path.startsWith("/")) {
path = "/" + path;
}
// Decode URL
path = java.net.URLDecoder.decode(path, "UTF-8");
// Return path
return path;
}
/**
* Read serialized value
*/
private String extractSerializedValue(HttpExchange req) throws IOException {
// Read request body
InputStream is = req.getRequestBody();
StringBuilder serValue = new StringBuilder();
// This seems kind of slow...
while (is.available() > 0) {
serValue.append(String.valueOf((char) (byte) is.read()));
}
return serValue.toString();
}
/**
* Start server
*/
public void start() {
// Start HTTP server
server.start();
}
/**
* Stop server
*/
public void stop() {
// Stop HTTP server
this.stop(0);
}
/**
* Stop server
*/
public void stop(int endCode) {
// Stop HTTP server
server.stop(endCode);
}
}