As part of my Final Year Project I've developed a desktop application, which fits in the category of the "graphical IDE" if such a thing exists. I've implemented a little subset of Jessy James Garrett Visual Vocabulary for Information Architecture and Interaction Design, so the user can draw a diagram (a directed graph in other words) representing the user's experience in a webapp, assign HTML templates to pages and write some code to a connector/transition that will be executed, once the application is compiled and the user clicks the corresponding hyperlink.
(I can't post more than one hyperlink, but I'm referring to pages and connectors like the Elements of User Experience described in JJG's Visual Vocabulary)
So I'm using a different SwingWorkers to generate a set of C++ source files in which the diagram gets translated into. Looking at the logs, I see that my app is always creating new threads, instead of reusing them.
15:29:55.750 [SwingWorker-pool-2-thread-26] DEBUG i.v.a.ui.worker.ConnectorGenerator - Building source code for transition: connector_29
15:29:55.750 [SwingWorker-pool-2-thread-26] DEBUG i.v.a.ui.worker.ConnectorGenerator - Project retrieved: sasdasdasd
15:29:55.750 [SwingWorker-pool-2-thread-26] INFO i.v.a.webapp.htcpp.CTransition - Generated C:\Workspaces\PFC\aedifico-ui\sasdasdasd\connector_29_action.h...
15:29:55.750 [SwingWorker-pool-2-thread-26] INFO i.v.a.webapp.htcpp.CTransition - Generated C:\Workspaces\PFC\aedifico-ui\sasdasdasd\connector_29_action.cpp...
15:29:55.750 [SwingWorker-pool-2-thread-26] DEBUG i.v.a.ui.worker.ConnectorGenerator - Transition generated at: C:\Workspaces\PFC\aedifico-ui\sasdasdasd/connector_29_action.cpp
All my workers do the same two things:
Generate a pair of C++ source and header files using Freemarker template engine.
Send messages to the
EDT
through the publish-process mechanism to inform the user how things are going.
I believe I've coded the SwingWorker
s carefully. I was especially worried about the FileWriter instances not being closed as expected, but I can't see the reason the ThreadPoolExecutor
is not reusing the threads it previously created.
The magic happens in the ConnectorGenerator
. The BaseWorker
extends SwingWorker<V,T>
and just holds the behaviour to communicate to a component to display the messages to the user.
public class ConnectorGenerator<Void> extends BaseWorker<Void> {
@Override
public Void doInBackground() {
Transition transition = connector.getModel().getTransition();
logger.debug("Building source code for transition: {}", transition.getName());
logger.debug("Project retrieved: {}", project.getName());
try {
publish("Generating transition (%s) source code at %s", transition.getName(), project.getBaseDir());
/**
* Transition.build(String), attached below, is responsible of generating and writing the files
*/
transition.build(project.getBaseDir().getPath());
publish("Transition generated.");
} catch (BuilderException e) {
logger.error("Error: {}", e);
publish("There was an error that prevented generating %s's source code", transition.getName());
}
logger.debug("Transition generated at: {}/{}", project.getBaseDir(), transition.getSource());
return null;
}
}
And the Transition.build(String)
method, including an ugly-as-hell try-catch-finally block:
@Override
public void build(String path) throws BuilderException {
generateFile(String.format("%s%s%s", path, File.separator, getHeader()), "action.h.ftl");
generateFile(String.format("%s%s%s", path, File.separator, getSource()), "action.cpp.ftl");
}
private void generateFile(String path, String templateName) throws BuilderException {
FileWriter out = null;
try {
Map<String, Object> model = new HashMap<String, Object>();
model.put("transition", this);
Configuration config = new Configuration();
config.setClassForTemplateLoading(CTransition.class, "/");
config.setObjectWrapper(ObjectWrapper.DEFAULT_WRAPPER);
out = new FileWriter(path);
freemarker.template.Template template = config.getTemplate(templateName);
template.process(model, out, ObjectWrapper.BEANS_WRAPPER);
stdout.info("Generated {}...", path);
} catch (IOException e) {
throw new BuilderException(e);
} catch (TemplateException e) {
throw new BuilderException(e);
} finally {
if (out != null)
try {
out.flush();
out.close();
} catch (IOException e) {
throw new BuilderException(e);
}
}
}
Does anyone see or knows something I'm probably missing?