com.vmware.photon.controller.common.dcp.BasicServiceHost.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.photon.controller.common.dcp.BasicServiceHost.java

Source

/*
 * Copyright 2015 VMware, Inc. All Rights Reserved.
 *
 * 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 com.vmware.photon.controller.common.dcp;

import com.vmware.xenon.common.FactoryService;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.Service;
import com.vmware.xenon.common.ServiceDocument;
import com.vmware.xenon.common.ServiceHost;
import com.vmware.xenon.common.UriUtils;
import com.vmware.xenon.common.Utils;
import com.vmware.xenon.services.common.QueryTask;

import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;

import java.io.File;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.function.Predicate;
import java.util.logging.Level;

/**
 * Test helper used to test DCP services in isolation.
 */
public class BasicServiceHost extends ServiceHost implements DcpHostInfoProvider {
    public static final String FIELD_NAME_SELF_LINK = "SELF_LINK";
    public static final String SERVICE_URI = "/TestService";
    public static final int WAIT_ITERATION_SLEEP = 500;
    public static final int WAIT_ITERATION_COUNT = 10000 / WAIT_ITERATION_SLEEP;
    public static final String BIND_ADDRESS = "0.0.0.0";
    public static final Integer BIND_PORT = 0;
    public static final String REFERRER = "test-basic-service-host";

    private static final Logger logger = LoggerFactory.getLogger(BasicServiceHost.class);

    @VisibleForTesting
    protected String serviceUri;

    @VisibleForTesting
    protected int waitIterationSleep;

    @VisibleForTesting
    protected int waitIterationCount;

    @VisibleForTesting
    protected String bindAddress;

    @VisibleForTesting
    protected Integer bindPort;

    @VisibleForTesting
    protected String storagePath;

    public BasicServiceHost(String bindAddress, Integer bindPort, String storagePath, String serviceUri,
            int waitIterationSleep, int waitIterationCount) {
        this.bindAddress = bindAddress;
        this.bindPort = bindPort;
        this.storagePath = storagePath;
        this.serviceUri = serviceUri;
        this.waitIterationSleep = waitIterationSleep;
        this.waitIterationCount = waitIterationCount;
    }

    public BasicServiceHost() {
        this(BIND_ADDRESS, BIND_PORT, null, SERVICE_URI, WAIT_ITERATION_SLEEP, WAIT_ITERATION_COUNT);
    }

    public static BasicServiceHost create(String bindAddress, Integer bindPort, String storagePath,
            String serviceUri, int waitIterationSleep, int waitIterationCount) throws Throwable {
        BasicServiceHost host = new BasicServiceHost(bindAddress, bindPort, storagePath, serviceUri,
                waitIterationSleep, waitIterationCount);

        host.initialize();
        host.startWithCoreServices();
        return host;
    }

    public static BasicServiceHost create() throws Throwable {
        BasicServiceHost host = new BasicServiceHost();
        host.initialize();
        host.startWithCoreServices();
        return host;
    }

    public static void destroy(BasicServiceHost host) throws Throwable {
        host.destroy();
    }

    @Override
    public boolean isReady() {
        return super.getState().isStarted;
    }

    @Override
    public Class[] getFactoryServices() {
        return new Class[0];
    }

    protected synchronized void initialize() throws Throwable {

        ServiceHost.Arguments arguments = new ServiceHost.Arguments();
        arguments.port = this.bindPort;
        arguments.bindAddress = this.bindAddress;

        if (StringUtils.isBlank(this.storagePath)) {
            arguments.sandbox = Files.createTempDirectory(null);
        } else {
            arguments.sandbox = Paths.get(this.storagePath);
        }

        super.initialize(arguments);
    }

    protected synchronized BasicServiceHost startWithCoreServices() throws Throwable {
        super.start();
        super.startDefaultCoreServicesSynchronously();
        return this;
    }

    public synchronized void destroy() throws Throwable {
        super.stop();
        File sandbox = new File(this.getStorageSandbox());
        if (sandbox.exists()) {
            FileUtils.forceDelete(sandbox);
        }
    }

    private static String buildPath(Class<? extends Service> type) {
        try {
            Field f = type.getField(FIELD_NAME_SELF_LINK);
            return (String) f.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            Utils.log(Utils.class, Utils.class.getSimpleName(), Level.SEVERE, "%s field not found in class %s: %s",
                    FIELD_NAME_SELF_LINK, type.getSimpleName(), Utils.toString(e));
            throw new IllegalArgumentException(e);
        }
    }

    public void startFactoryServicesSynchronously(Class[] factoryServices) throws Throwable {
        checkNotNull(factoryServices);
        for (Class service : factoryServices) {
            Service instance = (Service) service.newInstance();
            startFactoryServiceSynchronously(instance);
        }
    }

    public Operation startFactoryServiceSynchronously(Service service) throws Throwable {
        String path = buildPath(service.getClass());
        return startFactoryServiceSynchronously(service, path);
    }

    public Operation startFactoryServiceSynchronously(Service service, String path) throws Throwable {
        if (!FactoryService.class.isAssignableFrom(service.getClass())) {
            throw new IllegalArgumentException(
                    "Service " + service.getClass().getName() + " is not FactoryService");
        }

        Operation post = Operation.createPost(UriUtils.buildUri(this, path));

        OperationLatch syncPost = new OperationLatch(post);
        startService(post, service);
        return syncPost.awaitOperationCompletion();
    }

    public Operation startServiceSynchronously(Service service, ServiceDocument body) throws Throwable {
        return startServiceSynchronously(service, body, this.serviceUri);
    }

    public Operation startServiceSynchronously(Service service, ServiceDocument body, String path)
            throws Throwable {
        return startServiceSynchronously(service, body, path, true);
    }

    public Operation startServiceSynchronously(Service service, ServiceDocument body, String path,
            Boolean disableOptions) throws Throwable {

        if (disableOptions) {
            service.toggleOption(Service.ServiceOption.ENFORCE_QUORUM, false);
            service.toggleOption(Service.ServiceOption.OWNER_SELECTION, false);
            service.toggleOption(Service.ServiceOption.REPLICATION, false);
        }

        Operation post = Operation.createPost(UriUtils.buildUri(this, path));
        if (body != null) {
            post.setBody(body);
        }

        OperationLatch syncPost = new OperationLatch(post);
        startService(post, service);
        Operation completedOperation = syncPost.awaitOperationCompletion();
        return OperationUtils.handleCompletedOperation(post, completedOperation);
    }

    public Operation deleteServiceSynchronously() throws Throwable {
        return deleteServiceSynchronously(SERVICE_URI);
    }

    public Operation deleteServiceSynchronously(String path) throws Throwable {

        Operation delete = Operation.createDelete(UriUtils.buildUri(this, path)).setBody("{}")
                .setReferer(UriUtils.buildUri(this, REFERRER));

        OperationLatch syncDelete = new OperationLatch(delete);
        sendRequest(delete);
        return syncDelete.awaitOperationCompletion();
    }

    public Operation sendRequestAndWait(Operation op) throws Throwable {
        return ServiceHostUtils.sendRequestAndWait(this, op, REFERRER);
    }

    public <T> T getServiceState(Class<T> type) throws Throwable {
        return getServiceState(type, this.serviceUri);
    }

    public <T> T getServiceState(Class<T> type, String path) throws Throwable {
        return ServiceHostUtils.getServiceState(this, type, path, "test-basic-service-host");
    }

    /**
     * Wait for the state change.
     *
     * @param type
     * @param <T>
     * @return
     * @throws Throwable
     */
    public <T> T waitForState(Class<T> type, Predicate<T> predicate) throws Throwable {
        return waitForState(this.serviceUri, type, predicate);
    }

    /**
     * Wait for the state change.
     *
     * @param type
     * @param <T>
     * @return
     * @throws Throwable
     */
    public <T> T waitForState(String uri, Class<T> type, Predicate<T> predicate) throws Throwable {
        return ServiceHostUtils.waitForServiceState(type, uri, predicate, this, this.waitIterationSleep,
                this.waitIterationCount, null);
    }

    /**
     * Wait for a query to returns particular information.
     *
     * @param query
     * @param predicate
     * @return
     * @throws Throwable
     */
    public QueryTask waitForQuery(QueryTask query, Predicate<QueryTask> predicate) throws Throwable {
        return ServiceHostUtils.waitForQuery(this, REFERRER, query, predicate, this.waitIterationCount,
                this.waitIterationSleep);
    }
}