class ApplicationLauncher: """A library for starting java application or Java Webstart application and importing remote libraries for operating it. The application is started as a separate process. """ ROBOT_LIBRARY_SCOPE = 'TEST SUITE' def __init__(self, application, timeout='60 seconds', libdir=''): """ApplicationLauncher takes one mandatory and two optional arguments. `application` is a required argument, it is the name of the main class (the class that has the main method) or the url to the Java Webstart jnlp descriptor file. In case the `application` is a jnlp url `libdir` must be provided. `timeout` is the timeout used to wait for importing a remote library. `libdir` is the path to the directory which should contain jars which should contain all the dependencies required for running the tests. In another words these jar files should contain jvmconnector jar and libraries that you want to remotely import (packaged in jars). """ self.application = application self.timeout = timestr_to_secs(timeout or '60') self.libdir = libdir self.builtin = BuiltIn() self.operating_system = OperatingSystem() self.rmi_url = None self._assert_invariants() def start_application(self, args='', jvm_args=''): """Starts the application with given arguments. `args` optional application arguments.. `jvm_args` optional jvm arguments. Example: | Start Application | one two three | -Dproperty=value | """ command = self._create_command(args, jvm_args) self.operating_system.start_process(command) self.application_started() def import_remote_library(self, library_name, *args): """Imports a library with given arguments for the application. Application needs to be started before using this keyword. In case the application is started externally, `Application Started` keyword has to be used beforehand. In case there is multiple applications, there is need to have one ApplicationLauncher per application. In that case, starting application and library imports needs to be in sequence. It is not possible to start multiple applications and then import libraries to those. Examples: | Start Application | arg1 | | Import Remote Library | SwingLibrary | or | Application Started | | Import Remote Library | SwingLibrary | """ library_url = self._run_remote_import(library_name) newargs = self._add_name_to_args_if_necessary(library_name, args) self._prepare_for_reimport_if_necessary(library_url, *newargs) self.builtin.import_library('ApplicationLauncher.RemoteLibrary', library_url, *newargs) def close_application(self): """Closes the active application. If same application is opened multiple times, only the latest one is closed. Therefore you should close the application before starting it again.""" rmi_client = self._connect_to_base_rmi_service() self.rmi_url = None try: rmi_client.getObject().closeService() except RemoteAccessException: return raise RuntimeError('Could not close application.') def application_started(self): """Notifies ApplicationLauncher that application is launched externally. Required before taking libraries into use with `Import Remote Library` when application is started with ApplicationLauncher.py script. """ self.rmi_url = None self._connect_to_base_rmi_service() def _create_command(self, args, jvm_args): if (self._is_jnlp_application()): jnlp = JnlpEnhancer(DATABASE, self.libdir).createRmiEnhancedJnlp(self.application) return 'javaws %s %s' % (jvm_args, jnlp) else: pythonpath = self._get_python_path() out_file, err_file = self._get_output_files() return 'jython -Dpython.path="%s" %s "%s" %s %s 1>%s 2>%s' % (pythonpath, jvm_args, __file__, self.application, args, out_file, err_file) def _is_jnlp_application(self): return self.application.startswith('http') and self.application.endswith('jnlp') def _get_output_files(self): out_file = mktemp('%s.out' % self.application) err_file = mktemp('%s.err' % self.application) return out_file, err_file def _get_python_path(self): for path_entry in sys.path: if path.exists(path.join(path_entry, 'robot')): return path_entry def _add_name_to_args_if_necessary(self, library_name, args): if len(args) >= 2 and args[-2].upper() == 'WITH NAME': return args return sum((args,), ('WITH NAME', library_name)) def _prepare_for_reimport_if_necessary(self, library_url, *args): lib = Importer().import_library('ApplicationLauncher.RemoteLibrary', sum((args,), (library_url,))) testlibs = NAMESPACES.current._testlibs if testlibs.has_key(lib.name): testlibs.pop(lib.name) def _connect_to_base_rmi_service(self): start_time = time.time() while time.time() - start_time < self.timeout: url = self._retrieve_base_rmi_url() try: return self._create_rmi_client(url) except (BeanCreationException, RemoteAccessException, InvalidURLException): time.sleep(2) raise RuntimeError('Could not connect to application %s' % self.application) def _run_remote_import(self, library_name): try: rmi_client = self._connect_to_base_rmi_service() return rmi_client.getObject().importLibrary(library_name) except (BeanCreationException, RemoteAccessException): raise RuntimeError('Could not connect to application %s' % self.application) def _retrieve_base_rmi_url(self): if self.rmi_url: return self.rmi_url return RmiInfoStorage(DATABASE).retrieve() def _create_rmi_client(self, url): if not re.match('rmi://[^:]+:\d{1,5}/.*', url): raise InvalidURLException() rmi_client = RmiProxyFactoryBean(serviceUrl=url, serviceInterface=LibraryImporter) rmi_client.prepare() rmi_client.afterPropertiesSet() self._save_base_url_and_clean_db(url) return rmi_client def _save_base_url_and_clean_db(self, url): self.rmi_url = url if path.exists(DATABASE): remove(DATABASE) def _assert_invariants(self): if self._is_jnlp_application(): self._assert_libdir_is_correct() def _assert_libdir_is_correct(self): if len(self.libdir) == 0: raise RuntimeError('Library directory required for test dependencies.') else: if not path.isdir(self.libdir): raise RuntimeError("Library directory '%s' doesn't exist." % self.libdir)
class ApplicationLauncher: """A library for starting java application or Java Webstart application and importing remote libraries for operating it. The application is started as a separate process. """ ROBOT_LIBRARY_SCOPE = 'TEST SUITE' def __init__(self, application, timeout='60 seconds', libdir=''): """ApplicationLauncher takes one mandatory and two optional arguments. `application` is a required argument, it is the name of the main class (the class that has the main method) or the url to the Java Webstart jnlp descriptor file. In case the `application` is a jnlp url `libdir` must be provided. `timeout` is the timeout used to wait for importing a remote library. `libdir` is the path to the directory which should contain jars which should contain all the dependencies required for running the tests. In another words these jar files should contain jvmconnector jar and libraries that you want to remotely import (packaged in jars). """ self.application = application self.timeout = timestr_to_secs(timeout or '60') self.libdir = libdir self.builtin = BuiltIn() self.operating_system = OperatingSystem() self.rmi_url = None self._assert_invariants() def start_application(self, args='', jvm_args=''): """Starts the application with given arguments. `args` optional application arguments.. `jvm_args` optional jvm arguments. Example: | Start Application | one two three | -Dproperty=value | """ command = self._create_command(args, jvm_args) self.operating_system.start_process(command) self.application_started() def import_remote_library(self, library_name, *args): """Imports a library with given arguments for the application. Application needs to be started before using this keyword. In case the application is started externally, `Application Started` keyword has to be used beforehand. In case there is multiple applications, there is need to have one ApplicationLauncher per application. In that case, starting application and library imports needs to be in sequence. It is not possible to start multiple applications and then import libraries to those. Examples: | Start Application | arg1 | | Import Remote Library | SwingLibrary | or | Application Started | | Import Remote Library | SwingLibrary | """ library_url = self._run_remote_import(library_name) newargs = self._add_name_to_args_if_necessary(library_name, args) self._prepare_for_reimport_if_necessary(library_url, *newargs) self.builtin.import_library('ApplicationLauncher.RemoteLibrary', library_url, *newargs) def close_application(self): """Closes the active application. If same application is opened multiple times, only the latest one is closed. Therefore you should close the application before starting it again.""" rmi_client = self._connect_to_base_rmi_service() self.rmi_url = None try: rmi_client.getObject().closeService() except RemoteAccessException: return raise RuntimeError('Could not close application.') def application_started(self): """Notifies ApplicationLauncher that application is launched externally. Required before taking libraries into use with `Import Remote Library` when application is started with ApplicationLauncher.py script. """ self.rmi_url = None self._connect_to_base_rmi_service() def _create_command(self, args, jvm_args): if (self._is_jnlp_application()): jnlp = JnlpEnhancer(self.libdir).createRmiEnhancedJnlp(self.application) return 'javaws %s %s' % (jvm_args, jnlp) else: pythonpath = self._get_python_path() out_file, err_file = self._get_output_files() return 'jython -Dpython.path="%s" %s "%s" %s %s 1>%s 2>%s' % (pythonpath, jvm_args, __file__, self.application, args, out_file, err_file) def _is_jnlp_application(self): return self.application.startswith('http') or path.isfile(self.application) def _get_output_files(self): out_file = mktemp('%s.out' % self.application) err_file = mktemp('%s.err' % self.application) return out_file, err_file def _get_python_path(self): for path_entry in sys.path: if path.exists(path.join(path_entry, 'robot')): return path_entry def _add_name_to_args_if_necessary(self, library_name, args): if len(args) >= 2 and args[-2].upper() == 'WITH NAME': return args return sum((args,), ('WITH NAME', library_name)) def _prepare_for_reimport_if_necessary(self, library_url, *args): lib = Importer().import_library('ApplicationLauncher.RemoteLibrary', sum((args,), (library_url,))) testlibs = NAMESPACES.current._testlibs if testlibs.has_key(lib.name): testlibs.pop(lib.name) def _connect_to_base_rmi_service(self): start_time = time.time() while time.time() - start_time < self.timeout: url = self._retrieve_base_rmi_url() try: return self._create_rmi_client(url) except (BeanCreationException, RemoteAccessException, InvalidURLException): time.sleep(2) raise RuntimeError('Could not connect to application %s' % self.application) def _run_remote_import(self, library_name): try: rmi_client = self._connect_to_base_rmi_service() return rmi_client.getObject().importLibrary(library_name) except (BeanCreationException, RemoteAccessException): raise RuntimeError('Could not connect to application %s' % self.application) def _retrieve_base_rmi_url(self): if self.rmi_url: return self.rmi_url return RmiInfoStorage(DATABASE).retrieve() def _create_rmi_client(self, url): if not re.match('rmi://[^:]+:\d{1,5}/.*', url): raise InvalidURLException() rmi_client = RmiProxyFactoryBean(serviceUrl=url, serviceInterface=LibraryImporter) rmi_client.prepare() rmi_client.afterPropertiesSet() self._save_base_url_and_clean_db(url) return rmi_client def _save_base_url_and_clean_db(self, url): self.rmi_url = url if path.exists(DATABASE): remove(DATABASE) def _assert_invariants(self): if self._is_jnlp_application(): self._assert_libdir_is_correct() def _assert_libdir_is_correct(self): if len(self.libdir) == 0: raise RuntimeError('Library directory required for test dependencies.') else: if not path.isdir(self.libdir): raise RuntimeError("Library directory '%s' doesn't exist." % self.libdir)
class ApplicationLauncher: """A library for starting java application in separate JVM and importing remote libraries for operating it. """ def __init__(self, application, timeout='60 seconds'): """ApplicationLauncher takes one mandatory and one optional argument. `application` is a required argument, it is the name of the main class or the class that has the main method. `timeout` is the timeout used to wait for importing a remote library. """ self.application = application self.timeout = timestr_to_secs(timeout) self.builtin = BuiltIn() self.operating_system = OperatingSystem() self.rmi_url = None def start_application(self, args='', jvm_args=''): """Starts the application with given arguments. `args` optional application arguments.. `jvm_args` optional jvm arguments. Example: | Start Application | one two three | -Dproperty=value | """ pythonpath = self._get_python_path() command = 'jython -Dpython.path=%s %s %s %s %s' % (pythonpath, jvm_args, __file__, self.application, args) self.operating_system.start_process(command) self.application_started() def import_remote_library(self, library_name, *args): """Imports a library with given arguments for the application. Application needs to be started before using this keyword. In case the application is started externally, `Application Started` keyword has to be used beforehand. In case there is multiple applications, there is need to have one ApplicationLauncher per application. In that case, starting application and library imports needs to be in sequence. It is not possible to start multiple applications and then import libraries to those. Examples: | Start Application | arg1 | | Import Remote Library | SwingLibrary | or | Application Started | | Import Remote Library | SwingLibrary | """ library_url = self._run_remote_import(library_name) newargs = self._add_name_to_args_if_necessary(library_name, args) self._prepare_for_reimport_if_necessary(library_url, *newargs) self.builtin.import_library('ApplicationLauncher.RemoteLibrary', library_url, *newargs) def close_application(self): """Closes the active application. If same application is opened multiple times, only the latest one is closed. Therefore you should close the application before starting it again.""" rmi_client = self._connect_to_base_rmi_service() self.rmi_url = None try: rmi_client.getObject().closeService() except RemoteAccessException: return raise RuntimeError('Could not close application.') def application_started(self): """Notifies ApplicationLauncher that application is launched externally. Required before taking libraries into use with `Import Remote Library` when application is started with ApplicationLauncher.py script. """ self.rmi_url = None self._connect_to_base_rmi_service() def _get_python_path(self): for path_entry in sys.path: if path.exists(path.join(path_entry, 'robot')): return path_entry def _add_name_to_args_if_necessary(self, library_name, args): if len(args) >= 2 and args[-2].upper() == 'WITH NAME': return args return sum((args,), ('WITH NAME', library_name)) def _prepare_for_reimport_if_necessary(self, library_url, *args): lib = Importer().import_library('ApplicationLauncher.RemoteLibrary', sum((args,), (library_url,))) testlibs = NAMESPACES.current._testlibs if testlibs.has_key(lib.name): testlibs.pop(lib.name) def _connect_to_base_rmi_service(self): start_time = time.time() while time.time() - start_time < self.timeout: url = self._retrieve_base_rmi_url() try: return self._create_rmi_client(url) except (BeanCreationException, RemoteAccessException, InvalidURLException): time.sleep(2) raise RuntimeError('Could not connect to application %s' % self.application) def _run_remote_import(self, library_name): try: rmi_client = self._connect_to_base_rmi_service() return rmi_client.getObject().importLibrary(library_name) except (BeanCreationException, RemoteAccessException): raise RuntimeError('Could not connect to application %s' % self.application) def _retrieve_base_rmi_url(self): if self.rmi_url: return self.rmi_url return LibraryDb(DATABASE).retrieve_base_rmi_url() def _create_rmi_client(self, url): if not re.match('rmi://[^:]+:\d{1,5}/.*', url): raise InvalidURLException() rmi_client = RmiProxyFactoryBean(serviceUrl=url, serviceInterface=LibraryImporter) rmi_client.prepare() rmi_client.afterPropertiesSet() self._save_base_url_and_clean_db(url) return rmi_client def _save_base_url_and_clean_db(self, url): self.rmi_url = url if path.exists(DATABASE): remove(DATABASE)