All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ninja.abap.odatamock.server.ODataMockServer Maven / Gradle / Ivy

/*
 * Copyright (C) 2019 Guilherme Maeda
 *
 * 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.
 */
package ninja.abap.odatamock.server;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.ep.EntityProvider;
import org.apache.olingo.odata2.api.exception.ODataException;
import org.apache.olingo.odata2.core.edm.provider.EdmxProvider;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import lombok.Getter;
import lombok.NonNull;
import ninja.abap.odatamock.event.FunctionImportHandler;

@Getter
public class ODataMockServer {

	protected Server server;
	protected URI uri;

	/**
	 * Mock Data Store - Use this property to manipulate the served data.
	 */
	@Getter
	protected MockDataStore dataStore;

	@Getter
	protected final String edmx;
	@Getter
	protected final Edm edm;
	@Getter
	protected final EdmxProvider edmProvider;

	protected final ODataMockServerBuilder options;
	protected DataSource dataSource;
	protected MockServiceFactory serviceFactory;
	protected MockServlet servlet;

	/**
	 * Constructor - Initializes and starts the OData server.
	 * @param options OData server options
	 * @throws ODataException If the OData server fails to load
	 * @throws IOException If the Edmx file cannot be read
	 * @throws Exception If the Edmx parsing the HTTP server fails to start
	 */
	ODataMockServer(final @NonNull ODataMockServerBuilder options)
			throws ODataException, IOException, Exception {
		this.options = options;

		// Parse the provided metadata file using Olingo and initialize the
		//  in-memory Olingo data store and processor.
		this.edmx = IOUtils.toString(options.edmx(), StandardCharsets.UTF_8);
		this.edm = EntityProvider.readMetadata(IOUtils.toInputStream(this.edmx, StandardCharsets.UTF_8), true);
		this.edmProvider = new EdmxProvider().parse(IOUtils.toInputStream(this.edmx, StandardCharsets.UTF_8), true);

		this.dataStore = new MockDataStore(edmProvider);
		this.dataSource = createDataSource();

		this.serviceFactory = new MockServiceFactory(edmProvider, dataSource);
		this.servlet = new MockServlet(serviceFactory);

		// Load/generate mock data
		if (options.localDataPath() != null) {
			MockDataLoader loader = new MockDataLoader(edm, edmProvider, options.localDataPath(), dataStore);
			loader.load(options.generateMissing());
		}

		start();
	}

	/**
	 * Start the Jetty HTTP server and registers the OData servlet
	 * @throws Exception If Jetty fails to start
	 */
	public void start() throws Exception {
		if (server != null && server.isRunning())
			return; // Already started

		server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(options.portNumber());
        server.setConnectors(new Connector[] {connector});

    	ServletHolder servletHolder = new ServletHolder(servlet);

        ServletContextHandler newHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
        newHandler.setContextPath("/");

    	String servletPath = StringUtils.removeEnd(options.rootPath(), "/");
    	newHandler.addServlet(servletHolder, servletPath + "/*");
		server.setHandler(newHandler);

    	server.start();
    	this.uri = new URI(StringUtils.appendIfMissing(server.getURI().toString() + servletPath, "/"));
	}

	/**
	 * Stop the Jetty HTTP server
	 * @throws Exception If Jetty fails to stop
	 */
	public void stop() throws Exception {
		if (server != null && server.isRunning())
			server.stop();
	}

	/**
	 * Registers a Function Import handler for a specific function import.
	 * @param functionName The Function Import name
	 * @param handler A handler function to respond to the requests
	 * @return This same instance for fluent calls
	 */
	public ODataMockServer onFunctionImport(String functionName, FunctionImportHandler handler) {
		if (dataSource instanceof MockDataSource) {
			MockDataSource mds = (MockDataSource) dataSource;
			mds.getFunctionImportHandlers().put(functionName, handler);
		}
		return this;
	}

	/**
	 * Unregisters all currently registered event handlers.
	 * @return This same instance for fluent calls
	 */
	public ODataMockServer clearHandlers() {
		if (dataSource instanceof MockDataSource) {
			MockDataSource mds = (MockDataSource) dataSource;
			mds.getFunctionImportHandlers().clear();
		}
		return this;
	}

	/**
	 * Creates a new DataSource instance for handling the OData requests.
	 * Override this method if you need more advanced customization.
	 * @return New DataSource instance
	 * @throws ODataException If the DataSource initialization fails
	 */
	protected DataSource createDataSource() throws ODataException {
		return new MockDataSource(edmProvider, dataStore);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy