com.github.wasiqb.coteafs.appium.service.AppiumServer.java Source code

Java tutorial

Introduction

Here is the source code for com.github.wasiqb.coteafs.appium.service.AppiumServer.java

Source

/**
 * Copyright (c) 2017, Wasiq Bhamla.
 *
 * 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.github.wasiqb.coteafs.appium.service;

import static com.github.wasiqb.coteafs.appium.checker.ServerChecker.checkServerConfigParams;
import static com.github.wasiqb.coteafs.appium.constants.ConfigKeys.COTEAFS_CONFIG_DEFAULT_FILE;
import static com.github.wasiqb.coteafs.appium.constants.ConfigKeys.COTEAFS_CONFIG_KEY;
import static com.github.wasiqb.coteafs.appium.utils.CapabilityUtils.setCapability;
import static com.github.wasiqb.coteafs.appium.utils.ErrorUtils.fail;
import static io.appium.java_client.service.local.flags.AndroidServerFlag.BOOTSTRAP_PORT_NUMBER;
import static io.appium.java_client.service.local.flags.AndroidServerFlag.CHROME_DRIVER_EXECUTABLE;
import static io.appium.java_client.service.local.flags.AndroidServerFlag.CHROME_DRIVER_PORT;
import static io.appium.java_client.service.local.flags.AndroidServerFlag.SUPPRESS_ADB_KILL_SERVER;
import static io.appium.java_client.service.local.flags.GeneralServerFlag.CALLBACK_ADDRESS;
import static io.appium.java_client.service.local.flags.GeneralServerFlag.CALLBACK_PORT;
import static io.appium.java_client.service.local.flags.GeneralServerFlag.CONFIGURATION_FILE;
import static io.appium.java_client.service.local.flags.GeneralServerFlag.LOCAL_TIMEZONE;
import static io.appium.java_client.service.local.flags.GeneralServerFlag.LOG_LEVEL;
import static io.appium.java_client.service.local.flags.GeneralServerFlag.LOG_TIMESTAMP;
import static io.appium.java_client.service.local.flags.GeneralServerFlag.SESSION_OVERRIDE;
import static io.appium.java_client.service.local.flags.IOSServerFlag.BACK_END_RETRIES;
import static io.appium.java_client.service.local.flags.IOSServerFlag.IPA_ABSOLUTE_PATH;
import static io.appium.java_client.service.local.flags.IOSServerFlag.SAFARI;
import static io.appium.java_client.service.local.flags.IOSServerFlag.WEBKIT_DEBUG_PROXY_PORT;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URL;
import java.nio.file.Files;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.remote.DesiredCapabilities;

import com.github.wasiqb.coteafs.appium.config.AppiumSetting;
import com.github.wasiqb.coteafs.appium.config.ServerArgumentSetting;
import com.github.wasiqb.coteafs.appium.config.ServerSetting;
import com.github.wasiqb.coteafs.appium.config.android.AndroidArgumentSetting;
import com.github.wasiqb.coteafs.appium.config.ios.IOSArgumentSetting;
import com.github.wasiqb.coteafs.appium.error.AppiumServerAlreadyRunningError;
import com.github.wasiqb.coteafs.appium.error.AppiumServerLogFileError;
import com.github.wasiqb.coteafs.appium.error.AppiumServerNotRunningError;
import com.github.wasiqb.coteafs.appium.error.AppiumServerNotStartingError;
import com.github.wasiqb.coteafs.appium.error.AppiumServerNotStoppingError;
import com.github.wasiqb.coteafs.config.loader.ConfigLoader;

import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import io.appium.java_client.service.local.flags.ServerArgument;

/**
 * @author wasiq.bhamla
 * @since 12-Apr-2017 5:17:22 PM
 */
public final class AppiumServer {
    private static final Logger log = LogManager.getLogger(AppiumServer.class);

    private AppiumServiceBuilder builder;
    private DesiredCapabilities capabilities;
    private AppiumDriverLocalService service;
    private final ServerSetting setting;

    /**
     * @author wasiq.bhamla
     * @param name
     * @since 13-Apr-2017 7:33:24 PM
     */
    public AppiumServer(final String name) {
        this.setting = ConfigLoader.settings().withKey(COTEAFS_CONFIG_KEY).withDefault(COTEAFS_CONFIG_DEFAULT_FILE)
                .load(AppiumSetting.class).getServer(name);
        if (!this.setting.isExternal() && !this.setting.isCloud()) {
            initService();
            buildCapabilities();
            buildService();
        }
    }

    /**
     * @author wasiq.bhamla
     * @since 13-Apr-2017 3:28:14 PM
     * @return url
     */
    public URL getServiceUrl() {
        log.trace("Fetching Appium Service URL...");
        if (!this.setting.isExternal() && !this.setting.isCloud())
            return this.service.getUrl();
        final String url = String.format("%s/wd/hub", getUrl());
        try {
            return new URL(url);
        } catch (final MalformedURLException e) {
            log.error("Error occurred while getting service url...");
            log.catching(e);
        }
        return null;
    }

    /**
     * @author wasiq.bhamla
     * @since 13-Apr-2017 5:30:12 PM
     * @return isRunning
     */
    public boolean isRunning() {
        if (this.setting.isCloud())
            return true;
        if (!this.setting.isExternal()) {
            log.trace("Checking if Appium Service is running...");
            return this.service.isRunning();
        }
        final SocketAddress addr = new InetSocketAddress(this.setting.getHost(), this.setting.getPort());
        try (Socket socket = new Socket()) {
            socket.connect(addr, 2000);
        } catch (final IOException e) {
            fail(AppiumServerNotRunningError.class, "Error connecting to Server...", e);
        }
        return true;
    }

    /**
     * @author wasiq.bhamla
     * @since 12-Apr-2017 5:23:19 PM
     */
    public void start() {
        log.trace("Starting Appium Service...");
        if (!this.setting.isExternal() && !this.setting.isCloud()) {
            this.service = AppiumDriverLocalService.buildService(this.builder);
            try {
                this.service.start();
            } catch (final AppiumServerHasNotBeenStartedLocallyException e) {
                fail(AppiumServerNotStartingError.class, "Error occured while starting Appium server", e);
            } catch (final Exception e) {
                fail(AppiumServerAlreadyRunningError.class, "Appium server is running already.", e);
            }
            log.trace("Appium Service Started...");
        } else {
            if (isRunning()) {
                log.trace("Appium Service is already running...");
            }
        }
    }

    /**
     * @author wasiq.bhamla
     * @since 12-Apr-2017 5:23:39 PM
     */
    public void stop() {
        log.trace("Trying to stop Appium Service...");
        if (!this.setting.isExternal() && !this.setting.isCloud()) {
            try {
                this.service.stop();
            } catch (final Exception e) {
                fail(AppiumServerNotStoppingError.class, "Error occured while stopping the server.", e);
            }
            this.service = null;
            log.trace("Appium Service Stopped...");
        } else {
            log.trace("Appium Service can only be stopped from the tool you started with...");
        }
    }

    /**
     * @author wasiq.bhamla
     * @since 12-Apr-2017 9:29:17 PM
     */
    private void buildCapabilities() {
        log.trace("Building Appium Capabilities started...");
        setCapability(MobileCapabilityType.NO_RESET, Boolean.toString(this.setting.isNoReset()), this.capabilities);
        setCapability(MobileCapabilityType.FULL_RESET, Boolean.toString(this.setting.isFullReset()),
                this.capabilities);
        setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, Integer.toString(this.setting.getSessionTimeout()),
                this.capabilities);
        log.trace("Building Appium Capabilities completed...");
    }

    private void buildService() {
        log.trace("Building Appium Service started...");
        checkServerConfigParams("IP Host Address", this.setting.getHost());
        this.builder = this.builder.withIPAddress(this.setting.getHost())
                .withStartUpTimeOut(this.setting.getStartUpTimeOutSeconds(), TimeUnit.SECONDS);
        setPort();
        setLogFile();
        setAppiumJS();
        setNodeExe();
        setCapabilities();
        setArguments();
        setEnvironmentVariables();
        log.trace("Building Appium Service done...");
    }

    private String getUrl() {
        final StringBuilder sb = new StringBuilder(this.setting.getProtocol().getName()).append("://");
        if (this.setting.isCloud()) {
            checkServerConfigParams("User Name", this.setting.getUserName());
            checkServerConfigParams("Password", this.setting.getPassword());
            sb.append(this.setting.getUserName()).append(":").append(this.setting.getPassword()).append("@")
                    .append(this.setting.getHost());
        } else {
            sb.append(this.setting.getHost());
        }
        if (this.setting.getPort() > 0) {
            sb.append(":").append(this.setting.getPort());
        }
        return sb.toString();
    }

    private void initService() {
        log.trace("Initializing Appium Service started...");
        this.builder = new AppiumServiceBuilder();
        this.capabilities = new DesiredCapabilities();
        log.trace("Initializing Appium Service done...");
    }

    /**
     * @author wasiq.bhamla
     * @since Oct 27, 2017 12:39:17 PM
     */
    private void setAppiumJS() {
        if (this.setting.getAppiumJsPath() != null) {
            final File appJs = new File(this.setting.getAppiumJsPath());
            this.builder = this.builder.withAppiumJS(appJs);
        }
    }

    private void setArgument(final ServerArgument flag, final boolean value) {
        if (value) {
            this.builder = this.builder.withArgument(flag);
        }
    }

    private void setArgument(final ServerArgument flag, final int value) {
        if (value > 0) {
            this.builder = this.builder.withArgument(flag, Integer.toString(value));
        }
    }

    /**
     * @author wasiq.bhamla
     * @since Oct 27, 2017 3:15:05 PM
     * @param logLevel
     * @param level
     */
    private void setArgument(final ServerArgument flag, final String value) {
        if (StringUtils.isNoneEmpty(value)) {
            this.builder = this.builder.withArgument(flag, value);
        }
    }

    /**
     * @author wasiq.bhamla
     * @since Oct 27, 2017 12:43:53 PM
     */
    private void setArguments() {
        final ServerArgumentSetting args = this.setting.getArguments();
        final IOSArgumentSetting ios = args.getIos();
        final AndroidArgumentSetting android = args.getAndroid();

        if (ios != null) {
            setArgument(BACK_END_RETRIES, ios.getBackendRetries());
            setArgument(IPA_ABSOLUTE_PATH, ios.getIpaAbsolutePath());
            setArgument(SAFARI, ios.isSafari());
            setArgument(WEBKIT_DEBUG_PROXY_PORT, ios.getWebkitDebugProxyPort());
        }
        if (android != null) {
            setArgument(BOOTSTRAP_PORT_NUMBER, android.getBootstrapPort());
            setArgument(CHROME_DRIVER_PORT, android.getChromeDriverPort());
            setArgument(CHROME_DRIVER_EXECUTABLE, android.getChromeDriverExePath());
            setArgument(SUPPRESS_ADB_KILL_SERVER, android.isSuppressAdbKillServer());
        }
        setArgument(LOG_LEVEL, args.getLogLevel().toString());
        setArgument(SESSION_OVERRIDE, args.isSessionOverride());
        setArgument(LOG_TIMESTAMP, args.isLogTimeStamp());
        setArgument(LOCAL_TIMEZONE, args.isLocalTimeZone());
        setArgument(CONFIGURATION_FILE, args.getNodeConfigFile());
        setArgument(CALLBACK_ADDRESS, args.getCallbackIp());
        setArgument(CALLBACK_PORT, args.getCallbackPort());
    }

    /**
     * @author wasiq.bhamla
     * @since Oct 27, 2017 12:40:55 PM
     */
    private void setCapabilities() {
        this.builder = this.builder.withCapabilities(this.capabilities);
    }

    /**
     * @author wasiq.bhamla
     * @since Oct 27, 2017 1:10:26 PM
     */
    private void setEnvironmentVariables() {
        this.builder = this.builder.withEnvironment(this.setting.getEnvironmentVariables());
    }

    /**
     * @author wasiq.bhamla
     * @since Oct 27, 2017 3:00:49 PM
     */
    private void setLogFile() {
        final String logFilePath = this.setting.getLogFilePath();
        if (logFilePath != null) {
            final File logFile = new File(logFilePath);
            try {
                if (logFile.exists()) {
                    Files.delete(logFile.toPath());
                }
            } catch (final IOException e) {
                fail(AppiumServerLogFileError.class, "Error while deleting log file!", e);
            }
            this.builder = this.builder.withLogFile(logFile);
        }
    }

    private void setNodeExe() {
        if (this.setting.getNodePath() != null) {
            final File nde = new File(this.setting.getNodePath());
            this.builder = this.builder.usingDriverExecutable(nde);
        }
    }

    /**
     * @author wasiq.bhamla
     * @since Oct 27, 2017 12:42:30 PM
     */
    private void setPort() {
        if (this.setting.getPort() > 0) {
            this.builder = this.builder.usingPort(this.setting.getPort());
        } else {
            this.builder = this.builder.usingAnyFreePort();
        }
    }
}