1 /* ServerAccess.java
2 Copyright (C) 2011, 2012 Red Hat, Inc.
3 
4 This file is part of IcedTea.
5 
6 IcedTea is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 2.
9 
10 IcedTea is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with IcedTea; see the file COPYING.  If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301 USA.
19 
20 Linking this library statically or dynamically with other modules is
21 making a combined work based on this library.  Thus, the terms and
22 conditions of the GNU General Public License cover the whole
23 combination.
24 
25 As a special exception, the copyright holders of this library give you
26 permission to link this library with independent modules to produce an
27 executable, regardless of the license terms of these independent
28 modules, and to copy and distribute the resulting executable under
29 terms of your choice, provided that you also meet, for each linked
30 independent module, the terms and conditions of the license of that
31 module.  An independent module is a module which is not derived from
32 or based on this library.  If you modify this library, you may extend
33 this exception to your version of the library, but you are not
34 obligated to do so.  If you do not wish to do so, delete this
35 exception statement from your version.
36  */
37 package net.sourceforge.jnlp;
38 
39 import java.io.ByteArrayOutputStream;
40 import java.io.File;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.net.HttpURLConnection;
44 import java.net.MalformedURLException;
45 import java.net.ServerSocket;
46 import java.net.URL;
47 import java.net.URLConnection;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.List;
51 import net.sourceforge.jnlp.browsertesting.Browser;
52 import net.sourceforge.jnlp.browsertesting.BrowserFactory;
53 import net.sourceforge.jnlp.browsertesting.Browsers;
54 import net.sourceforge.jnlp.closinglisteners.AutoErrorClosingListener;
55 import net.sourceforge.jnlp.closinglisteners.AutoOkClosingListener;
56 import net.sourceforge.jnlp.util.FileUtils;
57 import net.sourceforge.jnlp.util.logging.OutputController;
58 
59 /**
60  *
61  * This class provides access to virtual server and stuff around.
62  * It can find unoccupied port, start server, provides its singleton instantiation, launch parallel instantiations,
63  * read location of installed (tested javaws) see javaws.build.bin java property,
64  * location of server www root on file system (see test.server.dir java property),
65  * stubs for launching javaws and for locating resources and read resources.
66  *
67  * It can also execute processes with timeout (@see PROCESS_TIMEOUT) (used during launching javaws)
68  * Some protected apis are exported because public classes in this package are put to be tested by makefile.
69  *
70  * There are included test cases which show some basic usages.
71  *
72  *
73  */
74 public class ServerAccess {
75 
76     public static enum AutoClose {
77 
78         CLOSE_ON_EXCEPTION, CLOSE_ON_CORRECT_END, CLOSE_ON_BOTH
79     }
80 
81     public static final long NANO_TIME_DELIMITER=1000000l;
82     /**
83      * java property which value containing path to default (makefile by) directory with deployed resources
84      */
85     public static final String TEST_SERVER_DIR = "test.server.dir";
86     /**
87      * java property which value containing path to installed (makefile by) javaws binary
88      */
89     public static final String JAVAWS_BUILD_BIN = "javaws.build.bin";
90     /** property to set the different then default browser
91      */
92     public static final String USED_BROWSERS = "used.browsers";
93     public static final String DEFAULT_LOCALHOST_NAME = "localhost";
94     /**
95      * server instance singleton
96      */
97     private static ServerLauncher server;
98     /**
99      * inner version of engine
100      */
101     private static final String version = "5";
102     /**
103      * timeout to read 'remote' resources
104      * This can be changed in runtime, but will affect all following tasks
105      */
106     public static int READ_TIMEOUT = 1000;
107     /**
108      * timeout in ms to let process to finish, before assassin will kill it.
109      * This can be changed in runtime, but will affect all following tasks
110      */
111     public static long PROCESS_TIMEOUT = 10 * 1000;//ms
112     /**
113      * this flag is indicating whether output of executeProcess should be logged. By default true.
114      */
115     public static boolean PROCESS_LOG = true;
116     public static boolean LOGS_REPRINT = false;
117 
118     private Browser currentBrowser;
119     public static final String UNSET_BROWSER="unset_browser";
120 
121     /**
122      * main method of this class prints out random free port
123      * or runs server
124      * param "port" prints out the port
125      * nothing or number will run server on random(or on number specified)
126      * port in -Dtest.server.dir
127      * @param args params from commandline. recognized params are port and randomport
128      * @throws java.lang.Exception if anything happens
129      */
main(String[] args)130     public static void main(String[] args) throws Exception {
131         if (args.length > 0 && args[0].equalsIgnoreCase("port")) {
132             int i = findFreePort();
133             System.out.println(i);
134             System.exit(0);
135         } else {
136             int port = 44321;
137             if (args.length > 0 && args[0].equalsIgnoreCase("randomport")) {
138                 port = findFreePort();
139             } else if (args.length > 0) {
140                 port = new Integer(args[0]);
141             }
142             getIndependentInstance(port);
143             while (true) {
144                 Thread.sleep(1000);
145             }
146 
147         }
148     }
149 
150     /**
151      * utility method to find random free port
152      *
153      * @return - found random free port
154      * @throws IOException - if socket can't be opened or no free port exists
155      */
findFreePort()156     public static int findFreePort()
157             throws IOException {
158         ServerSocket findPortTestingSocket = new ServerSocket(0);
159         int port = findPortTestingSocket.getLocalPort();
160         findPortTestingSocket.close();
161         return port;
162     }
163     public static final  String HEADLES_OPTION=OptionsDefinitions.OPTIONS.HEADLESS.option;
164     public static final  String VERBOSE_OPTION=OptionsDefinitions.OPTIONS.VERBOSE.option;
165 
166     /**
167      * we would like to have an singleton instance ASAP
168      */
ServerAccess()169     public ServerAccess() {
170 
171         getInstance();
172 
173 
174     }
175 
176     /**
177      *
178      * @return cached instance. If none, then creates new
179      */
getInstance()180     public static ServerLauncher getInstance() {
181         if (server == null) {
182             server = getIndependentInstance();
183         }
184         return server;
185     }
186 
187     /**
188      *
189      * @return new not cached iserver instance on random port,
190      * useful for testing application loading from different url then base
191      */
getIndependentInstance()192     public static ServerLauncher getIndependentInstance() {
193         return getIndependentInstance(true);
194     }
getIndependentInstance(boolean daemon)195     public static ServerLauncher getIndependentInstance(boolean daemon) {
196         String dir = (System.getProperty(TEST_SERVER_DIR));
197         try{
198             return getIndependentInstance(dir, findFreePort(),daemon);
199         }catch (Exception ex){
200             throw  new RuntimeException(ex);
201         }
202     }
203 
204 
205     /**
206      *
207      * @param port specific port on which this server is accepting requests
208      * @return new not cached iserver instance on random port,
209      * useful for testing application loading from different url then base
210      */
211 
getIndependentInstance(int port)212     public static ServerLauncher getIndependentInstance(int port) {
213         return getIndependentInstance(port, true);
214     }
getIndependentInstance(int port,boolean daemon)215     public static ServerLauncher getIndependentInstance(int port,boolean daemon) {
216         String dir = (System.getProperty(TEST_SERVER_DIR));
217         return getIndependentInstance(dir,port,daemon);
218     }
219 
220     /**
221      *
222      * @param dir directory from which server returns resources
223      * @param port specific port on which this server is accepting requests
224      * @return new not cached iserver instance on random port upon custom www root directory,
225      * useful for testing application loading from different url then base
226      */
227 
getIndependentInstance(String dir, int port)228     public static ServerLauncher getIndependentInstance(String dir, int port) {
229         return getIndependentInstance(dir, port, true);
230     }
231 
getIndependentInstance(String dir)232     public static ServerLauncher getIndependentInstance(String dir) throws IOException {
233         return getIndependentInstance(dir, findFreePort(), true);
234     }
235 
getIndependentInstanceOnTmpDir()236     public static ServerLauncher getIndependentInstanceOnTmpDir() throws IOException {
237         File f = File.createTempFile("itwReproducers_", "_anotherDeployDir");
238         f.delete();
239         f.mkdir();
240         f.deleteOnExit();
241         return getIndependentInstance(f.getAbsolutePath(), findFreePort(), true);
242     }
243 
getIndependentInstance(String dir, int port, boolean daemon)244     public static ServerLauncher getIndependentInstance(String dir, int port, boolean daemon) {
245 
246 
247         if (dir == null || dir.trim().length() == 0 || !new File(dir).exists() || !new File(dir).isDirectory()) {
248             throw new RuntimeException("test.server.dir property must be set to valid directory!");
249         }
250         try {
251             ServerLauncher lServerLuncher = new ServerLauncher(port, new File(dir));
252             Thread r=new Thread(lServerLuncher);
253             r.setDaemon(daemon);
254             r.start();
255             return lServerLuncher;
256         } catch (Exception ex) {
257             throw new RuntimeException(ex);
258         }
259 
260     }
261 
262     /**
263      *
264      * @return - value passed inside as javaws binary location. See JAVAWS_BUILD_BIN
265      */
getJavawsLocation()266     public String getJavawsLocation() {
267         return System.getProperty(JAVAWS_BUILD_BIN);
268     }
269 
270       /**
271      *
272      * @return - bianry from where to lunch current browser
273      */
getBrowserLocation()274     public String getBrowserLocation() {
275        if (this.currentBrowser==null) return UNSET_BROWSER;
276        return this.currentBrowser.getBin();
277     }
278 
getBrowserParams()279     public List<String> getBrowserParams() {
280        if (this.currentBrowser==null) return null;
281        List<String> l1=this.currentBrowser.getComaptibilitySwitches();
282        List<String> l2=this.currentBrowser.getDefaultSwitches();
283        List<String> l= new ArrayList<>();
284        if (l1!=null)l.addAll(l1);
285        if (l2!=null)l.addAll(l2);
286        return l;
287 
288     }
289 
getCurrentBrowsers()290     public Browsers getCurrentBrowsers() {
291         if (currentBrowser==null) return null;
292         return currentBrowser.getID();
293     }
getCurrentBrowser()294     public Browser getCurrentBrowser() {
295         return currentBrowser;
296     }
297 
setCurrentBrowser(Browsers currentBrowser)298     public void setCurrentBrowser(Browsers currentBrowser) {
299         this.currentBrowser = BrowserFactory.getFactory().getBrowser(currentBrowser);
300         if (this.currentBrowser == null) {
301            LoggingBottleneck.getDefaultLoggingBottleneck().setLoggedBrowser(UNSET_BROWSER);
302         } else {
303             LoggingBottleneck.getDefaultLoggingBottleneck().setLoggedBrowser(this.currentBrowser.getID().toString());
304         }
305     }
306 
setCurrentBrowser(Browser currentBrowser)307     public void setCurrentBrowser(Browser currentBrowser) {
308         this.currentBrowser = currentBrowser;
309         if (this.currentBrowser == null) {
310             LoggingBottleneck.getDefaultLoggingBottleneck().setLoggedBrowser(UNSET_BROWSER);
311         } else {
312             LoggingBottleneck.getDefaultLoggingBottleneck().setLoggedBrowser(this.currentBrowser.getID().toString());
313         }
314     }
315 
316 
317 
318     /**
319      *
320      * @return - value passed inside as javaws binary location as file. See JAVAWS_BUILD_BIN
321      */
getJavawsFile()322     public File getJavawsFile() {
323         return new File(System.getProperty(JAVAWS_BUILD_BIN));
324     }
325 
326     /**
327      *
328      * @return port on which is running cached server. If non singleton instance is running, new is created.
329      */
getPort()330     public int getPort() {
331         if (server == null) {
332             getInstance();
333         }
334         //if (!server.isRunning()) throw new RuntimeException("Server mysteriously died");
335         return server.getPort();
336 
337     }
338 
339     /**
340      *
341      * @return directory upon which is running cached server. If non singleton instance is running, new is created.
342      */
getDir()343     public File getDir() {
344         if (server == null) {
345             getInstance();
346         }
347         // if (!server.isRunning()) throw new RuntimeException("Server mysteriously died");
348         return server.getDir();
349     }
350 
351     /**
352      *
353      * @throws java.net.MalformedURLException if url for this resource can not be constructed
354      * @return complete url for this resource on this server
355      * @param resource relative path  pointing to server resource. If non singleton instance is running, new is created.
356      */
getUrl(String resource)357     public URL getUrl(String resource) throws MalformedURLException {
358         if (server == null) {
359             getInstance();
360         }
361         //if (!server.isRunning()) throw new RuntimeException("Server mysteriously died");
362         return server.getUrl(resource);
363     }
364 
365     /**
366      *
367      * @return url pointing to cached server . If non singleton instance is running, new is created.
368      * @throws java.net.MalformedURLException
369      */
getUrl()370     public URL getUrl() throws MalformedURLException {
371         return getUrl("");
372 
373     }
374 
375     /**
376      *
377      * @return whether cached server is alive. If non singleton instance is running, new is created.
378      */
isRunning()379     public boolean isRunning() {
380         if (server == null) {
381             getInstance();
382         }
383         //if (!server.isRunning()) throw new RuntimeException("Server mysteriously died");
384         return server.isRunning();
385 
386     }
387 
388     /**
389      * Return resource from cached server
390      *
391      * @param resource to be located on cached server
392      * @return individual bytes of resource
393      * @throws IOException if connection can't be established or resource does not exist
394      */
getResourceAsBytes(String resource)395     public ByteArrayOutputStream getResourceAsBytes(String resource) throws IOException {
396         return getResourceAsBytes(getUrl(resource));
397     }
398 
399     /**
400      * Return resource from cached server
401      *
402      * @param resource to be located on cached server
403      * @return string constructed from  resource
404      * @throws IOException if connection can't be established or resource does not exist
405      */
getResourceAsString(String resource)406     public String getResourceAsString(String resource) throws IOException {
407         return getResourceAsString(getUrl(resource));
408     }
409 
410     /**
411      * utility method which can read bytes of any stream
412      *
413      * @param is stream to be read
414      * @return individual bytes of resource
415      * @throws IOException if connection can't be established or resource does not exist
416      */
getBytesFromStream(InputStream is)417     public static ByteArrayOutputStream getBytesFromStream(InputStream is) throws IOException {
418         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
419         int nRead;
420         byte[] data = new byte[16384];
421         while ((nRead = is.read(data, 0, data.length)) != -1) {
422             buffer.write(data, 0, nRead);
423         }
424         buffer.flush();
425         return buffer;
426     }
427 
428     /**
429      * utility method which can read from any stream as one long String
430      *
431      * @param is stream to be read
432      * @param encoding encoding of this stream
433      * @return stream as string
434      * @throws IOException if connection can't be established or resource does not exist
435      */
getContentOfStream(InputStream is, String encoding)436     public static String getContentOfStream(InputStream is, String encoding) throws IOException {
437         return FileUtils.getContentOfStream(is, encoding);
438     }
439 
440     /**
441      * utility method which can read from any stream as one long String
442      *
443      * @param is input stream to read from
444      * @return stream as string
445      * @throws IOException if connection can't be established or resource does not exist
446      */
getContentOfStream(InputStream is)447     public static String getContentOfStream(InputStream is) throws IOException {
448         return FileUtils.getContentOfStream(is);
449     }
450 
451     /**
452      * utility method which can read bytes of resource from any url
453      *
454      * @param u full url to read from
455      * @return individual bytes of resource
456      * @throws IOException if connection can't be established or resource does not exist
457      */
getResourceAsBytes(URL u)458     public static ByteArrayOutputStream getResourceAsBytes(URL u) throws IOException {
459         URLConnection connection = null;
460         try {
461             connection = u.openConnection();
462             if (connection instanceof HttpURLConnection) {
463                 ((HttpURLConnection) connection).setRequestMethod("GET");
464             }
465             connection.setDoOutput(true);
466             connection.setReadTimeout(READ_TIMEOUT);
467             connection.connect();
468             return getBytesFromStream(connection.getInputStream());
469         } finally {
470             if (connection != null && connection instanceof HttpURLConnection) {
471                 ((HttpURLConnection) connection).disconnect();
472             }
473         }
474 
475     }
476 
477     /**
478      * utility method which can read string of resource from any url
479      *
480      * @param u full url to read from
481      * @return resource as string
482      * @throws IOException if connection can't be established or resource does
483      * not exist
484      */
getResourceAsString(URL u)485     public static String getResourceAsString(URL u) throws IOException {
486         URLConnection connection = null;
487         try {
488             connection = (HttpURLConnection) u.openConnection();
489             if (connection instanceof HttpURLConnection) {
490                 ((HttpURLConnection) connection).setRequestMethod("GET");
491             }
492             connection.setDoOutput(true);
493             connection.setReadTimeout(READ_TIMEOUT);
494             connection.connect();
495             return getContentOfStream(connection.getInputStream());
496         } finally {
497             if (connection != null && connection instanceof HttpURLConnection) {
498                 ((HttpURLConnection) connection).disconnect();
499             }
500         }
501     }
502 
503     /**
504      * helping dummy  method to save String as file in UTF-8 encoding.
505      *
506      * @param content which will be saved as it is saved in this String
507      * @param f file to be saved. No warnings provided
508      * @throws IOException
509      */
saveFile(String content, File f)510     public static void saveFile(String content, File f) throws IOException {
511         FileUtils.saveFile(content, f);
512     }
513 
514     /**
515      * helping dummy  method to save String as file in specified encoding/.
516      *
517      * @param content which will be saved as it is saved in this String
518      * @param f file to be saved. No warnings provided
519      * @param encoding of output byte representation
520      * @throws IOException
521      */
saveFile(String content, File f,String encoding)522     public static void saveFile(String content, File f,String encoding) throws IOException {
523         FileUtils.saveFile(content, f, encoding);
524     }
525 
526     /**
527      * wrapping method to executeProcess (eg: javaws -headless http://localhost:port/resource)
528      * will execute default javaws (@see JAVAWS_BUILD_BIN) upon default url upon cached server (@see SERVER_NAME @see getPort(), @see getInstance())
529      * with parameter -headless (no gui, no asking)
530      * @param resource  name of resource
531      * @return result what left after running this process
532      * @throws Exception
533      */
executeJavawsHeadless(String resource)534     public ProcessResult executeJavawsHeadless(String resource) throws Exception {
535         return executeJavawsHeadless(null, resource);
536     }
executeJavawsHeadless(String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl)537     public ProcessResult executeJavawsHeadless(String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl) throws Exception {
538         return executeJavawsHeadless(null, resource,stdoutl,stderrl,null);
539     }
executeJavawsClearCache()540     public ProcessResult executeJavawsClearCache() throws Exception {
541          return executeProcess(Arrays.asList(new String[]{getJavawsLocation(), OptionsDefinitions.OPTIONS.CLEARCACHE.option,  ServerAccess.HEADLES_OPTION}));
542     }
543 
544     /**
545      * wrapping method to executeProcess (eg: javaws arg arg -headless http://localhost:port/resource)
546      * will execute default javaws (@see JAVAWS_BUILD_BIN) upon default url upon cached server (@see SERVER_NAME @see getPort(), @see getInstance())
547      * with parameter -headless (no gui, no asking)
548      * @param resource  name of resource
549      * @param otherargs other arguments to be added to headless one
550      * @return result what left after running this process
551      * @throws Exception
552      */
executeJavawsHeadless(List<String> otherargs, String resource)553     public ProcessResult executeJavawsHeadless(List<String> otherargs, String resource) throws Exception {
554          return executeJavawsHeadless(otherargs, resource,null,null,null);
555      }
executeJavawsHeadless(List<String> otherargs, String resource, String[] vars)556     public ProcessResult executeJavawsHeadless(List<String> otherargs, String resource, String[] vars) throws Exception {
557          return executeJavawsHeadless(otherargs, resource,null,null,vars);
558      }
559 
executeJavawsHeadless(List<String> otherargs, String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl,String[] vars)560     public ProcessResult executeJavawsHeadless(List<String> otherargs, String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl,String[] vars) throws Exception {
561         if (otherargs == null) {
562             otherargs = new ArrayList<>(1);
563         }
564         List<String> headlesList = new ArrayList<>(otherargs);
565         headlesList.add(HEADLES_OPTION);
566         return executeJavaws(headlesList, resource,stdoutl,stderrl,vars);
567     }
568 
569 
570     /**
571      * wrapping method to executeProcess (eg: javaws  http://localhost:port/resource)
572      * will execute default javaws (@see JAVAWS_BUILD_BIN) upon default url upon cached server (@see SERVER_NAME @see getPort(), @see getInstance())
573      * @param resource  name of resource
574      * @return result what left after running this process
575      * @throws Exception
576      */
executeJavaws(String resource)577     public ProcessResult executeJavaws(String resource) throws Exception {
578         return executeJavaws(null, resource);
579     }
executeJavaws(String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl)580     public ProcessResult executeJavaws(String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl) throws Exception {
581         return executeJavaws(null, resource,stdoutl,stderrl);
582     }
583 
executeBrowser(String string, AutoClose autoClose)584     public net.sourceforge.jnlp.ProcessResult executeBrowser(String string, AutoClose autoClose) throws Exception {
585         ClosingListener errClosing = null;
586         ClosingListener outClosing = null;
587         if (autoClose == AutoClose.CLOSE_ON_BOTH || autoClose == AutoClose.CLOSE_ON_EXCEPTION){
588             errClosing=new AutoErrorClosingListener();
589         }
590         if (autoClose == AutoClose.CLOSE_ON_BOTH || autoClose == AutoClose.CLOSE_ON_CORRECT_END){
591             outClosing=new AutoOkClosingListener();
592         }
593         return executeBrowser(string, outClosing, errClosing);
594     }
595 
596     /**
597      *
598      * @param resource relative resource to be opened in browser for current server instance.
599      * @return result of browser run
600      *
601      */
executeBrowser(String resource)602     public ProcessResult executeBrowser(String resource) throws Exception {
603         return executeBrowser(getBrowserParams(), resource);
604     }
605 
606     /**
607      *
608      * @param resource relative resource to be opened in browser for current server instance.
609      * @param stdoutl listener for stdout
610      * @param stderrl listener for stderr
611      * @return result of browser run
612      *
613      */
executeBrowser(String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl)614     public ProcessResult executeBrowser(String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl) throws Exception {
615         return executeBrowser(getBrowserParams(), resource, stdoutl, stderrl);
616     }
617 
618      /**
619      *
620      * @param resource elative resource to be opened in browser for current server instance.
621      * @param stdoutl listeners for stdout
622      * @param stderrl listeners for stderr
623      * @return result of browser run
624      *
625      */
executeBrowser(String resource, List<ContentReaderListener> stdoutl, List<ContentReaderListener> stderrl)626     public ProcessResult executeBrowser(String resource, List<ContentReaderListener> stdoutl, List<ContentReaderListener> stderrl) throws Exception {
627         return executeBrowser(getBrowserParams(), resource, stdoutl, stderrl);
628     }
629 
630     /**
631      *  wrapping method to executeProcess (eg: javaws arg arg http://localhost:port/resource)
632      * will execute default javaws (@see JAVAWS_BUILD_BIN) upon default url upon cached server (@see SERVER_NAME @see getPort(), @see getInstance()))
633      * @param resource  name of resource
634      * @param otherargs other arguments to be added
635      * @return result what left after running this process
636      * @throws Exception
637      */
executeJavaws(List<String> otherargs, String resource)638     public ProcessResult executeJavaws(List<String> otherargs, String resource) throws Exception {
639         return executeProcessUponURL(getJavawsLocation(), otherargs, getUrlUponThisInstance(resource));
640     }
executeJavaws(List<String> otherargs, String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl)641     public ProcessResult executeJavaws(List<String> otherargs, String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl) throws Exception {
642         return executeProcessUponURL(getJavawsLocation(), otherargs, getUrlUponThisInstance(resource),stdoutl,stderrl);
643     }
executeJavaws(List<String> otherargs, String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl,String[] vars)644     public ProcessResult executeJavaws(List<String> otherargs, String resource,ContentReaderListener stdoutl,ContentReaderListener stderrl,String[] vars) throws Exception {
645         return executeProcessUponURL(getJavawsLocation(), otherargs, getUrlUponThisInstance(resource),stdoutl,stderrl,vars);
646     }
647 
executeBrowser(List<String> otherargs, String resource)648     public ProcessResult executeBrowser(List<String> otherargs, String resource) throws Exception {
649         return executeBrowser(otherargs, getUrlUponThisInstance(resource));
650     }
651 
executeBrowser(List<String> otherargs, URL url)652      public ProcessResult executeBrowser(List<String> otherargs, URL url) throws Exception {
653         ProcessWrapper rpw = new ProcessWrapper(getBrowserLocation(), otherargs, url);
654         rpw.setReactingProcess(getCurrentBrowser());//current browser may be null, but it does not metter
655         return rpw.execute();
656     }
657 
executeBrowser(List<String> otherargs, String resource, ContentReaderListener stdoutl, ContentReaderListener stderrl)658     public ProcessResult executeBrowser(List<String> otherargs, String resource, ContentReaderListener stdoutl, ContentReaderListener stderrl) throws Exception {
659         ProcessWrapper rpw = new ProcessWrapper(getBrowserLocation(), otherargs, getUrlUponThisInstance(resource), stdoutl, stderrl, null);
660         rpw.setReactingProcess(getCurrentBrowser());//current browser may be null, but it does not metter
661         return rpw.execute();
662     }
663 
executeBrowser(List<String> otherargs, URL url, ContentReaderListener stdoutl, ContentReaderListener stderrl)664     public ProcessResult executeBrowser(List<String> otherargs, URL url, ContentReaderListener stdoutl, ContentReaderListener stderrl) throws Exception {
665         ProcessWrapper rpw = new ProcessWrapper(getBrowserLocation(), otherargs, url, stdoutl, stderrl, null);
666         rpw.setReactingProcess(getCurrentBrowser());//current browser may be null, but it does not metter
667         return rpw.execute();
668     }
669 
executeBrowser(List<String> otherargs, String resource, List<ContentReaderListener> stdoutl, List<ContentReaderListener> stderrl)670     public ProcessResult executeBrowser(List<String> otherargs,    String resource, List<ContentReaderListener> stdoutl, List<ContentReaderListener> stderrl) throws Exception {
671         ProcessWrapper rpw = new ProcessWrapper(getBrowserLocation(), otherargs, getUrlUponThisInstance(resource), stdoutl, stderrl, null);
672         rpw.setReactingProcess(getCurrentBrowser());// current browser may be null, but it does not matter
673         return rpw.execute();
674     }
675 
executeBrowser(Browser b, List<String> otherargs, String resource)676     public ProcessResult executeBrowser(Browser b, List<String> otherargs, String resource) throws Exception {
677         ProcessWrapper rpw = new ProcessWrapper(b.getBin(), otherargs, getUrlUponThisInstance(resource));
678         rpw.setReactingProcess(b);
679         return rpw.execute();
680     }
681 
executeBrowser(Browser b, List<String> otherargs, String resource, ContentReaderListener stdoutl, ContentReaderListener stderrl)682     public ProcessResult executeBrowser(Browser b, List<String> otherargs, String resource, ContentReaderListener stdoutl, ContentReaderListener stderrl) throws Exception {
683         ProcessWrapper rpw = new ProcessWrapper(b.getBin(), otherargs, getUrlUponThisInstance(resource), stdoutl, stderrl, null);
684         rpw.setReactingProcess(b);
685         return rpw.execute();
686     }
687 
executeBrowser(Browser b, List<String> otherargs, String resource, List<ContentReaderListener> stdoutl, List<ContentReaderListener> stderrl)688     public ProcessResult executeBrowser(Browser b, List<String> otherargs, String resource, List<ContentReaderListener> stdoutl, List<ContentReaderListener> stderrl) throws Exception {
689         ProcessWrapper rpw = new ProcessWrapper(b.getBin(), otherargs, getUrlUponThisInstance(resource), stdoutl, stderrl, null);
690         rpw.setReactingProcess(b);
691         return rpw.execute();
692     }
693 
694     /**
695      * Create resource on http, on 'localhost' on port on which this cached instance is running
696      * @param resource
697      * @return
698      * @throws MalformedURLException
699      */
getUrlUponThisInstance(String resource)700     public URL getUrlUponThisInstance(String resource) throws MalformedURLException {
701         getInstance();
702         return getUrlUponInstance(server, resource);
703     }
704 
705     /**
706      * Create resource on http, on 'localhost' on port on which this instance is running
707      * @param instance of server to return the resource
708      * @param resource relative path to resource to be loaded from specified instance
709      * @return the absolute url
710      * @throws MalformedURLException
711      */
getUrlUponInstance(ServerLauncher instance,String resource)712     public static URL getUrlUponInstance(ServerLauncher instance,String resource) throws MalformedURLException {
713        return instance.getUrl(resource);
714     }
715 
716     /**
717      * wrapping method to executeProcess (eg: javaws arg arg arg url)
718      * will execute default javaws (@see JAVAWS_BUILD_BIN) upon any server
719      * @param otherargs - commandline arguments  for javaws process
720      * @param u url of resource upon any server
721      * @return result what left after running this process
722      * @throws Exception
723      */
executeJavawsUponUrl(List<String> otherargs, URL u)724     public ProcessResult executeJavawsUponUrl(List<String> otherargs, URL u) throws Exception {
725         return executeProcessUponURL(getJavawsLocation(), otherargs, u);
726     }
executeJavawsUponUrl(List<String> otherargs, URL u,ContentReaderListener stdoutl,ContentReaderListener stderrl)727     public ProcessResult executeJavawsUponUrl(List<String> otherargs, URL u,ContentReaderListener stdoutl,ContentReaderListener stderrl) throws Exception {
728         return executeProcessUponURL(getJavawsLocation(), otherargs, u,stdoutl,stderrl);
729     }
730 
731     /**
732      * wrapping utility method to executeProcess (eg: any_binary arg arg arg url)
733      *
734      * will execute  any process upon  url upon any server
735      * @param toBeExecuted - command to lunch javaws program
736      * @param u url of resource upon any server
737      * @param otherargs commandline arguments for new process
738      * @return result what left after running this process
739      * @throws Exception
740      */
executeProcessUponURL(String toBeExecuted, List<String> otherargs, URL u)741     public static ProcessResult executeProcessUponURL(String toBeExecuted, List<String> otherargs, URL u) throws Exception {
742         return new ProcessWrapper(toBeExecuted, otherargs, u).execute();
743     }
744 
executeProcessUponURL(String toBeExecuted, List<String> otherargs, URL u, ContentReaderListener stdoutl, ContentReaderListener stderrl)745     public static ProcessResult executeProcessUponURL(String toBeExecuted, List<String> otherargs, URL u, ContentReaderListener stdoutl, ContentReaderListener stderrl) throws Exception {
746         return new ProcessWrapper(toBeExecuted, otherargs, u, stdoutl, stderrl, null).execute();
747     }
748 
executeProcessUponURL(String toBeExecuted, List<String> otherargs, URL u, ContentReaderListener stdoutl, ContentReaderListener stderrl, String[] vars)749     public static ProcessResult executeProcessUponURL(String toBeExecuted, List<String> otherargs, URL u, ContentReaderListener stdoutl, ContentReaderListener stderrl, String[] vars) throws Exception {
750         return new ProcessWrapper(toBeExecuted, otherargs, u, stdoutl, stderrl, vars).execute();
751     }
752 
executeProcess(final List<String> args)753      public static ProcessResult executeProcess(final List<String> args) throws Exception {
754          return  executeProcess(args, null);
755      }
executeProcess(final List<String> args,ContentReaderListener stdoutl,ContentReaderListener stderrl)756       public static ProcessResult executeProcess(final List<String> args,ContentReaderListener stdoutl,ContentReaderListener stderrl) throws Exception {
757          return  executeProcess(args, null,stdoutl,stderrl);
758      }
executeProcess(final List<String> args,ContentReaderListener stdoutl,ContentReaderListener stderrl,String[] vars)759       public static ProcessResult executeProcess(final List<String> args,ContentReaderListener stdoutl,ContentReaderListener stderrl,String[] vars) throws Exception {
760          return  executeProcess(args, null,stdoutl,stderrl,vars);
761      }
762     /**
763      * utility method to lunch process, get its stdout/stderr, its return value and to kill it if running to long (@see PROCESS_TIMEOUT)
764      *
765      *
766      * Small background:
767      * This method creates thread inside which exec will be executed. Then creates assassin thread with given timeout to kill the previously created thread if necessary.
768      * Starts assassin thread, starts process thread. Wait until process is running, then starts content readers.
769      * Closes input of process.
770      * Wait until process is running (no matter if it terminate itself (correctly or badly), or is terminated by its assassin.
771      * Construct result from read stdout, stderr, process return value, assassin successfully
772      *
773      * @param args binary with args to be executed
774      * @param dir optional, directory where this process will run
775      * @return what left from process - process itself, its stdout, stderr and return value and whether it was terminated by assassin.
776      * @throws Exception
777      */
executeProcess(final List<String> args,File dir)778     public static ProcessResult executeProcess(final List<String> args,File dir) throws Exception {
779         return executeProcess(args, dir, null, null);
780     }
781 
782     /**
783      * Proceed message s to logging with request to reprint to System.err
784      * @param s
785      */
logErrorReprint(String s)786     public static void logErrorReprint(String s) {
787         log(s, false, true);
788     }
789 
790     /**
791      * Proceed message s to logging with request to reprint to System.out
792      * @param s
793      */
logOutputReprint(String s)794     public static void logOutputReprint(String s) {
795         log(s, true, false);
796     }
797 
798     /**
799      * Proceed message s to logging withhout request to reprint
800      * @param s
801      */
logNoReprint(String s)802     public static void logNoReprint(String s) {
803         log(s, false, false);
804     }
805 
log(String message, boolean printToOut, boolean printToErr)806     static void log(String message, boolean printToOut, boolean printToErr) {
807         String idded;
808         StackTraceElement ste = getTestMethod();
809         String fullId = LoggingBottleneck.getDefaultLoggingBottleneck().modifyMethodWithForBrowser(ste.getMethodName(), ste.getClassName());
810         if (message.contains("\n")) {
811             idded = fullId + ": \n" + message + "\n" + fullId + " ---";
812         } else {
813             idded = fullId + ": " + message;
814 
815         }
816         if (LOGS_REPRINT) {
817             if (printToOut) {
818                 System.out.println(idded);
819             }
820             if (printToErr) {
821                 System.err.println(idded);
822             }
823         }
824         LoggingBottleneck.getDefaultLoggingBottleneck().logIntoPlaintextLog(idded, printToOut,printToErr);
825         LoggingBottleneck.getDefaultLoggingBottleneck().addToXmlLog(message,printToOut,printToErr,ste);
826     }
827 
logException(Throwable t)828     public static void logException(Throwable t){
829         logException(t, true);
830     }
logException(Throwable t, boolean print)831     public static void logException(Throwable t, boolean print){
832         log(OutputController.exceptionToString(t), false, print);
833     }
834 
getTestMethod()835     private static StackTraceElement getTestMethod() {
836         return getTestMethod(Thread.currentThread().getStackTrace());
837     }
838 
getTestMethod(StackTraceElement[] stack)839     private static StackTraceElement getTestMethod(StackTraceElement[] stack) {
840         //0 is always thread
841         //1 is net.sourceforge.jnlp.*
842         //we need to get out of all  of classes from this package or pick last of it
843         StackTraceElement result = stack[1];
844         String baseClass = stack[1].getClassName();
845         int i = 2;
846         for (; i < stack.length; i++) {
847             result = stack[i];//at least moving up
848             if (stack[i].getClassName().contains("$")) {
849                 continue;
850             }
851             //probablky it is necessary to get out of net.sourceforge.jnlp.
852             //package where are right now all test-extensions
853             //for now keeping exactly the three classes helping you  access the log
854             try {
855                 Class<?> clazz = Class.forName(stack[i].getClassName());
856                 String path = null;
857                 try {
858                     path = clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
859                 } catch (NullPointerException ex) {
860                     //silently ignoring and continuing with null path
861                 }
862                 if (path != null && path.contains("/tests.build/")) {
863                     if (!path.contains("/test-extensions/")) {
864                         break;
865                     }
866                 } else {
867                     //running from ide
868                     if (!stack[i].getClassName().startsWith("net.sourceforge.jnlp.")) {
869                         break;
870                     }
871                 }
872             } catch (ClassNotFoundException ex) {
873                 ///should not happen, searching  only for already loaded class
874                 ex.printStackTrace();
875             }
876         }
877         //if nothing left in stack then we have been in ServerAccess already
878         //so the target method is the highest form it and better to return it
879         //rather then die to ArrayOutOfBounds
880         if (i >= stack.length) {
881             return result;
882         }
883         //now we are out of test-extensions
884         //method we need (the test)  is highest from following class
885         baseClass = stack[i].getClassName();
886         for (; i < stack.length; i++) {
887             if(stack[i].getClassName().contains("$")){
888                 continue;
889             }
890             if (!baseClass.equals(stack[i].getClassName())) {
891                 break;
892             }
893             result = stack[i];
894         }
895 
896         return result;
897     }
898 
executeProcess(final List<String> args, File dir, ContentReaderListener stdoutl, ContentReaderListener stderrl)899     public static ProcessResult executeProcess(final List<String> args, File dir, ContentReaderListener stdoutl, ContentReaderListener stderrl) throws Exception {
900         return executeProcess(args, dir, stdoutl, stderrl,null);
901 
902     }
executeProcess(final List<String> args, File dir, ContentReaderListener stdoutl, ContentReaderListener stderrl, String[] vars)903     public static ProcessResult executeProcess(final List<String> args, File dir, ContentReaderListener stdoutl, ContentReaderListener stderrl, String[] vars) throws Exception {
904         return new ProcessWrapper(args, dir, stdoutl, stderrl, vars).execute();
905     }
906 
907 }
908