1 /*
2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package nsk.monitoring.share;
25 
26 import java.util.*;
27 import nsk.share.log.Log;
28 import nsk.share.ClassUnloader;
29 import nsk.share.CustomClassLoader;
30 import nsk.share.test.Stresser;
31 
32 /**
33  * The <code>ClassLoadingController</code> class allows to operate class
34  * loading/unloading process.
35  */
36 public class ClassLoadingController extends StateControllerBase {
37         // Path and name of the classes to load
38         private static final String CLASSNAME_PATTERN = "nsk.monitoring.share.newclass.LoadableClass";
39 
40         private int loadedClassCount = 100;
41         private int loaderCount = 1;
42         private boolean singleClass = true;
43         private String classDir;
44         private Hashtable<String, String[]> classesTable = new Hashtable<String, String[]>();
45         private ClassUnloader[] unloaders;
46 
47         private Stresser stresser;
48 
49         /**
50          * Constructs a new <code>ClassLoadingController</code> with defined
51          * arguments.
52          *
53          * @param log <code>Log</code> to print log info to.
54          * @param loadedClassCount number of classes to load.
55          * @param loaderCount number of loaders to use.
56          * @param singleClass if class loaders are instances of the same class.
57          * @param classDir directory to load classes from.
58          */
ClassLoadingController( Log log, int loadedClassCount, int loaderCount, boolean singleClass, String classDir, Stresser stresser )59         public ClassLoadingController(
60                 Log log,
61                 int loadedClassCount,
62                 int loaderCount,
63                 boolean singleClass,
64                 String classDir,
65                 Stresser stresser
66         ) {
67                 super(log);
68                 setLoadedClassCount(loadedClassCount);
69                 setLoaderCount(loaderCount);
70                 setClassDir(classDir);
71                 singleClassLoaderClass(singleClass);
72                 dump();
73                 preloadAllClasses();
74                 setStresser(stresser);
75         }
76 
setStresser(Stresser stresser)77     private void setStresser(Stresser stresser) {
78         this.stresser = stresser;
79     }
80 
ClassLoadingController(Log log, ArgumentHandler argHandler, Stresser stresser)81     public ClassLoadingController(Log log, ArgumentHandler argHandler, Stresser stresser) {
82                 this(
83                         log,
84                         argHandler.getLoadableClassesCount(),
85 //                        argHandler.getLoadersCount(),
86                         (int)stresser.getMaxIterations(),
87                         argHandler.singleClassloaderClass(),
88                         argHandler.getRawArgument(0),
89                         stresser
90                 );
91         }
92 
dump()93         public void dump() {
94                 log.debug("classes to be loaded:\t" + loadedClassCount);
95                 log.debug("classloader instances:\t" + loaderCount);
96                 if (singleClass)
97                         log.debug("classloader class:\tsingle");
98                 else
99                         log.debug("classloader class:\ttwo");
100                 log.debug("Class dir" + classDir);
101 
102         }
103 
setLoadedClassCount(int loadedClassCount)104         private void setLoadedClassCount(int loadedClassCount) {
105                 this.loadedClassCount = loadedClassCount;
106         }
107 
108         // Set loaderCount value
setLoaderCount(int loaderCount)109         private void setLoaderCount(int loaderCount) {
110                 this.loaderCount = loaderCount;
111         }
112 
113         // Set singleClass value
singleClassLoaderClass(boolean singleClass)114         private void singleClassLoaderClass(boolean singleClass) {
115                 this.singleClass = singleClass;
116         }
117 
118         // Set classDir value
setClassDir(String classDir)119         private void setClassDir(String classDir) {
120                 this.classDir = classDir;
121         }
122 
123         // Load classes
preloadAllClasses()124         private void preloadAllClasses() {
125                 log.debug("preloading all classes...");
126                 if (singleClass)
127                         createUnloaders(1);
128                 else
129                         createUnloaders(2);
130 
131                 for (int i = 0; i < unloaders.length; i++) {
132                         loadClasses(unloaders[i], 1, false);
133                         unloaders[i].unloadClass();
134                 }
135         }
136 
137         // Load classes
loadClasses(ClassUnloader unloader, int classCount, boolean doKeep)138         private boolean loadClasses(ClassUnloader unloader, int classCount, boolean doKeep) {
139                 String newClassName;
140                 String[] classNames = new String[classCount + 1];
141                 classNames[0] = unloader.getClassLoader().getClass().getName()
142                         + "@"
143                         + Integer.toHexString(
144                                         unloader.getClassLoader().hashCode()
145                                         );
146 
147 
148                 for (int i = 1; i <= classCount; i++) {
149                         newClassName = CLASSNAME_PATTERN + int2Str(i);
150                         classNames[i] = newClassName;
151                         try {
152                                 unloader.loadClass(newClassName);
153                         } catch (ClassNotFoundException e) {
154                                 log.error(e.toString());
155                                 e.printStackTrace();
156                                 return false;
157                         }
158                 }
159                 if (doKeep)
160                         classesTable.put(String.valueOf(unloader.hashCode()), classNames);
161                 return true;
162         } // loadClasses()
163 
164         /**
165          * Loads all classes.
166          *
167          * @see ClassLoadingController#ClassLoadingController
168          */
loadClasses()169         public int loadClasses() {
170                 CustomClassLoader loader;
171                 boolean res = true;
172                 String loaderName;
173 
174                 createUnloaders(loaderCount);
175 
176                 int count = 0;
177                 for (int i = 0; i < unloaders.length; i++) {
178                         loaderName = unloaders[i].getClassLoader().getClass().getName()
179                                 + "@"
180                                 + Integer.toHexString(
181                                                 unloaders[i].getClassLoader().hashCode()
182                                                 );
183                         if (loadClasses(unloaders[i], loadedClassCount, true)) {
184                                 String[] values = (String[])
185                                         classesTable.get(String.valueOf(unloaders[i].hashCode()));
186                                 int length = values.length - 1;
187                                 log.debug(loaderName + "(" + i + ")>>> " + length
188                                                 + " classes have been loaded");
189                                 count += length;
190                         }
191                 }
192                 log.info("Total: loading is performed " + count + " times");
193 
194                 return count;
195         }
196 
197         // Unload classes
unloadClasses()198         public int unloadClasses() {
199                 String loaderName;
200                 int count = 0;
201                 long timeLeft = 0;
202 
203                 for (int i = 0; i < loaderCount && (timeLeft = stresser.getTimeLeft()/1000) > 0; i++) {
204                         loaderName = unloaders[i].getClassLoader().getClass().getName()
205                                 + "@"
206                                 + Integer.toHexString(
207                                                 unloaders[i].getClassLoader().hashCode()
208                                                 );
209                         String hashCode = String.valueOf(unloaders[i].hashCode());
210                         String[] values = (String[]) classesTable.get(hashCode);
211 
212                         if (unloaders[i].unloadClass()) {
213                                 int length = values.length - 1;
214                                 count += length;
215                                 log.debug(loaderName + "(" + i + ")>>> " + length
216                                                 + " classes have been unloaded (time left: "+timeLeft+" s)");
217                                 classesTable.remove(hashCode);
218                         } else {
219                                 log.debug(loaderName + "(" + i + ")>>> "
220                                                 + "classes couldn't be unloaded (time left: "+timeLeft+" s)");
221                         }
222                 }
223 
224                 log.info("Total: unloading is performed " + count + " times");
225 
226                 return count;
227         }
228 
createUnloaders(int count)229         private void createUnloaders(int count) {
230                 CustomClassLoader loader;
231                 unloaders = new ClassUnloader[count];
232 
233                 for (int i = 0; i < count; i++) {
234                         unloaders[i] = new ClassUnloader();
235                         if (singleClass) {
236                                 loader = unloaders[i].createClassLoader();
237                         } else {
238                                 if (i%2 == 0)
239                                         loader = new ClassLoaderA();
240                                 else
241                                         loader = new ClassLoaderB();
242                                 unloaders[i].setClassLoader(loader);
243                         }
244                         loader.setClassPath(classDir);
245                 } // for
246         }
247 
248         /**
249          * Brings out VM into defined state. The method loads all classes via
250          * {@link ClassLoadingController#loadClasses}.
251          *
252          * @see ClassLoadingController#loadClasses
253          */
run()254         public void run() {
255                 loadClasses();
256         }
257 
258         /**
259          * Tries to reclaim VM into initial state. The method tries to load all
260          * classes via {@link ClassLoadingController#unloadClasses}.
261          *
262          * @see ClassLoadingController#unloadClasses
263          */
reset()264         public void reset() {
265                 unloadClasses();
266         }
267 
268         // The class extends CustomClassLoader with specific implementation of
269         // toString() method
270         class ClassLoaderA extends CustomClassLoader {
ClassLoaderA()271                 public ClassLoaderA() {
272                         super();
273                 }
274 
toString()275                 public String toString() {
276                         return "ClassLoaderA";
277                 }
278         } // ClassLoaderA
279 
280         // The class extends CustomClassLoader with specific implementation of
281         // toString() method
282         class ClassLoaderB extends CustomClassLoader {
ClassLoaderB()283                 public ClassLoaderB() {
284                         super();
285                 }
286 
toString()287                 public String toString() {
288                         return "ClassLoaderB";
289                 }
290         } // ClassLoaderB
291 }
292