1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002, 2014 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 
8 package com.sleepycat.je.junit;
9 
10 import java.io.BufferedReader;
11 import java.io.InputStream;
12 import java.io.InputStreamReader;
13 
14 /**
15  * [#16348] JE file handle leak when multi-process writing a same environment.
16  *
17  * Write this thread for creating multi-process test, you can generate
18  * a JUnitProcessThread, each thread would create a process for you, just need
19  * to assign the command line parameters to the thread.
20  */
21 public class JUnitProcessThread extends JUnitThread {
22     private String cmdArrays[];
23 
24     /*
25      * Variable record the return value of the process. If 0, it means the
26      * process finishes successfully, if not, the process fails.
27      */
28     private int exitVal = 0;
29 
30     /* If true, don't print out the standard output in this process. */
31     private final boolean suppressOutput;
32 
33     /**
34      * Pass the process name and command line to the constructor.
35      */
JUnitProcessThread(String threadName, String[] parameters)36     public JUnitProcessThread(String threadName, String[] parameters) {
37         this(threadName, null, parameters, false);
38     }
39 
JUnitProcessThread(String threadName, String[] jvmParams, String[] parameters)40     public JUnitProcessThread(String threadName,
41                               String[] jvmParams,
42                               String[] parameters) {
43         this(threadName, jvmParams, parameters, false);
44     }
45 
JUnitProcessThread(String threadName, String[] jvmParams, String[] parameters, boolean suppressOutput)46     public JUnitProcessThread(String threadName,
47                               String[] jvmParams,
48                               String[] parameters,
49                               boolean suppressOutput) {
50         super(threadName);
51 
52         this.suppressOutput = suppressOutput;
53 
54         if (jvmParams == null) {
55             jvmParams = new String[0];
56         }
57 
58         cmdArrays = new String[3 + jvmParams.length + parameters.length];
59         cmdArrays[0] = System.getProperty("java.home") +
60             System.getProperty("file.separator") + "bin" +
61             System.getProperty("file.separator") + "java" +
62             (System.getProperty("path.separator").equals(":") ? "" : "w.exe");
63 
64         for (int i = 0; i < jvmParams.length; i++) {
65             cmdArrays[i + 1] = jvmParams[i];
66         }
67 
68         cmdArrays[jvmParams.length + 1] = "-cp";
69         cmdArrays[jvmParams.length + 2] =
70             "." + System.getProperty("path.separator") +
71             System.getProperty("java.class.path");
72 
73         for (int i = 0; i < parameters.length; i++) {
74             cmdArrays[i + jvmParams.length + 3] = parameters[i];
75         }
76     }
77 
78     /** Generate a process for this thread.*/
testBody()79     public void testBody() {
80         Runtime runtime = Runtime.getRuntime();
81 
82         try {
83             Process proc = runtime.exec(cmdArrays);
84 
85             InputStream error = proc.getErrorStream();
86             InputStream output = proc.getInputStream();
87 
88             Thread err = new Thread(new OutErrReader(error));
89             err.start();
90 
91             if (!suppressOutput) {
92                 Thread out = new Thread(new OutErrReader(output));
93                 out.start();
94             }
95 
96             exitVal = proc.waitFor();
97         } catch (Exception e) {
98             e.printStackTrace();
99         }
100     }
101 
102     /** Return the return value of the created process to main thread. */
getExitVal()103     public int getExitVal() {
104         return exitVal;
105     }
106 
107     /**
108      * A class prints out the output information of writing serialized files.
109      */
110     public static class OutErrReader implements Runnable {
111         final InputStream is;
112         final boolean ignoreOutput;
113 
OutErrReader(InputStream is)114         public OutErrReader(InputStream is) {
115             this.is = is;
116             this.ignoreOutput = false;
117         }
118 
OutErrReader(InputStream is, boolean ignoreOutput)119         public OutErrReader(InputStream is, boolean ignoreOutput) {
120             this.is = is;
121             this.ignoreOutput = ignoreOutput;
122         }
123 
run()124         public void run() {
125             try {
126                 BufferedReader in =
127                     new BufferedReader(new InputStreamReader(is));
128                 String temp = new String();
129                 while((temp = in.readLine()) != null) {
130                     if (!ignoreOutput) {
131                         System.err.println(temp);
132                     }
133                 }
134                 is.close();
135             } catch (Exception e) {
136                 if (!ignoreOutput) {
137                     e.printStackTrace();
138                 }
139             }
140         }
141     }
142 }
143