URL input) throws Exception {
if (input == null) {
// Create a blank effigy.
// Use the strategy pattern so derived classes can
// override this.
PtolemyEffigy effigy = _newEffigy(container, container
.uniqueName("effigy"));
// If this factory contains an entity called "blank", then
// clone that.
NamedObj entity = getEntity("blank");
Attribute attribute = getAttribute("blank");
NamedObj newModel;
if (entity != null) {
newModel = (NamedObj) entity.clone(new Workspace());
// The cloning process results an object that defers change
// requests. By default, we do not want to defer change
// requests, but more importantly, we need to execute
// any change requests that may have been queued
// during cloning. The following call does that.
newModel.setDeferringChangeRequests(false);
} else if (attribute != null) {
newModel = (NamedObj) attribute.clone(new Workspace());
// The cloning process results an object that defers change
// requests. By default, we do not want to defer change
// requests, but more importantly, we need to execute
// any change requests that may have been queued
// during cloning. The following call does that.
newModel.setDeferringChangeRequests(false);
} else {
newModel = new TypedCompositeActor(new Workspace());
}
// The model should have a parser associated with it
// so that undo works.
// Checking to see if there already is a _parser attribute
// might be overkill, but it is safer.
ParserAttribute parserAttribute = (ParserAttribute) newModel
.getAttribute("_parser", ParserAttribute.class);
if (parserAttribute == null) {
parserAttribute = new ParserAttribute(newModel, "_parser");
MoMLParser parser = new MoMLParser();
// Make sure that the MoMLParser._modified flag is reset
// If we don't call reset here, then the second time
// the code generator is run, we will be prompted to
// save the model because the first time we ran
// the code generator the model was marked as modified.
parser.reset();
parserAttribute.setParser(parser);
}
// The name might be "blank" which is confusing.
// Set it to an empty string. On Save As, this will
// be changed to match the file name.
newModel.setName("");
effigy.setModel(newModel);
// THALES MODIF
new Attribute(newModel, "_navigable");
if (!modelIsValid(newModel)) {
effigy.setContainer(null);
effigy = null;
}
//END THALES MODIF
return effigy;
} else {
String extension = getExtension(input);
if (!extension.equals("xml") && !extension.equals("moml")) {
return null;
}
// THALES MODIF
if (checkFile(input)) {
// Create a blank effigy.
PtolemyEffigy effigy = _newEffigy(container, container
.uniqueName("effigy"));
MoMLParser parser = new MoMLParser();
// Make sure that the MoMLParser._modified flag is reset
// If we don't call reset here, then the second time
// the code generator is run, we will be prompted to
// save the model because the first time we ran
// the code generator the model was marked as modified.
parser.reset();
NamedObj toplevel = null;
try {
try {
// If the following fails, we should remove the effigy.
try {
toplevel = parser.parse(base, input);
} catch (IOException io) {
// If we are running under Web Start, we
// might have a URL that refers to another
// jar file.
URL anotherURL = ClassUtilities
.jarURLEntryResource(input.toString());
if (anotherURL != null) {
toplevel = parser.parse(base, anotherURL);
} else {
throw io;
}
}
if (toplevel != null) {
effigy.setModel(toplevel);
// A MoMLFilter may have modified the model
// as it was being parsed.
effigy.setModified(MoMLParser.isModified());
// The effigy will handle saving the modified
// moml for us, so MoMLParser need
// not care anymore.
MoMLParser.setModified(false);
// Identify the URI from which the model was read
// by inserting an attribute into both the model
// and the effigy.
URIAttribute uriAttribute = new URIAttribute(
toplevel, "_uri");
URI inputURI = null;
try {
inputURI = new URI(input.toExternalForm());
} catch (java.net.URISyntaxException ex) {
// This is annoying, if the input has a space
// in it, then we cannot create a URI,
// but we could create a URL.
// If, under Windows, we call
// File.createTempFile(), then we are likely
// to get a pathname that has space.
// FIXME: Note that jar urls will barf if there
// is a %20 instead of a space. This could
// cause problems in Web Start
String inputExternalFormFixed = StringUtilities
.substitute(input.toExternalForm(),
" ", "%20");
try {
inputURI = new URI(
inputExternalFormFixed);
} catch (Exception ex2) {
throw new Exception(
"Failed to generate "
+ "a URI from '"
+ input
.toExternalForm()
+ "' and from '"
+ inputExternalFormFixed
+ "'", ex);
}
}
uriAttribute.setURI(inputURI);
// This is used by TableauFrame in its
//_save() method.
effigy.uri.setURI(inputURI);
return effigy;
} else {
effigy.setContainer(null);
}
} catch (Throwable throwable) {
if (throwable instanceof StackOverflowError) {
Throwable newThrowable = new StackOverflowError(
"StackOverflowError: "
+ "Which often indicates that a class "
+ "could not be found, but there was "
+ "possibly a moml file with that same "
+ "name in the directory that referred "
+ "to the class, so we got into a loop."
+ "For example: We had "
+ "actor/lib/joystick/Joystick.java "
+ "and "
+ "actor/lib/joystick/joystick.xml, "
+ "but "
+ "the .class file would not load "
+ "because of a classpath problem, "
+ "so we kept "
+ "loading joystick.xml which "
+ "referred to Joystick and because "
+ "of Windows "
+ "filename case insensitivity, "
+ "we found joystick.xml, which put "
+ "us in a loop.");
newThrowable.initCause(throwable);
throwable = newThrowable;
}
throwable.printStackTrace();
// The finally clause below can result in the
// application exiting if there are no other
// effigies open. We check for that condition,
// and report the error here. Otherwise, we
// pass the error to the caller.
ModelDirectory dir = (ModelDirectory) effigy
.topEffigy().getContainer();
List effigies = dir.entityList(Effigy.class);
// We might get to here if we are running a
// vergil with a model specified as a command
// line argument and the model has an invalid
// parameter.
// We might have three effigies here:
// 1) .configuration.directory.configuration
// 2) .configuration.directory.UserLibrary
// 3) .configuration.directory.effigy
// Note that one of the effigies is the configuration
// itself, which does not prevent exiting the app.
// Hence, we handle the error if there are 3 or fewer.
if (effigies.size() <= 3) {
// FIXME: This could cause problems with
// systems that do not load the user
// library. Currently, VergilApplication
// loads the user library, but other
// applications like PtolemyApplication do
// not. We could check to see if the
// names of two of the three Effigies were
// .configuration.directory.configuration
// and.configuration.directory.user
// library, but this seems like overkill.
String errorMessage = "Failed to read " + input;
System.err.println(errorMessage);
throwable.printStackTrace();
MessageHandler.error(errorMessage, throwable);
} else {
if (throwable instanceof Exception) {
// Let the caller handle the error.
throw (Exception) throwable;
} else {
// If we have a parameter that has a backslash
// then we might get a data.expr.TokenMgrError
// which is an error, so we rethrow this
// FIXME: createEffigy() should be
// declared to throw Throwable, but that
// results in lots of changes elsewhere.
throw new Exception(throwable);
}
}
}
} finally {
// If we failed to populate the effigy with a model,
// then we remove the effigy from its container.
if (toplevel == null) {
effigy.setContainer(null);
}
}
}
//END THALES MODIF