001/* An attribute that references a library to use with the container.
002
003 Copyright (c) 1998-2013 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.moml;
029
030import ptolemy.kernel.CompositeEntity;
031import ptolemy.kernel.util.Attribute;
032import ptolemy.kernel.util.ConfigurableAttribute;
033import ptolemy.kernel.util.IllegalActionException;
034import ptolemy.kernel.util.InternalErrorException;
035import ptolemy.kernel.util.KernelException;
036import ptolemy.kernel.util.NameDuplicationException;
037import ptolemy.kernel.util.NamedObj;
038import ptolemy.kernel.util.SingletonAttribute;
039import ptolemy.kernel.util.Workspace;
040
041///////////////////////////////////////////////////////////////////
042//// LibraryAttribute
043
044/**
045 This class is a configurable singleton attribute that associates a
046 component library with a model.  By convention, it is typically named
047 "_library".  A visual editor that opens a model containing this attribute
048 will offer the contents of its library as the component library for editing
049 the model.  "Singleton" means that if this attribute is placed in a model,
050 it will replace any previous singleton attribute that has the same name.
051 "Configurable" means that the contents of the library can be set in
052 a configure element in MoML, or via the configure() method.
053 The library can also be set by calling setLibrary(); this will override
054 any library specified by configure.
055 <p>
056 When creating a library to associate with this attribute, the
057 library should be created in the same workspace as this attribute
058 (as returned by the workspace() method).  Normally, it will have no
059 container.  The text specified in the configure element (or a call
060 to the configure() method) is not parsed until the getLibrary()
061 method is called.  Thus, the overhead of creating the library is
062 avoided if the library is not used.
063
064 @author Edward A. Lee
065 @version $Id$
066 @since Ptolemy II 1.0
067 @Pt.ProposedRating Yellow (eal)
068 @Pt.AcceptedRating Red (janneck)
069 */
070public class LibraryAttribute extends ConfigurableAttribute {
071    /** Construct a new attribute with no
072     *  container and an empty string as its name. Add the attribute to the
073     *  workspace directory.
074     *  Increment the version number of the workspace.
075     */
076    public LibraryAttribute() {
077        super();
078    }
079
080    /** Construct a new attribute with
081     *  no container and an empty string as a name. You can then change
082     *  the name with setName(). If the workspace argument is null, then
083     *  use the default workspace.
084     *  Add the attribute to the workspace directory.
085     *  Increment the version number of the workspace.
086     *  @param workspace The workspace that will list the attribute.
087     */
088    public LibraryAttribute(Workspace workspace) {
089        super(workspace);
090    }
091
092    /** Construct an attribute with the given container and name.
093     *  If an attribute already exists with the same name as the one
094     *  specified here, that is an instance of class
095     *  LibraryAttribute (or a derived class), then that
096     *  attribute is removed before this one is inserted in the container.
097     *  @param container The container.
098     *  @param name The name of this attribute.
099     *  @exception IllegalActionException If the attribute cannot be contained
100     *   by the proposed container.
101     *  @exception NameDuplicationException If the container already has an
102     *   attribute with this name, and the class of that container is not
103     *   LibraryAttribute.
104     */
105    public LibraryAttribute(NamedObj container, String name)
106            throws NameDuplicationException, IllegalActionException {
107        super(container, name);
108    }
109
110    ///////////////////////////////////////////////////////////////////
111    ////                         public methods                    ////
112
113    /** Return the library specified by the configure() method or the
114     *  setLibrary() method, or null if it has not been set.  If the
115     *  configure() method has defined the library, then calling this
116     *  method will parse the MoML in specified in the configure() call
117     *  to create the library.  The parser for the top-level container
118     *  of this attribute will be used, if there is one.  Otherwise,
119     *  a new parser will be used.  Note that the library will be
120     *  reparsed each time this is called.  This method ensures that
121     *  the library that is returned contains an attribute called
122     *  "_libraryMarker" so that a user interface recognizes it as
123     *  a library.
124     *  @return The library, or null if none.
125     *  @exception Exception If the library specification
126     *   is invalid, for example because the MoML cannot be parsed, or
127     *   because it does not define an instance of CompositeEntity.
128     *  @see #setLibrary(CompositeEntity)
129     */
130    public CompositeEntity getLibrary() throws Exception {
131        if (_librarySet) {
132            return _library;
133        }
134
135        MoMLParser parser = ParserAttribute.getParser(this);
136        parser.reset();
137
138        String value = value();
139
140        NamedObj library = null;
141        if (!value.trim().equals("")) {
142            library = parser.parse(value);
143            if (!(library instanceof CompositeEntity)) {
144                throw new IllegalActionException(this,
145                        "Expected library to be in an instance of CompositeEntity,"
146                                + " but it is: "
147                                + library.getClass().getName());
148            }
149            // Ensure that the library is marked as a library.
150            Attribute marker = library.getAttribute("_libraryMarker");
151
152            if (marker == null) {
153                new SingletonAttribute(library, "_libraryMarker");
154            }
155        }
156
157        return (CompositeEntity) library;
158    }
159
160    /** Specify the library, overriding any library that might have been
161     *  or might later be specified by a call to configure().  This method
162     *  ensures that the library contains an attribute named "_libraryMarker"
163     *  by creating one if it is not there.
164     *  @param library The library.
165     *  @see #getLibrary()
166     */
167    public void setLibrary(CompositeEntity library) {
168        _library = library;
169        _librarySet = true;
170
171        if (_library != null) {
172            Attribute marker = _library.getAttribute("_libraryMarker");
173
174            if (marker == null) {
175                try {
176                    new SingletonAttribute(_library, "_libraryMarker");
177                } catch (KernelException ex) {
178                    throw new InternalErrorException(
179                            "Can't add library marker: " + ex);
180                }
181            }
182        }
183    }
184
185    ///////////////////////////////////////////////////////////////////
186    ////                         private variables                 ////
187    // The library.
188    private CompositeEntity _library;
189
190    // Flag indicating that the library was set by setLibrary().
191    private boolean _librarySet = false;
192}