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

omelet.browserstack.support.BrowserStackTunnel Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * 	Copyright 2014 Springer Science+Business Media Deutschland GmbH
 * 	
 * 	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 omelet.browserstack.support;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import omelet.common.OSName;
import omelet.common.OSName.OSN;
import omelet.common.Utils;

import org.apache.log4j.Logger;

/**
 * For Setting and terminating BrowserStack Tunnel
 * 
 * @author kapilA
 *
 */
public class BrowserStackTunnel {

	private static Set activeTunnels = Collections
			.synchronizedSet(new HashSet());
	private static BrowserStackTunnel browserStackTunnel;
	private static final Logger LOGGER = Logger
			.getLogger(BrowserStackTunnel.class);
	private static OSN environment;
	private Process tunnelProcess;
	private InputStream is;
	private BufferedReader br;
	private ProcessBuilder pb;
	private String tunnelIdentifier = UUID.randomUUID().toString();

	String browserStackKey;
	List browserStackURLS;

	// Hiding the constructor for Singleton
	private BrowserStackTunnel() {
	}

	public static BrowserStackTunnel getInstance() {
		if (browserStackTunnel == null) {
			synchronized (BrowserStackTunnel.class) {
				if (browserStackTunnel == null) {
					browserStackTunnel = new BrowserStackTunnel();
				}
			}
		}
		environment = OSName.get();	
		return browserStackTunnel;
	}

	/***
	 * Return the List of the keys present for termination
	 * 
	 * @return
	 */
	public List getOpenTunnelKeys() {
		List returnKeys = new ArrayList();
		for (String s : activeTunnels) {
			returnKeys.add(s);
		}
		return returnKeys;
	}

	/***
	 * Set ups the tunnel for the Keys
	 * 
	 * @param browserStackKey
	 * @param browserStackURLS
	 */
	public void createTunnel(String browserStackKey,
			List browserStackURLS) {
		this.browserStackKey = browserStackKey;
		this.browserStackURLS = browserStackURLS;

		if (!activeTunnels.contains(browserStackKey)) {
			synchronized (browserStackTunnel) {
				if (!activeTunnels.contains(browserStackKey)) {
					LOGGER.info("Starting tunnel for Key:" + browserStackKey);
					pb = new ProcessBuilder();

					pb.command(getSetUpCommand(browserStackKey,
							browserStackURLS));
					try {
						tunnelProcess = pb.start();
						waitforTunnelTobeUp("Press Ctrl-C to exit");
						activeTunnels.add(browserStackKey);
					} catch (IOException e) {
						LOGGER.error(e);
					} catch (InterruptedException e) {
						LOGGER.error(e);
					}
				} else {
					LOGGER.info("Tunnel Already exsist for they key:"
							+ browserStackKey);
				}
			}
		} else {
			LOGGER.info("Tunnel Already exsist for key:" + browserStackKey);
		}
	}

	/***
	 * wait for tunnel to be up
	 * 
	 * @param waitForMessage
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private void waitforTunnelTobeUp(String waitForMessage) throws IOException,
			InterruptedException {
		is = tunnelProcess.getInputStream();
		br = new BufferedReader(new InputStreamReader(is));
		String t = "";
		while (!waitForMessage.equalsIgnoreCase(t) && t != null) {
			try {
				t = br.readLine();
				// if(t == null) {
				// createTunnel(browserStackKey, browserStackURLS);
				// }
				LOGGER.info("cmd Output:" + t);
			} catch (IOException e) {
				LOGGER.error(e);
			}
		}
	}

	/***
	 * Terminate tunnel
	 * 
	 * @param browserStackKey
	 */
	public void terminateTunnel(String browserStackKey) {
		// Check if it is present in the Hash Set
		// if not , remove from the set
		if (isTunnelPresent(browserStackKey)) {
			LOGGER.debug("Starting termination of Tunnel for key:"
					+ browserStackKey);
			KillTunnel kbs = this.new KillTunnel(browserStackKey);
			kbs.kill();
			LOGGER.info("Killing BrowserStack tunnel for Key:"
					+ browserStackKey);
		} else {
			LOGGER.info("Tunnel Already Terminated for the key:"
					+ browserStackKey);
		}
	}

	/***
	 * Check if key entry there in Set yes remove and return true for killing
	 * else false
	 * 
	 * @param browserStackKey
	 * @return
	 */
	private boolean isTunnelPresent(String browserStackKey) {
		if (activeTunnels.contains(browserStackKey)) {
			synchronized (browserStackTunnel) {
				if (activeTunnels.contains(browserStackKey)) {
					activeTunnels.remove(browserStackKey);
					return true;
				} else {
					return false;
				}
			}
		}
		return false;
	}

	/***
	 * Return the set up command for setting the browserstack tunnel
	 * 
	 * @param browserStackKey
	 * @param bsURLS
	 * @return
	 */
	private List getSetUpCommand(String browserStackKey,
			List bsURLS) {
		List command = new ArrayList();
		StringBuilder urls = new StringBuilder();
		for (String s : bsURLS) {
			if (!s.contains(",")) {
				urls.append(s);
				urls.append(",80,0,");
				urls.append(s);
				urls.append(",443,1,");
			} else {
				urls.append(s);
				urls.append(",");
			}
		}

		urls.deleteCharAt(urls.length() - 1);
		switch (environment) {
		case UNIX:
			command.add(Utils.getResources(this, "BrowserStackLocal"));
			
			break;
		case WIN:
			command.add("cmd");
			command.add("/c");
			command.add('"' + Utils.getResources(this, "BrowserStackLocal.exe") + '"');
			break;
		case MAC:
			command.add(Utils.getResources(this, "BrowserStackLocal"));
			break;
		default:
			break;
		}
		command.add(browserStackKey);
		command.add(urls.toString());
		command.add("-force");
		command.add("-tunnelIdentifier");
		command.add(tunnelIdentifier);
		return command;
	}
	
	public String getTunnelIdentifier(){
		return tunnelIdentifier;
	}

	/***
	 * @author kapilA
	 * 
	 */
	private class KillTunnel {
		// As of now key is not required because process name is taken and then
		// killed
		// Expectation is that there should be only one BrowserStackLocal task
		// running
		String browserStackKey;

		public KillTunnel(String browserStackKey) {
			this.browserStackKey = browserStackKey;
		}

		/***
		 * Kills the tunnel
		 */
		public void kill() {
			Process killProcess = null;
			ProcessBuilder killpb = new ProcessBuilder();
			killpb.command(getKillCommand());
			try {
				killProcess = killpb.start();
				killProcess.waitFor();
			} catch (IOException e) {
				LOGGER.error("Kill process for BrowserStack Tunnel having key: "
						+ browserStackKey + " failed to start. " + e);
			} catch (InterruptedException e) {
				LOGGER.error("Kill process for BrowserStack Tunnel having key: "
						+ browserStackKey + " failed to start. " + e);
			} finally {
				if (killProcess != null) {
					killProcess.destroy();
				}
			}
		}

		private List getKillCommand() {
			List killCommand = new ArrayList();
			switch (environment) {
			case UNIX:
				killCommand.add("pkill");
				killCommand.add("-f");
				killCommand.add("BrowserStackLocal");
				break;
			case WIN:
				killCommand.add("taskkill");
				killCommand.add("/F");
				killCommand.add("/IM");
				killCommand.add("BrowserStackLocal.exe");
				break;
			case MAC:
				killCommand.add("pkill");
				killCommand.add("-f");
				killCommand.add("BrowserStackLocal");
				break;
			default:
				break;
			}
			return killCommand;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy