/** * Clone the library into the specified workspace. The new object is <i>not</i> added to the * directory of that workspace (you must do this yourself if you want it there). If the library * has not yet been populated, then the clone will also not have been populated. * * @param workspace The workspace for the cloned object. * @exception CloneNotSupportedException If the library contains level crossing transitions so * that its connections cannot be cloned, or if one of the attributes cannot be cloned. * @return A new LazyTypedCompositeActor. */ public Object clone(Workspace workspace) throws CloneNotSupportedException { // To prevent populating during cloning, we set a flag. _cloning = true; try { LazyTypedCompositeActor result = (LazyTypedCompositeActor) super.clone(workspace); // There may or may not be configure text, but it won't be the // same as what we are cloning (instantiating) from. result._base = null; result._configureDone = false; result._populating = false; result._configureSource = null; result._configureText = null; result._cloning = false; return result; } finally { _cloning = false; } }
/** * Populate the actor by reading the file specified by the <i>source</i> parameter. Note that the * exception thrown here is a runtime exception, inappropriately. This is because execution of * this method is deferred to the last possible moment, and it is often evaluated in a context * where a compile-time exception cannot be thrown. Thus, extra care should be exercised to * provide valid MoML specifications. * * @exception InvalidStateException If the source cannot be read, or if an exception is thrown * parsing its MoML data. */ public void populate() throws InvalidStateException { boolean resetPolulatingValue = false; try { if (_populating) { resetPolulatingValue = true; return; } // Avoid populating during cloning. if (_cloning) { return; } // Do not populate if this is a derived object. // Instead, populate the object is this is derived // from, which will have the side effect of populating // this object. if (getDerivedLevel() != Integer.MAX_VALUE) { // Object is derived. Delegate to the most remote // prototype. List prototypes = getPrototypeList(); if (prototypes == null || prototypes.size() == 0) { throw new InternalErrorException( getFullName() + ": Object says it is derived but reports no prototypes!"); } // The prototype must have the same class as this. LazyTypedCompositeActor prototype = (LazyTypedCompositeActor) prototypes.get(prototypes.size() - 1); prototype.populate(); return; } _populating = true; if (!_configureDone) { // NOTE: If you suspect this is being called prematurely, // the uncomment the following to see who is doing the // calling. // System.out.println("-----------------------"); // (new Exception()).printStackTrace(); // NOTE: Set this early to prevent repeated attempts to // evaluate if an exception occurs. This way, it will // be possible to examine a partially populated entity. _configureDone = true; // NOTE: This does not seem like the right thing to do! // removeAllEntities(); // If we have a subclass that has LazyTypedCompositeActor // in it, then things get tricky. See // actor/lib/test/auto/LazySubClassModel.xml // If this is an instance or subclass of something, that // something must also be a LazyTypedCompositeActor and // it should be populated first. if (getParent() != null) { ((LazyTypedCompositeActor) getParent()).populate(); } // We were getting ConcurrentModifications because // when we instantiate and call // NamedObj._markContentsDerived() we end up // eventually calling populate(), which calls // parse(URL, String, Reader) and adds a // ParserAttribute, which results in a // ConcurrentModificationException MoMLParser parser = new MoMLParser(workspace()); // If we get the parser from ParserAttribute, then // after we call parse(), MoMLParser._xmlParser gets // set to null, which causes problems for the calling // parse() method. // NamedObj toplevel = toplevel(); // MoMLParser parser = ParserAttribute.getParser(toplevel); parser.setContext(this); List savedFilters = MoMLParser.getMoMLFilters(); try { MoMLParser.setMoMLFilters(null); if ((_configureSource != null) && !_configureSource.equals("")) { URL xmlFile = new URL(_base, _configureSource); parser.parse(xmlFile, xmlFile); } if ((_configureText != null) && !_configureText.equals("")) { // NOTE: Regrettably, the XML parser we are using cannot // deal with having a single processing instruction at the // outer level. Thus, we have to strip it. String trimmed = _configureText.trim(); if (trimmed.startsWith("<?") && trimmed.endsWith("?>")) { trimmed = trimmed.substring(2, trimmed.length() - 2).trim(); if (trimmed.startsWith("moml")) { trimmed = trimmed.substring(4).trim(); parser.parse(_base, trimmed); } // If it's not a moml processing instruction, ignore. } else { // Data is not enclosed in a processing instruction. // Must have been given in a CDATA section. parser.parse(_base, _configureText); // Our work here is done, free this up. _configureText = null; } } } finally { MoMLParser.setMoMLFilters(savedFilters); } } } catch (Exception ex) { MessageHandler.error("Failed to populate contents.", ex); // Oddly, under JDK1.3.1, we may see the line // "Exception occurred during event dispatching:" // in the console window, but there is no stack trace. // If we change this exception to a RuntimeException, then // the stack trace appears. My guess is this indicates a // bug in the ptolemy.kernel.Exception* classes or in JDK1.3.1 // Note that under JDK1.4, the stack trace is printed in // both cases. throw new InvalidStateException(this, ex, "Failed to populate contents"); } finally { _populating = resetPolulatingValue; } }