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