/*
* A base class for attributes that contain a refinement model graph.
*
* Copyright (c) 2008-2009 The Regents of the University of California. All
* rights reserved. Permission is hereby granted, without written agreement and
* without license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the above
* copyright notice and the following two paragraphs appear in all copies of
* this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
* "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY
*
*/
package ptolemy.domains.properties.kernel;
import java.io.IOException;
import java.io.StringReader;
import java.io.Writer;
import java.net.URL;
import ptolemy.actor.Manager;
import ptolemy.domains.fsm.kernel.Configurer;
import ptolemy.kernel.CompositeEntity;
import ptolemy.kernel.attributes.URIAttribute;
import ptolemy.kernel.util.Attribute;
import ptolemy.kernel.util.Configurable;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.InternalErrorException;
import ptolemy.kernel.util.KernelException;
import ptolemy.kernel.util.NameDuplicationException;
import ptolemy.kernel.util.NamedObj;
import ptolemy.kernel.util.Workspace;
import ptolemy.moml.MoMLParser;
//////////////////////////////////////////////////////////////////////////
//// ModelAttribute
/**
* A base class for attributes that contain a refinement model graph.
*
* <p> Note that this class expects that
* ptolemy.vergil.properties.ModelAttributeControllerFactory
* will be used as the _controllerFactory of this class. Instead of
* having an explicit compile-time dependency between this class and
* ModelAttributeControllerFactory, derived classes should use MoML
* to set up the containment relationship. For example,
* <code>ptII/ptolemy/configs/properties/propertiesConfigurableSolvers.xml</code>
* contains:
* <pre>
* <property name="PropertyLatticeAttribute" class="ptolemy.domains.properties.kernel.PropertyLatticeAttribute">
* <property name="_controllerFactory" class="ptolemy.vergil.properties.ModelAttributeControllerFactory">
* </property>
* </property>
* </pre>
* All classes that derive from this class should use a similar pattern.
*
* @author Man-Kit Leung
* @version $Id$
* @since Ptolemy II 7.1
* @Pt.ProposedRating Red (tfeng)
* @Pt.AcceptedRating Red (tfeng)
*/
public class ModelAttribute extends Attribute implements Configurable {
/**
* Create a model attribute with the specified container and name.
* @param container The specified container.
* @param name The specified name.
* @exception IllegalActionException If the attribute is not of an
* acceptable class for the container, or if the name contains a period.
* @exception NameDuplicationException If the name coincides with an
* attribute already in the container.
*/
public ModelAttribute(NamedObj container, String name)
throws NameDuplicationException, IllegalActionException {
super(container, name);
_init();
}
/**
* Construct an attribute in the specified workspace with an empty string as
* a name. If the workspace argument is null, then use the default
* workspace. The object is added to the directory of the workspace.
* @param workspace The workspace that will list the attribute.
*/
public ModelAttribute(Workspace workspace) {
super(workspace);
try {
_init();
} catch (KernelException e) {
throw new InternalErrorException(e);
}
}
/**
* Construct an attribute in the specified workspace with the specified
* name. If the workspace argument is null, then use the default workspace.
* The object is added to the directory of the workspace.
* @param workspace The workspace that will list the attribute.
* @param name The specified name.
*/
public ModelAttribute(Workspace workspace, String name) {
super(workspace);
try {
setName(name);
_init();
} catch (KernelException e) {
throw new InternalErrorException(e);
}
}
///////////////////////////////////////////////////////////////////
//// public methods ////
/**
* Return a clone of this model attribute. This also creates a clone for the
* contained model.
* @param workspace The workspace for the cloned object.
* @return A clone.
* @exception CloneNotSupportedException Thrown if an error occurs while
* cloning the attribute or the contained model.
*/
public Object clone(Workspace workspace) throws CloneNotSupportedException {
ModelAttribute newObject = (ModelAttribute) super.clone(workspace);
try {
newObject._configurer = new Configurer(workspace);
newObject._configurer.setName("Configurer");
//new DEDirector(newObject._configurer, "_director");
newObject._configurer
.setManager(new Manager(workspace, "_manager"));
newObject._configurer.setConfiguredObject(newObject);
newObject._model = (CompositeEntity) _model.clone(workspace);
newObject._model.setContainer(newObject._configurer);
} catch (KernelException e) {
throw new InternalErrorException(e);
}
return newObject;
}
/**
* Construct and configure the contained model with the specified source and
* text. It parses the specified MoML text and clear clears the URI
* information from the constructed model.
* @param base The base URL for relative references, or null if not known.
* @param source The URI of the document.
* @param text The MoML description.
* @exception Exception If the parsing fails or the URI info cannot be
* cleared.
*/
public void configure(URL base, String source, String text)
throws Exception {
_configureSource = source;
if (!text.trim().equals("")) {
MoMLParser parser = new MoMLParser(workspace());
_configurer.removeAllEntities();
parser.setContext(_configurer);
parser.parse(base, source, new StringReader(text));
_model = (CompositeEntity) _configurer.entityList().get(0);
_clearURI(_model);
}
}
/**
* Return the configure source.
* @return The configure source.
*/
public String getConfigureSource() {
return _configureSource;
}
/**
* Return the configure text. In this base class, this returns null.
* @return The configure text.
*/
public String getConfigureText() {
return null;
}
/**
* Return the contained model.
* @return The contained model.
*/
public CompositeEntity getContainedModel() {
return _model;
}
///////////////////////////////////////////////////////////////////
//// protected methods ////
/**
* Write a MoML description of the contents of this object. This wraps the
* MoML description of the contained model within the <configure> tag.
* @param output The output stream to write to.
* @param depth The depth in the hierarchy, to determine indenting.
* @exception IOException If an I/O error occurs.
*/
protected void _exportMoMLContents(Writer output, int depth)
throws IOException {
super._exportMoMLContents(output, depth);
String sourceSpec = "";
if (_configureSource != null && !_configureSource.trim().equals("")) {
sourceSpec = " source=\"" + _configureSource + "\"";
}
output.write(_getIndentPrefix(depth) + "<configure" + sourceSpec
+ ">\n");
_model.exportMoML(output, depth + 1);
output.write(_getIndentPrefix(depth) + "</configure>\n");
}
/**
* Return the class name of the contained model. The class name is used to
* instantiate the contained model. By default, this returns the string
* "ptolemy.actor.CompositeActor". If base classes can override this method
* to instantiate a different type of top-level for the contained model.
* @return the class name of the contained model.
*/
protected String _getContainedModelClassName() {
return "ptolemy.actor.CompositeActor";
}
///////////////////////////////////////////////////////////////////
//// private methods ////
private static void _clearURI(NamedObj object)
throws IllegalActionException, NameDuplicationException {
URIAttribute attribute = (URIAttribute) object.getAttribute("_uri",
URIAttribute.class);
if (attribute != null) {
attribute.setContainer(null);
}
}
private void _init() throws IllegalActionException,
NameDuplicationException {
_configurer = new Configurer(workspace());
_configurer.setName("Configurer");
// FIXME: do we need a director for the configurer?
//new DEDirector(_configurer, "_director");
_configurer.setManager(new Manager(workspace(), "_manager"));
_configurer.setConfiguredObject(this);
String moml = "<entity name=\"Model\" " + "class=\""
+ _getContainedModelClassName() + "\"/>";
MoMLParser parser = new MoMLParser();
parser.setContext(_configurer);
try {
parser.parse(moml);
} catch (Exception e) {
throw new IllegalActionException(this, e, "Unable to populate "
+ "the model within \"" + getFullName() + "\".");
}
_model = (CompositeEntity) _configurer.getEntity("Model");
// Note that derived classes should set _controllerFactory by using
// MoML. See the class comment for detail
}
///////////////////////////////////////////////////////////////////
//// private variables ////
private String _configureSource;
private Configurer _configurer;
private CompositeEntity _model;
}