Source code
/*
* Copyright 2004 Francois Guillet
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
package artofillusion.spmanager;
import artofillusion.*;
import artofillusion.util.SearchlistClassLoader;
import artofillusion.ui.*;
import java.awt.*;
import java.awt.event.*;
import buoy.event.*;
import buoy.widget.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
/**
* The Plugin corresponding to the SPManager
*
*@author Francois Guillet
*@created 20 march 2004
*/
public class SPManagerPlugin implements Plugin
{
public static String AOI_VERSION;
public static String UNIQUE_PATH;
public static String TEMP_DIR;
public static String APP_DIRECTORY;
public static String PLUGIN_DIRECTORY;
public static String TOOL_SCRIPT_DIRECTORY;
public static String OBJECT_SCRIPT_DIRECTORY;
public static String STARTUP_SCRIPT_DIRECTORY;
public static final int DOWNLOAD = -1;
private static SPManagerFrame spmFrame;
protected static HashMap plugins;
/**
* Description of the Method
*
*@param message Description of the Parameter
*@param args Description of the Parameter
*/
public void processMessage( int message, Object args[] )
{
// NTJ: get the AOI run-time (*not* compile-time) version
if (AOI_VERSION == null) {
AOI_VERSION = ArtOfIllusion.getMajorVersion();
System.setProperty("artofillusion.version", ArtOfIllusion.getVersion());
System.setProperty("artofillusion.version.major", ArtOfIllusion.getMajorVersion());
}
switch (message) {
case Plugin.APPLICATION_STARTING:
SPMTranslate.setLocale(ArtOfIllusion.getPreferences().getLocale());
APP_DIRECTORY = ArtOfIllusion.APP_DIRECTORY;
PLUGIN_DIRECTORY = ArtOfIllusion.PLUGIN_DIRECTORY;
TOOL_SCRIPT_DIRECTORY = ArtOfIllusion.TOOL_SCRIPT_DIRECTORY;
OBJECT_SCRIPT_DIRECTORY = ArtOfIllusion.OBJECT_SCRIPT_DIRECTORY;
STARTUP_SCRIPT_DIRECTORY = ArtOfIllusion.STARTUP_SCRIPT_DIRECTORY;
System.out.println("SPManager starting...");
// get details of plugin classloaders
int i, j, idx;
URL urlList[];
ArrayList aoiloaders;
ClassLoader ldr = null;
URLClassLoader urlldr = null;
SearchlistClassLoader searchldr = null;
Object obj;
java.util.List list = PluginRegistry.getPluginClassLoaders();
HashMap loaders = new HashMap(list.size());
for (i = 0; i < list.size(); i++) {
obj = list.get(i);
if (obj instanceof URLClassLoader)
urlList = ((URLClassLoader) obj).getURLs();
else
urlList = ((SearchlistClassLoader) obj).getURLs();
if (urlList.length > 0)
loaders.put(urlList[0], obj);
}
/*
try {
Field ldrfield =
PluginRegistry.class.getDeclaredField("pluginLoaders");
ldrfield.setAccessible(true);
aoiloaders = (ArrayList) ldrfield.get(null);
} catch (Exception e) {
System.out.println("SPManager: cannot get pluginsLoaders: " +
e);
aoiloaders = new ArrayList();
}
*/
URL[] urlarg = new URL[1];
Class[] sig = new Class[] { URL.class };
Method addUrl = null;
try {
addUrl =
URLClassLoader.class.getDeclaredMethod("addURL", sig);
addUrl.setAccessible(true);
} catch (Exception e) {
System.out.println("Error getting addURL method: " + e);
}
// get details of all local plugins
SPMObjectInfo info;
StringBuffer errs = null;
Class plugType;
File files[], urlfile;
URL url;
Map.Entry entry;
String key[], value;
File plugdir = new File(PLUGIN_DIRECTORY);
if (plugdir.exists()) {
files = plugdir.listFiles();
for (i = 0; i < files.length; i++) {
info = new SPMObjectInfo(files[i].getAbsolutePath());
if (info.invalid) {
if (errs == null) errs = new StringBuffer(1024);
if (errs.length() > 0) errs.append('\n');
errs.append(SPMTranslate.text("pluginFailure",
info.getName()));
}
if (info.actions != null && info.actions.size() > 0) {
try {
url = files[i].toURI().toURL();
} catch (Exception e) {
continue;
}
//System.out.println("SPM: url=" + url);
// get the classloader for the current plugin
obj = loaders.get(url);
if (obj == null) {
System.out.println("SPManager: could not find"
+ " classloader: "
+ files[i].getPath());
continue;
}
// cast or convert it to a SearchlistClassLoader
if (obj instanceof SearchlistClassLoader) {
searchldr = (SearchlistClassLoader) obj;
//System.out.println("loader is a srchloader");
}
else {
urlldr = (URLClassLoader) obj;
/*
searchldr =
new SearchlistClassLoader((ClassLoader) obj);
idx = aoiloaders.indexOf(obj);
if (idx >= 0) aoiloaders.set(idx, searchldr);
else System.out.println("SPM: loader not in list");
loaders.put(url, searchldr);
*/
}
// ok, now perform the actions
for (Iterator iter = info.actions.entrySet().iterator();
iter.hasNext(); ) {
entry = (Map.Entry) iter.next();
key = entry.getKey().toString().split(":");
//System.out.println("SPM: action=" +
// entry.getValue().toString());
try {
if (key[0].startsWith("/"))
urlfile = new File(APP_DIRECTORY, key[0].substring(1));
else
urlfile = new File(plugdir, key[0]);
url = urlfile.toURI().toURL();
} catch (Exception e) {
System.out.println("Error making url: " + e);
continue;
}
System.out.println("SPM: adding path: " + url);
value = entry.getValue().toString();
/*
if ("merge".equalsIgnoreCase(value)) {
if (searchldr != null)
searchldr.merge(url);
else if (addUrl != null) {
try {
urlarg[0] = url;
addUrl.invoke(urlldr, urlarg);
} catch (Exception e) {
System.out.println("Error invoking: "
+ e);
}
}
else System.out.println("Could not merge path"
+ url);
}
*/
if ("classpath".equalsIgnoreCase(value)) {
if (searchldr != null)
searchldr.add(url);
else if (addUrl != null) {
try {
//urlarg[0] = url;
//addUrl.invoke(urlldr, urlarg); // non-varargs call (1.4)
addUrl.invoke(urlldr, url); // varargs call (1.5)
} catch (Exception e) {
System.out.println("Error invoking: "
+ e);
}
}
else System.out.println("Could not add path" +
url);
}
else if ("import".equalsIgnoreCase(value)) {
ldr = (ClassLoader) loaders.get(url);
if (key.length == 1) {
if (obj != null) searchldr.add(ldr);
else System.out.println("SPM: could not find"
+ " loader for: " + url);
}
/*
* NTJ - disabled. No longer needed, and requires a new method in SearchlistClassLoader
*
else {
System.out.println("SPM: importing: " + key[1]);
if (searchldr != null) {
try {
searchldr.add(ldr.loadClass(key[1]));
} catch (Exception e) {
System.out.println("SPM: Error importing class: " + key[1] + " into " + url);
}
}
else {
System.out.println("SPM: Error: Class cannot be imported without a SearchListClassLoader: " + url
+ "(" + key[1] + ")");
}
}
*/
}
}
}
}
if (errs != null) {
BTextArea txt = new BTextArea(5, 45);
txt.setEditable(false);
txt.append(errs.toString());
BScrollPane detail =
new BScrollPane(txt, BScrollPane.SCROLLBAR_NEVER,
BScrollPane.SCROLLBAR_AS_NEEDED);
BLabel messg = SPMTranslate.bLabel("loadError");
new BStandardDialog("SPManager initialise",
new Widget[] { messg, detail },
BStandardDialog.ERROR)
.showMessageDialog(null);
}
}
else System.out.println("SPManager: could not find plugin dir: " +
PLUGIN_DIRECTORY);
init();
break;
case Plugin.SCENE_WINDOW_CREATED:
{
LayoutWindow layout = (LayoutWindow) args[0];
//BMenuBar menuBar = layout.getMenuBar();
//BMenu toolsMenu = menuBar.getChild( 3 );
BMenu toolsMenu = layout.getToolsMenu();
toolsMenu.addSeparator();
BMenuItem menuItem =
SPMTranslate.bMenuItem( "SPManager", this, "doMenu" );
toolsMenu.add( menuItem );
}
break;
case APPLICATION_STOPPING:
break;
case DOWNLOAD:
{
System.out.println("DOWNLOAD...");
BFrame frame = (BFrame) args[0];
URL from = (URL) args[1];
URL to = (URL) (args.length > 2 ? args[2] : null);
download(frame, from, to);
}
break;
default:
//System.out.println("SPManagerPlugin: ignoringmessage: " + message);
}
}
/**
* initialise the plugin
*/
public void init()
{
ArrayList err = new ArrayList(8);
System.out.println("SPManager: java temp dir is " +
System.getProperty("java.io.tmpdir"));
// try system TEMP directory
File temp = new File(System.getProperty("java.io.tmpdir"));
// try 'temp' in AOI installation directory
if (! ((temp.exists() && temp.isDirectory()) || temp.mkdir())) {
System.out.println("SPManager: could not open/create temp dir: " +
temp.getAbsolutePath());
temp = new File(APP_DIRECTORY, "temp");
}
// try 'SPtemp' in user's home directory
if (! ((temp.exists() && temp.isDirectory()) || temp.mkdir())) {
System.out.println("Cannot create temp folder: " +
temp.getAbsolutePath());
temp = new File(System.getProperty("user.dir"), "SPMtemp");
}
if (! ((temp.exists() && temp.isDirectory()) || temp.mkdir())) {
err.add("Cannot create temp folder: " +
temp.getAbsolutePath());
}
if (!temp.canWrite())
err.add("Write permission denied to temp folder: " +
temp.getAbsolutePath());
// create temporary private sub-tree
String path;
File t = null;
try {
t = File.createTempFile("spmanager-temp-"
+ System.getProperty("user.name") + "-", ".lck", temp);
t.deleteOnExit();
path= t.getName();
path = path.substring(0, path.length()- ".lck".length());
} catch (Exception e) {
// failed to create temp file, use fallback naming algorithm
System.out.println("SPManager: could not create temp file: " +
t.getAbsolutePath() + e);
path = System.getProperty("user.name") + "-"
+ String.valueOf(System.currentTimeMillis());
}
temp = new File(temp, path);
if (! ((temp.exists() && temp.isDirectory()) || temp.mkdir())) {
err.add("Cannot create temp folder: " +
temp.getAbsolutePath());
}
if (!temp.canWrite())
err.add("Write permission denied to temp folder: " +
temp.getAbsolutePath());
TEMP_DIR = temp.getAbsolutePath();
System.out.println("SPManager: temp dir set to: " +
temp.getAbsolutePath());
// make sure all temp directories are created
File subfolder = new File(PLUGIN_DIRECTORY);
temp = new File(TEMP_DIR, subfolder.getName());
if (!temp.exists() && !temp.mkdirs())
err.add("Cannot create temp plugin folder: " +
temp.getAbsolutePath());
subfolder = new File(TOOL_SCRIPT_DIRECTORY);
temp = new File(TEMP_DIR, subfolder.getName());
if (!temp.exists() && !temp.mkdirs())
err.add("Cannot create temp script folder: " +
temp.getAbsolutePath());
subfolder = new File(OBJECT_SCRIPT_DIRECTORY);
temp = new File(TEMP_DIR, subfolder.getName());
if (!temp.exists() && !temp.mkdirs())
err.add("Cannot create temp script folder: " +
temp.getAbsolutePath());
subfolder = new File(STARTUP_SCRIPT_DIRECTORY);
temp = new File(TEMP_DIR, subfolder.getName());
if (!temp.exists() && !temp.mkdirs ())
err.add("Cannot create temp script folder: " +
temp.getAbsolutePath());
// make sure all live directories exist
temp = new File(PLUGIN_DIRECTORY);
if (!temp.exists() && !temp.mkdir())
err.add("Cannot create missing plugin folder: " +
temp.getAbsolutePath());
temp = new File(TOOL_SCRIPT_DIRECTORY);
if (!temp.exists() && !temp.mkdirs())
err.add("Cannot create missing script folder: " +
temp.getAbsolutePath());
temp = new File(OBJECT_SCRIPT_DIRECTORY);
if (!temp.exists() && !temp.mkdirs())
err.add("Cannot create missing script folder: " +
temp.getAbsolutePath());
temp = new File(STARTUP_SCRIPT_DIRECTORY);
if (!temp.exists() && !temp.mkdirs ())
err.add("Cannot create missing script folder: " +
temp.getAbsolutePath());
if (err.size() > 0) {
BTextArea txt = new BTextArea(5, 45);
txt.setEditable(false);
for (int i = 0; i < err.size(); i++)
txt.append(err.get(i) + "\n");
BScrollPane detail =
new BScrollPane(txt, BScrollPane.SCROLLBAR_NEVER,
BScrollPane.SCROLLBAR_AS_NEEDED);
BLabel messg = SPMTranslate.bLabel("errMsg");
new BStandardDialog("SPManager initialise",
new Widget[] { messg, detail },
BStandardDialog.WARNING)
.showMessageDialog(null);
}
}
public void registerResource(String type, String id, ClassLoader loader,
String baseName, Locale locale)
{
String suffix = "";
if (locale.getLanguage().length() > 0)
suffix += "_" + locale.getLanguage();
if (locale.getCountry().length() > 0)
suffix += "_" + locale.getCountry();
if (locale.getVariant().length() > 0)
suffix += "_" + locale.getVariant();
URL url;
int cut;
for (int i = 0; i < 3; i++) {
try {
url = loader.getResource(baseName + suffix + ".properties");
if (url != null) {
PluginRegistry.registerResource(type, id, loader,
url.getPath(), locale);
break;
}
} catch (Exception e) {}
// can we remove part of the suffix?
cut = suffix.lastIndexOf('_');
if (cut > 0) suffix = suffix.substring(0, cut);
else break;
}
}
public void download(BFrame frame, URL from)
{ download(frame, from, null); }
/**
* download (and install if possible) the specified file(set).
*/
public void download(BFrame frame, URL from, URL to)
{
final BFrame context = frame;
final URL url = from;
final URL toUrl = to;
final StatusDialog status = new StatusDialog(context) {
SPMObjectInfo info;
BLabel size;
BButton okbtn;
String filename, name;
ColumnContainer col;
RowContainer buttons;
BTextField savePath;
Thread worker;
public void setVisible(boolean vis)
{
if (!vis) {
super.setVisible(vis);
return;
}
col = (ColumnContainer) getContent();
filename = url.getFile();
int cut = filename.lastIndexOf('/');
if (cut > 0 && cut < filename.length())
filename = filename.substring(cut+1);
cut = filename.lastIndexOf('?');
if (cut > 0)
filename = filename.substring(0, cut);
name = new String(filename);
cut = name.lastIndexOf('.');
if (cut > 0) name = name.substring(0, cut);
setText(name);
setProgressText(SPMTranslate.text("clickStart"));
okbtn = SPMTranslate.bButton("start", this, "ok");
buttons = new RowContainer();
buttons.add(okbtn);
buttons.add(SPMTranslate.bButton("cancel", this, "close"));
okbtn.setActionCommand("ok");
col.add(buttons);
pack();
super.setVisible(true);
}
public void close()
{
if (worker != null) worker.interrupt();
doClose();
}
public void ok(CommandEvent ev)
{
String cmd = ev.getActionCommand();
okbtn.setEnabled(false);
final BButton okbut = okbtn;
final StatusDialog stat = this;
if (cmd.equals("ok")) {
setProgressText(SPMTranslate.text("contacting"));
setIdle(true);
System.out.println("DOWNLOAD: creating ObjectInfo..."+
url.toString());
worker = new Thread() {
public void run()
{
info = new SPMObjectInfo(url);
if (info.length == 0) {
System.out.println("DOWNLOAD: no info");
info.length = info.getRemoteFileSize(url.toString());
}
/* NTJ: don't give up yet...
*
if (info.length < 0) {
new BStandardDialog("SPManager", SPMTranslate.text("httpError"), BStandardDialog.ERROR).showMessageDialog(null);
doClose();
}
*/
// get destination if needed
if (info.name == null
|| info.name.length() == 0) {
System.out.println("need path...");
RowContainer row = new RowContainer();
row.add(SPMTranslate.bLabel("savePath"));
savePath = new BTextField("", 25);
savePath.addEventLink(ValueChangedEvent.class, this, "savePath");
row.add(savePath);
row.add(SPMTranslate.bButton("browse",
this,
"browse"));
col.remove(buttons);
col.add(row);
col.add(buttons);
pack();
}
long total = info.getTotalLength();
String sz = (total > 1000000
? " " +
(total/1000000)
+ " MB"
: total > 1000
? " " + (total/1000)
+ " kB"
: (total > 0)
? " " + total
+ " bytes"
: "");
setText(info.getName() + " " + sz);
setIdle(false);
setProgressText(SPMTranslate.text("ready"));
okbut.setActionCommand("install");
okbut.setText(SPMTranslate.text("install"));
okbut.setEnabled(true);
pack();
}
public void savePath()
{
String val = savePath.getText();
okbtn.setEnabled(val != null && val.length() > 0);
}
public void browse()
{
BFileChooser fc = new
BFileChooser(BFileChooser.SAVE_FILE,
Translate.text("savePath"));
File file = null;
String path = null;
String fname = savePath.getText();
if (fname == null || fname.length() == 0) {
path = System.getProperty("user.home");
fname = filename;
}
if (fname != null) {
if (path != null)
file = new File(path, fname);
else
file = new File(fname);
fc.setDirectory(file.getParentFile());
fc.setSelectedFile(file);
}
else fc.setDirectory(new File(path));
if (fc.showDialog(context)) {
savePath.setText(fc.getSelectedFile().getAbsolutePath());
}
}
};
worker.start();
}
else if (cmd.equals("install")) {
System.out.println("DOWNLOAD: downloading " +
url.toString());
setText(SPMTranslate.text("downloading", info.getName()));
pack();
final ArrayList errs = new ArrayList();
worker = new Thread() {
public void run()
{
long total = info.getTotalLength();
// full save path
String path = null;
if (savePath != null)
path = savePath.getText();
else if (info.name != null)
path = ArtOfIllusion.PLUGIN_DIRECTORY + File.separatorChar + info.name + ".jar";
if (path == null || path.length() == 0) {
System.out.println("DOWNLOAD: no save location");
new BStandardDialog("SPManager", SPMTranslate.text("noSaveLocation"), BStandardDialog.ERROR).showMessageDialog(null);
doClose();
}
System.out.println("DOWNLOAD: downloading file...");
if (total > 0)
setBarValue(total > 0 ? 0 : -1);
long dl = HttpSPMFileSystem
.downloadRemoteBinaryFile(url, path, info.length, stat, total, 0, errs);
for (int i = 0; info.files != null && i < info.files.length; i++) {
if (worker.interrupted()) {
doClose();
return;
}
name = PLUGIN_DIRECTORY + File.separatorChar + info.destination.get(i) + info.files[i];
setText(SPMTranslate.text("downloading", info.files[i]));
pack();
dl += HttpSPMFileSystem
.downloadRemoteBinaryFile(info.getAddFileURL(i), name, info.fileSizes[i], stat, total, dl, errs);
}
if (errs != null && errs.size() > 0)
InstallSplitPane.showErrors(errs);
else
new BStandardDialog("SPManager", SPMTranslate.text("modified"), BStandardDialog.ERROR).showMessageDialog(null);
System.out.println("DOWNLOAD: done");
doClose();
}
};
worker.start();
}
else System.out.println("?? cmd=" + cmd);
}
};
}
/**
* Description of the Method
*/
public void doMenu()
{
// NTJ: don't implement yet... (Nov 2006)
//if (!Translate.getLocale().equals(Locale.getDefault())) {
//}
if ( spmFrame == null )
spmFrame = new SPManagerFrame();
( (Window) spmFrame.getComponent() ).toFront();
//spmFrame.layoutChildren();
( (Window) spmFrame.getComponent() ).show();
//spmFrame.printBounds( spmFrame );
}
/**
* restart the plugin
*/
public static void restart()
{
SPManagerFrame old = spmFrame;
spmFrame = new SPManagerFrame();
((Window) spmFrame.getComponent()).toFront();
((Window) spmFrame.getComponent()).show();
old.dispose();
}
/**
* close the frame
*/
public void close()
{
if (spmFrame != null) {
spmFrame.setVisible(false);
spmFrame.dispose();
}
}
/**
* Gets the name attribute of the SPManagerPlugin object
*
*@return The name value
*/
public String getName()
{
return "Script and Plugin Manager";
}
/**
* Gets the frame attribute of the SPManagerPlugin class
*
*@return The frame value
*/
public static SPManagerFrame getFrame()
{
return spmFrame;
}
/**
* update an already-loaded plugin
*/
public static void updatePlugin(String name, String action, String target)
{
}
/**
* main routine so SPManager can be run standalone
*/
public static void main(String[] argv)
{
char slash = File.separatorChar;
APP_DIRECTORY = System.getProperty("user.dir");
try {
URL url = SPManagerPlugin.class
.getResource("/artofillusion/spmanager/SPManagerPlugin.class");
System.out.println("SPManager.main: url=" + url);
System.out.println("SPManager.main: path=" + url.getPath());
String furl = url.getPath();
if (furl.indexOf('!') < 0) furl = url.toString();
int cut = furl.indexOf('!');
if (cut > 0) {
furl = furl.substring(0, cut);
cut = furl.indexOf("jar:");
if (cut >= 0)
furl = furl.substring(cut+"jar:".length());
if (!furl.startsWith("file:")) furl = "file:" + furl;
System.out.println("SPManager.main: furl=" + furl);
File dir = new File(new URL(furl).getPath()).getParentFile()
.getParentFile();
System.out.println("SPManager.main: dir=" +
dir.getAbsolutePath());
if (dir.exists())
APP_DIRECTORY = dir.getAbsolutePath();
else
APP_DIRECTORY = System.getProperty("user.dir");
System.out.println("SPManager.main: app_dir=" + APP_DIRECTORY);
}
}
catch (Exception ex) {
System.out.println("Error looking up app_dir: " + ex);
}
SPMTranslate.setLocale(Locale.getDefault());
PLUGIN_DIRECTORY = APP_DIRECTORY + slash + "Plugins";
TOOL_SCRIPT_DIRECTORY = APP_DIRECTORY + slash + "Scripts" + slash + "Tools";
OBJECT_SCRIPT_DIRECTORY = APP_DIRECTORY + slash + "Scripts" + slash + "Objects";
STARTUP_SCRIPT_DIRECTORY = APP_DIRECTORY + slash + "Scripts" + slash + "Startup";
SPManagerPlugin spm = new SPManagerPlugin();
spm.init();
// create Frame with overridden 'close' method
spmFrame = new SPManagerFrame() {
protected void hideSPManager()
{
setVisible(false);
dispose();
}
};
spm.doMenu();
}
}
Run 1
The code has significant readability issues. The processMessage method is extremely long (200+ lines) with excessive nesting (up to 5-6 levels deep), making it very difficult to follow. Large blocks of commented-out code add to the confusion. Many variables have unclear names like 'i', 'j', 'idx', and 't'. Multiple actions are packed onto single lines in places, violating one-action-per-line. The control flow jumps around with try-catch blocks scattered throughout. While there is some logical structure (init, download methods are separated), the main message handler tries to do everything at once. Reading flow is severely compromised by the deep nesting and monolithic methods. There's a massive anonymous inner class (StatusDialog) spanning over 200 lines, making the download method practically unreadable. The code would benefit greatly from extraction into smaller, focused methods, removing dead code, and reducing nesting levels. The consistent indentation and comments are the only positive factors preventing a lower score.
Run 2
This code is poorly readable. The main method is a huge switch statement containing deeply nested loops, conditionals, and try-catch blocks, making the structure tangled. Nesting is excessive in processMessage, download, and init methods (often 4-5 levels deep). Intent is unclear due to large commented-out blocks, cryptic variable names (e.g., 'errs', 'obj', 't'), and mixed responsibilities. Code is unnecessarily long—many repetitive file/folder checks could be extracted into helper methods. Action granularity is poor: multiple operations per line are common, and many lines exceed typical length. Reading flow is disorganized, with scattered logic, dead/commented code, and inconsistent formatting. Overall, the code requires significant effort to navigate and understand.
Run 3
The code is highly unreadable. The processMessage method is an enormous switch statement containing deeply nested loops and conditionals, making it nearly impossible to follow the flow. Massive blocks of commented-out code add significant noise and confusion. There is a severe lack of modularity; methods like processMessage and download contain hundreds of lines of procedural logic handling many unrelated responsibilities (classloader manipulation, UI creation, network operations, temp directory management). The download method uses a large anonymous inner class that further compounds the nesting and obscures intent. Naming is somewhat generic (obj, t, path) and does not clarify purpose. The code relies heavily on side effects and global mutable state, obscuring data flow. While some comments explain intent, they are overshadowed by the tangled structure and excessive length of individual methods. The code requires significant refactoring into smaller, well-named, and focused methods/classes to achieve readability.
Run 1
Code Structure: Named methods provide some organization, but processMessage and download mix class loading, filesystem operations, UI construction, and threading in oversized blocks. Nesting: Deeply nested loops, conditionals, exception handlers, and anonymous classes make control flow difficult to track. Clarity of intent: Descriptive constants and some useful comments help, but abbreviated variables, raw collections, placeholder documentation, and extensive commented-out code obscure purpose. Code length: Repeated directory setup and error-dialog construction, obsolete code, and debug statements unnecessarily inflate the class. Action granularity: Most statements perform one action per line, although inline conditionals, grouped declarations, and compressed methods reduce consistency. Reading flow: Broad lifecycle phases are recognizable, but inconsistent indentation, long expressions, nested ternaries, and callbacks embedded inside worker threads repeatedly interrupt natural reading.
Run 2
Code Structure: Methods separate some lifecycle operations, but processMessage and download combine many responsibilities, including UI, class loading, networking, and error handling. Nesting: Deeply nested loops, conditionals, exception handlers, and anonymous classes make execution paths difficult to follow. Clarity of intent: Descriptive constants and some comments help, but abbreviated variables, raw collections, placeholder documentation, and disabled code obscure intent. Code length: Large methods, repeated directory-creation logic, extensive logging, and substantial commented-out blocks add unnecessary length. Action granularity: Most statements perform one action per line, although inline conditionals and grouped declarations reduce scanability. Reading flow: Broad startup and download sequences are recognizable, but inconsistent indentation, scattered state changes, reflection, and embedded asynchronous callbacks interrupt the flow. Small accessor and window-management methods are substantially easier to read than the core implementation.
Run 3
Code Structure: Named methods and event cases provide some organization, but large methods mix initialization, classloader manipulation, UI construction, and downloads. Nesting: Deeply nested loops, conditionals, exception handlers, and anonymous classes make execution paths difficult to follow. Clarity of intent: Descriptive constants and some useful comments help, but terse variables, raw collections, placeholder documentation, and obsolete commented-out code obscure intent. Code length: Excessive length, repeated directory setup, debugging output, and disabled code add substantial reading overhead. Action granularity: Most statements perform one action per line, although inline conditionals and grouped declarations reduce consistency. Reading flow: High-level lifecycle stages are recognizable, but inconsistent indentation, long expressions, nested ternaries, shared mutable state, and callback-based control flow repeatedly interrupt comprehension.