1 | package genius.core;
|
---|
2 |
|
---|
3 | import java.io.File;
|
---|
4 | import java.io.IOException;
|
---|
5 | import java.io.InputStream;
|
---|
6 | import java.io.ObjectInputStream;
|
---|
7 | import java.io.ObjectOutputStream;
|
---|
8 | import java.io.OutputStream;
|
---|
9 | import java.io.Serializable;
|
---|
10 | import java.lang.reflect.Constructor;
|
---|
11 | import java.lang.reflect.InvocationTargetException;
|
---|
12 | import java.net.MalformedURLException;
|
---|
13 | import java.net.URL;
|
---|
14 | import java.net.URLClassLoader;
|
---|
15 | import java.text.SimpleDateFormat;
|
---|
16 | import java.util.Calendar;
|
---|
17 | import java.util.Date;
|
---|
18 | import java.util.HashMap;
|
---|
19 | import java.util.TimeZone;
|
---|
20 | import java.util.regex.Matcher;
|
---|
21 |
|
---|
22 | import javax.swing.JOptionPane;
|
---|
23 |
|
---|
24 | import genius.core.exceptions.InstantiateException;
|
---|
25 | import genius.core.protocol.Protocol;
|
---|
26 | import genius.core.repository.AgentRepItem;
|
---|
27 | import genius.core.repository.ProfileRepItem;
|
---|
28 | import genius.core.repository.ProtocolRepItem;
|
---|
29 | import genius.core.tournament.TournamentConfiguration;
|
---|
30 | import genius.core.tournament.VariablesAndValues.AgentParamValue;
|
---|
31 | import genius.core.tournament.VariablesAndValues.AgentParameterVariable;
|
---|
32 | import genius.gui.agentrepository.AgentRepositoryUI;
|
---|
33 |
|
---|
34 | /**
|
---|
35 | * Overview of global variables used throughout the application.
|
---|
36 | *
|
---|
37 | * @author dmytro
|
---|
38 | */
|
---|
39 | public class Global {
|
---|
40 | /** Path to domain repository */
|
---|
41 | public static final String DOMAIN_REPOSITORY = "domainrepository.xml";
|
---|
42 | /** Path to agent repository */
|
---|
43 | public static final String AGENT_REPOSITORY = "agentrepository.xml";
|
---|
44 | /** Path to protocol repository */
|
---|
45 | public static final String PROTOCOL_REPOSITORY = "protocolrepository.xml";
|
---|
46 | /** Path to simulator repository */
|
---|
47 | public static final String SIMULATOR_REPOSITORY = "simulatorrepository.xml";
|
---|
48 |
|
---|
49 | public static String logPrefix = "";
|
---|
50 |
|
---|
51 | public static String logPreset = "";
|
---|
52 |
|
---|
53 | private final static String WRONG_NAME = "wrong name: ";
|
---|
54 |
|
---|
55 | private static final Date loadDate = Calendar.getInstance().getTime();
|
---|
56 |
|
---|
57 | public static String getCurrentTime() {
|
---|
58 | Calendar cal = Calendar.getInstance(TimeZone.getDefault());
|
---|
59 | String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
---|
60 | java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(DATE_FORMAT);
|
---|
61 | /*
|
---|
62 | * on some JDK, the default TimeZone is wrong we must set the TimeZone
|
---|
63 | * manually.
|
---|
64 | */
|
---|
65 | sdf.setTimeZone(TimeZone.getDefault());
|
---|
66 |
|
---|
67 | return sdf.format(cal.getTime());
|
---|
68 | }
|
---|
69 |
|
---|
70 | public static String getFileNameWithoutExtension(String fileName) {
|
---|
71 |
|
---|
72 | File tmpFile = new File(fileName);
|
---|
73 | tmpFile.getName();
|
---|
74 | int whereDot = tmpFile.getName().lastIndexOf('.');
|
---|
75 | if (0 < whereDot && whereDot <= tmpFile.getName().length() - 2) {
|
---|
76 | return tmpFile.getName().substring(0, whereDot);
|
---|
77 | }
|
---|
78 | return "";
|
---|
79 | }
|
---|
80 |
|
---|
81 | public static Class<Protocol> getProtocolClass(ProtocolRepItem protRepItem) throws Exception {
|
---|
82 | java.lang.ClassLoader loader = Global.class.getClassLoader();// ClassLoader.getSystemClassLoader();
|
---|
83 | Class<Protocol> klass = (Class<Protocol>) loader.loadClass(protRepItem.getClassPath());
|
---|
84 | return klass;
|
---|
85 | }
|
---|
86 |
|
---|
87 | public static Protocol createProtocolInstance(ProtocolRepItem protRepItem, AgentRepItem[] agentRepItems,
|
---|
88 | ProfileRepItem[] profileRepItems, HashMap<AgentParameterVariable, AgentParamValue>[] agentParams)
|
---|
89 | throws InstantiateException {
|
---|
90 | try {
|
---|
91 | Protocol ns;
|
---|
92 |
|
---|
93 | java.lang.ClassLoader loader = ClassLoader.getSystemClassLoader();
|
---|
94 |
|
---|
95 | Class klass;
|
---|
96 | klass = loader.loadClass(protRepItem.getClassPath());
|
---|
97 | Class[] paramTypes = { AgentRepItem[].class, ProfileRepItem[].class, HashMap[].class, int.class };
|
---|
98 |
|
---|
99 | Constructor cons = klass.getConstructor(paramTypes);
|
---|
100 |
|
---|
101 | System.out.println("Found the constructor: " + cons);
|
---|
102 |
|
---|
103 | Object[] args = { agentRepItems, profileRepItems, agentParams, 1 };
|
---|
104 |
|
---|
105 | Object theObject = cons.newInstance(args);
|
---|
106 | ns = (Protocol) (theObject);
|
---|
107 | return ns;
|
---|
108 | } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException
|
---|
109 | | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
---|
110 | throw new InstantiateException("Failed to create instance", e);
|
---|
111 | }
|
---|
112 | }
|
---|
113 |
|
---|
114 | /**
|
---|
115 | * Load an object from a given path. If it's a .class file, figure out the
|
---|
116 | * correct class path and use that. If it's not a .class file, we assume
|
---|
117 | * it's already in the existing classpath and load it with the standard
|
---|
118 | * class loader.
|
---|
119 | *
|
---|
120 | *
|
---|
121 | * <p>
|
---|
122 | * we can't properly typecheck here. Generics fail as we have type erasure,
|
---|
123 | * and casting to the given type does NOTHING. So we leave this a general
|
---|
124 | * object and leave it to the caller to do the type checking.
|
---|
125 | *
|
---|
126 | * @param path
|
---|
127 | * This can be either a class name or filename.<br>
|
---|
128 | * <ul>
|
---|
129 | * <li>class name like"agents.anac.y2010.AgentFSEGA.AgentFSEGA".
|
---|
130 | * In this case the agent must be already on the JVM's classpath
|
---|
131 | * otherwise the agent will not be found. <br>
|
---|
132 | * <li>a full path, eg
|
---|
133 | * "/Volumes/documents/NegoWorkspace3/NegotiatorGUI/src/agents/anac/y2010/AgentFSEGA/AgentFSEGA.java"
|
---|
134 | * . In this case, we can figure out the class path ourselves,
|
---|
135 | * but the ref is system dependent (backslashes on windows) and
|
---|
136 | * might be absolute path.
|
---|
137 | * </ul>
|
---|
138 | *
|
---|
139 | * @return the {@link Object} in the given file
|
---|
140 | * @throws InstantiateException
|
---|
141 | * if path can not be loaded as object.
|
---|
142 | */
|
---|
143 | public static Object loadObject(String path) throws InstantiateException {
|
---|
144 | try {
|
---|
145 | if (path.endsWith(".class")) {
|
---|
146 | return loadClassFromFile(new File(path));
|
---|
147 | } else {
|
---|
148 | java.lang.ClassLoader loaderA = Global.class.getClassLoader();
|
---|
149 | return (loaderA.loadClass(path).newInstance());
|
---|
150 | }
|
---|
151 | } catch (Exception e) {
|
---|
152 | throw new InstantiateException("failed to load class from " + path, e);
|
---|
153 | }
|
---|
154 | }
|
---|
155 |
|
---|
156 | /**
|
---|
157 | * Runtime type-checked version of {@link #loadObject(String)}.
|
---|
158 | *
|
---|
159 | * @param path
|
---|
160 | * @param expectedClass
|
---|
161 | * the class type that the loaded object must extend.
|
---|
162 | * @return loaded object.
|
---|
163 | * @throws InstantiateException
|
---|
164 | */
|
---|
165 |
|
---|
166 | public static Object loadObject(String path, Class<?> expectedClass) throws InstantiateException {
|
---|
167 | Object object = loadObject(path);
|
---|
168 | if (!object.getClass().isAssignableFrom(expectedClass)) {
|
---|
169 | throw new InstantiateException("Failed to load class " + path + ": It is not extending " + expectedClass);
|
---|
170 | }
|
---|
171 | return object;
|
---|
172 | }
|
---|
173 |
|
---|
174 | /**
|
---|
175 | * Deserializes an object and casts it to the given type.
|
---|
176 | *
|
---|
177 | * @param is
|
---|
178 | * the input stream containing serialized object.
|
---|
179 | * @return object contained in given stream.
|
---|
180 | * @throws IOException
|
---|
181 | * if file can not be found
|
---|
182 | * @throws ClassNotFoundException
|
---|
183 | * if class in the object can't be found
|
---|
184 | * @throws ClassCastException
|
---|
185 | * if not of given class type
|
---|
186 | */
|
---|
187 | @SuppressWarnings("unchecked")
|
---|
188 | public static <T> T deserializeObject(InputStream is) throws ClassNotFoundException, IOException {
|
---|
189 | Object obj = new ObjectInputStream(is).readObject();
|
---|
190 | return (T) obj;
|
---|
191 | }
|
---|
192 |
|
---|
193 | /**
|
---|
194 | * Serialize a serializable object to a outputstream.
|
---|
195 | *
|
---|
196 | * @param outputStream
|
---|
197 | * the stream to write to
|
---|
198 | * @param object
|
---|
199 | * the object to store
|
---|
200 | * @throws IOException
|
---|
201 | */
|
---|
202 | public static void serializeObject(OutputStream outputStream, Serializable object) throws IOException {
|
---|
203 | new ObjectOutputStream(outputStream).writeObject(object);
|
---|
204 | }
|
---|
205 |
|
---|
206 | /**
|
---|
207 | * Load a file as a class. It 'reverse engineers' the correct path by first
|
---|
208 | * just trying to load the file. Assuming the file exists, we probably get
|
---|
209 | * an error that we then use to determine the correct base directory.
|
---|
210 | *
|
---|
211 | * @param file
|
---|
212 | * the object to be loaded. Filename should end with ".class".
|
---|
213 | * @return the object contained in the file.
|
---|
214 | * @throws ClassNotFoundException
|
---|
215 | * @throws IllegalAccessException
|
---|
216 | * @throws InstantiationException
|
---|
217 | * @throws MalformedURLException
|
---|
218 | */
|
---|
219 | public static Object loadClassFromFile(File file)
|
---|
220 | throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException {
|
---|
221 | String className = file.getName();
|
---|
222 | if (!className.endsWith(".class")) {
|
---|
223 | throw new IllegalArgumentException("file " + file + " is not a .class file");
|
---|
224 | }
|
---|
225 | // strip the trailing '.class' from the string.
|
---|
226 | className = className.substring(0, className.length() - 6);
|
---|
227 | File packageDir = file.getParentFile();
|
---|
228 | if (packageDir == null) {
|
---|
229 | packageDir = new File(".");
|
---|
230 | }
|
---|
231 |
|
---|
232 | try {
|
---|
233 | return loadClassfile(className, packageDir);
|
---|
234 | } catch (NoClassDefFoundError e) {
|
---|
235 | /**
|
---|
236 | * We try to get the correct name from the error message. Err msg ~
|
---|
237 | * "SimpleAgent (wrong name: agents/SimpleAgent)"
|
---|
238 | */
|
---|
239 | String errormsg = e.getMessage();
|
---|
240 | // "wrong name" is what we expect.
|
---|
241 | int i = errormsg.indexOf(WRONG_NAME);
|
---|
242 | if (i == -1) {
|
---|
243 | throw e; // unknown error. We can't handle...
|
---|
244 | }
|
---|
245 | // remove leading and trailing stuff. We now have
|
---|
246 | // 'agents.SimpleAgent'
|
---|
247 | String correctName = errormsg.substring(i + WRONG_NAME.length(), errormsg.length() - 1).replaceAll("/",
|
---|
248 | ".");
|
---|
249 |
|
---|
250 | // Check that file is in correct directory path
|
---|
251 | // we need quoteReplacement because on Windows "\" will be treated
|
---|
252 | // in special way by replaceAll. #906
|
---|
253 | String expectedPath = File.separator
|
---|
254 | + correctName.replaceAll("\\.", Matcher.quoteReplacement(File.separator)) + ".class";
|
---|
255 | if (!(file.getAbsolutePath().endsWith(expectedPath))) {
|
---|
256 | throw new NoClassDefFoundError("file " + file + "\nis not in the correct directory structure, "
|
---|
257 | + "\nas its class is " + correctName + "." + "\nEnsure the file is in ..." + expectedPath);
|
---|
258 | }
|
---|
259 |
|
---|
260 | // number of dots is number of times we need to go to parent
|
---|
261 | // directory. We are already in the directory of the agent, so -1.
|
---|
262 | for (int up = 0; up < correctName.split("\\.").length - 1; up++) {
|
---|
263 | // since we checked the path already, parents must exist.
|
---|
264 | packageDir = packageDir.getParentFile();
|
---|
265 | }
|
---|
266 | return loadClassfile(correctName, packageDir);
|
---|
267 | }
|
---|
268 | }
|
---|
269 |
|
---|
270 | /**
|
---|
271 | * Try to load an object with given classnamem from a given packagedir
|
---|
272 | *
|
---|
273 | * @param classname
|
---|
274 | * the exact class name, eg "examplepackage.example"
|
---|
275 | * @param packagedir
|
---|
276 | * the root directory of the classes to be loaded. If you add the
|
---|
277 | * given classname to it, you should end up at the correct
|
---|
278 | * location for the class file. Eg,
|
---|
279 | * "/Volumes/Users/wouter/Desktop/genius/".
|
---|
280 | * @return the loaded class object.
|
---|
281 | * @throws MalformedURLException
|
---|
282 | * @throws InstantiationException
|
---|
283 | * @throws IllegalAccessException
|
---|
284 | * @throws ClassNotFoundException
|
---|
285 | */
|
---|
286 | private static Object loadClassfile(String classname, File packagedir)
|
---|
287 | throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException {
|
---|
288 | try {
|
---|
289 | java.lang.ClassLoader loader = AgentRepositoryUI.class.getClassLoader();
|
---|
290 | URLClassLoader urlLoader = new URLClassLoader(new URL[] { packagedir.toURI().toURL() }, loader);
|
---|
291 | Class<?> theclass;
|
---|
292 | theclass = urlLoader.loadClass(classname);
|
---|
293 | return (Object) theclass.newInstance();
|
---|
294 | } catch (ClassNotFoundException e) {
|
---|
295 | // improve on the standard error message...
|
---|
296 | throw new ClassNotFoundException(
|
---|
297 | "agent " + classname + " is not available in directory '" + packagedir + "'", e);
|
---|
298 | }
|
---|
299 |
|
---|
300 | }
|
---|
301 |
|
---|
302 | /**
|
---|
303 | * Load an agent using the given classname/filename. DOES NOT call
|
---|
304 | * {@link Agent#parseStrategyParameters(String)}
|
---|
305 | *
|
---|
306 | * @param path
|
---|
307 | * This can be either a class name or filename.<br>
|
---|
308 | * <ul>
|
---|
309 | * <li>class name like"agents.anac.y2010.AgentFSEGA.AgentFSEGA".
|
---|
310 | * In this case the agent must be already on the JVM's classpath
|
---|
311 | * otherwise the agent will not be found.
|
---|
312 | * <li>a full path, eg
|
---|
313 | * "/Volumes/documents/NegoWorkspace3/NegotiatorGUI/src/agents/anac/y2010/AgentFSEGA/AgentFSEGA.java"
|
---|
314 | * . In this case, we can figure out the class path ourselves,
|
---|
315 | * but the ref is system dependent (backslashes on windows) and
|
---|
316 | * might be absolute path.
|
---|
317 | * </ul>
|
---|
318 | * @return instantiated agent ready to use.
|
---|
319 | * @throws InstantiateException
|
---|
320 | * if object can't be loaded
|
---|
321 | */
|
---|
322 | public static Agent loadAgent(String path) throws InstantiateException {
|
---|
323 | return (Agent) loadObject(path);
|
---|
324 | }
|
---|
325 |
|
---|
326 | /**
|
---|
327 | * load agent and then set the parameters. See {@link #loadAgent(String)}
|
---|
328 | *
|
---|
329 | * @param agentClassName
|
---|
330 | * @param variables
|
---|
331 | * the variables to use, as string (eg, "time=0.9;e=1.0").
|
---|
332 | * @return the agent contained in the given class name, and using the given
|
---|
333 | * variables.
|
---|
334 | * @throws InstantiateException
|
---|
335 | * if class can't be loaded
|
---|
336 | */
|
---|
337 | public static Agent loadAgent(String agentClassName, String variables) throws InstantiateException {
|
---|
338 |
|
---|
339 | Agent agent = loadAgent(agentClassName);
|
---|
340 |
|
---|
341 | // CHECK why do we catch failures in parseStrategyParameters?
|
---|
342 | try {
|
---|
343 | agent.parseStrategyParameters(variables);
|
---|
344 | } catch (Exception e) {
|
---|
345 | e.printStackTrace();
|
---|
346 | }
|
---|
347 | return agent;
|
---|
348 |
|
---|
349 | }
|
---|
350 |
|
---|
351 | /**
|
---|
352 | * Gives a useful agent name.
|
---|
353 | */
|
---|
354 | public static String getAgentDescription(Agent agent) {
|
---|
355 | if (agent == null)
|
---|
356 | return "";
|
---|
357 | String agentDescription = agent.getName();
|
---|
358 | if (agentDescription == null || "Agent A".equals(agentDescription) || "Agent B".equals(agentDescription))
|
---|
359 | agentDescription = agent.getClass().getSimpleName();
|
---|
360 |
|
---|
361 | return agentDescription;
|
---|
362 | }
|
---|
363 |
|
---|
364 | /**
|
---|
365 | * Show a dialog to the user, explaining the exception that was raised while
|
---|
366 | * loading file fc. Typically this is used in combination with
|
---|
367 | * {@link #loadObject(String)} and associates. Also dumps a copy of the full
|
---|
368 | * stacktrace to the console, to help us debugging #906
|
---|
369 | *
|
---|
370 | * @param fc
|
---|
371 | * file that was attempted to be loaded
|
---|
372 | * @param e
|
---|
373 | * the exception that was raised
|
---|
374 | */
|
---|
375 | public static void showLoadError(File fc, Throwable e) {
|
---|
376 | e.printStackTrace();
|
---|
377 | if (e instanceof ClassNotFoundException) {
|
---|
378 | showLoadError("No class found at " + fc, e);
|
---|
379 | } else if (e instanceof InstantiationException) {
|
---|
380 | // happens when object instantiated is interface or abstract
|
---|
381 | showLoadError(
|
---|
382 | "Class cannot be instantiated. Reasons may be that there is no constructor without arguments, "
|
---|
383 | + "or the class is abstract or an interface.",
|
---|
384 | e);
|
---|
385 | } else if (e instanceof IllegalAccessException) {
|
---|
386 | showLoadError("Missing constructor without arguments", e);
|
---|
387 | } else if (e instanceof NoClassDefFoundError) {
|
---|
388 | showLoadError("Errors in loaded class.", e);
|
---|
389 | } else if (e instanceof ClassCastException) {
|
---|
390 | showLoadError("The loaded class seems to be of the wrong type. ", e);
|
---|
391 | } else if (e instanceof IllegalArgumentException) {
|
---|
392 | showLoadError("The given file can not be used.", e);
|
---|
393 | } else if (e instanceof IOException) {
|
---|
394 | showLoadError("The file can not be read.", e);
|
---|
395 | } else {
|
---|
396 | showLoadError("Something went wrong loading the file", e);
|
---|
397 | }
|
---|
398 | }
|
---|
399 |
|
---|
400 | /*
|
---|
401 | * show error while loading agent file. Also show the detail message.
|
---|
402 | */
|
---|
403 | private static void showLoadError(String text, Throwable e) {
|
---|
404 | String message = e.getMessage();
|
---|
405 | if (message == null) {
|
---|
406 | message = "";
|
---|
407 | }
|
---|
408 |
|
---|
409 | JOptionPane.showMessageDialog(null, text + "\n" + message, "Load error", 0);
|
---|
410 | }
|
---|
411 |
|
---|
412 | /**
|
---|
413 | * @return the agentsLoader
|
---|
414 | */
|
---|
415 | private static String getLoadDate() {
|
---|
416 | // (2) createFrom our "formatter" (our custom format)
|
---|
417 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss");
|
---|
418 |
|
---|
419 | // (3) createFrom a new String in the format we want
|
---|
420 | String name = formatter.format(loadDate);
|
---|
421 |
|
---|
422 | return name;
|
---|
423 | }
|
---|
424 |
|
---|
425 | public static String getOutcomesFileName() {
|
---|
426 | if (!logPreset.equals("")) {
|
---|
427 | return logPreset;
|
---|
428 | }
|
---|
429 | if (!logPrefix.equals(""))
|
---|
430 | return logPrefix + "log.xml";
|
---|
431 |
|
---|
432 | return "log/" + getLoadDate() + getPostFix() + ".xml";
|
---|
433 | }
|
---|
434 |
|
---|
435 | public static String getDistributedOutcomesFileName() {
|
---|
436 | return "log/DT-" + getLoadDate() + getPostFix() + ".xml";
|
---|
437 | }
|
---|
438 |
|
---|
439 | public static String getTournamentOutcomeFileName() {
|
---|
440 | return "log/TM-" + getLoadDate() + getPostFix() + ".xml";
|
---|
441 | }
|
---|
442 |
|
---|
443 | public static String getExtensiveOutcomesFileName() {
|
---|
444 | if (!logPrefix.equals(""))
|
---|
445 | return logPrefix + "extensive_log.xml";
|
---|
446 | return "log/extensive " + getLoadDate() + getPostFix() + ".xml";
|
---|
447 | }
|
---|
448 |
|
---|
449 | public static String getOQMOutcomesFileName() {
|
---|
450 | return "log/OQM " + getLoadDate() + getPostFix() + ".csv";
|
---|
451 | }
|
---|
452 |
|
---|
453 | private static String getPostFix() {
|
---|
454 | String postFix = "";
|
---|
455 | if (TournamentConfiguration.getBooleanOption("appendModeAndDeadline", false)) {
|
---|
456 | String mode = "time";
|
---|
457 | if (TournamentConfiguration.getBooleanOption("protocolMode", false)) {
|
---|
458 | mode = "rounds";
|
---|
459 | }
|
---|
460 | postFix += "_" + mode + "_" + TournamentConfiguration.getIntegerOption("deadline", 180);
|
---|
461 | }
|
---|
462 | return postFix;
|
---|
463 | }
|
---|
464 |
|
---|
465 | /**
|
---|
466 | * @param classname
|
---|
467 | * @return Removes trailing ".class" from string if it is there. In absolute
|
---|
468 | * paths, the \ and / are replaced with '.' and we do as if that is
|
---|
469 | * a fully specified class path (it isn't but it gives at least some
|
---|
470 | * 'short name')
|
---|
471 | */
|
---|
472 | public static String nameOfClass(String classname1) {
|
---|
473 | // FIXME can we use class.forName.getShortName?
|
---|
474 | String classname = classname1.replaceAll("\\W", ".");
|
---|
475 | if (classname.endsWith(".class")) {
|
---|
476 | classname = classname.substring(0, classname.length() - 6);
|
---|
477 | }
|
---|
478 | return classname;
|
---|
479 | }
|
---|
480 |
|
---|
481 | /**
|
---|
482 | * @param classname
|
---|
483 | * @return Removes trailing ".class" from string if it is there. If there is
|
---|
484 | * no "." in the remainder, the remainder is returned. Otherwise,
|
---|
485 | * the string after the last "." in the remainder is returned. In
|
---|
486 | * absolute paths, the \ and / are replaced with '.' and we do as if
|
---|
487 | * that is a fully specified class path (it isn't but it gives at
|
---|
488 | * least some 'short name')
|
---|
489 | */
|
---|
490 | public static String shortNameOfClass(String classname1) {
|
---|
491 | String classname = nameOfClass(classname1);
|
---|
492 | if (!(classname.contains(".")))
|
---|
493 | return classname;
|
---|
494 | return classname.substring(classname.lastIndexOf(".") + 1);
|
---|
495 | }
|
---|
496 |
|
---|
497 | }
|
---|