001/* An attribute for defining a data type for a port. 002 003 Copyright (c) 1999-2018 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 */ 027package ptolemy.actor; 028 029import java.util.List; 030 031import ptolemy.data.expr.Parameter; 032import ptolemy.data.type.BaseType; 033import ptolemy.data.type.Type; 034import ptolemy.data.type.Typeable; 035import ptolemy.graph.InequalityTerm; 036import ptolemy.kernel.util.Attribute; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.InternalErrorException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.NamedObj; 041import ptolemy.kernel.util.Workspace; 042 043/////////////////////////////////////////////////////////////////// 044//// TypeAttribute 045 046/** 047 An attribute for defining a data type for a port. 048 Use setExpression() to define a data type, as in for example, 049 <pre> 050 attribute.setExpression("double"); 051 </pre> 052 The class TypedIOPort recognizes when this attribute is inserted 053 and calls setTypeEquals() to define its type. In the above example, 054 the type of the port is set to double. 055 <p> 056 The type can be given by any expression that can be evaluated. 057 In fact, it would be equally valid to specify the type to be double 058 using 059 <pre> 060 attribute.setExpression("0.0"); 061 </pre> 062 The Constants class defines the constant "double" to have the value 063 0.0, so that instead you may give the type by name. 064 The Constants class defines for convenience the following 065 constants: boolean, complex, double, fixedpoint, general, 066 int, long, matrix, object, scalar, string, and unknown. 067 The constant "unknown" has a rather special behavior, in that 068 it sets the type of the port to be unknown, allowing type resolution 069 to infer it. The constant "matrix" designates a matrix 070 without specifying an element type, in contrast to, for example, 071 "[double]", which specifies a double matrix. 072 Similarly, the constant "scalar" designates a scalar of any type 073 (double, int, long, etc.). 074 The constant "general" designates any type. 075 <p> 076 Since the type is given by a "prototype" (an expression with the 077 appropriate type), any data type that can be given in an expression 078 can be specified as a type. For structured types, follow the 079 same syntax as in expressions. For example: 080 <pre> 081 {double} - double array 082 [int] - int matrix 083 {field1 = string, field2 = int} - record with two fields 084 </pre> 085 <p> 086 This attribute is a singleton in a strong sense. 087 When its container is set, if the container contains any other instance 088 of TypeAttribute, that other instance is removed. 089 090 @author Edward A. Lee, Xiaojun Liu 091 @version $Id$ 092 @since Ptolemy II 1.0 093 @Pt.ProposedRating Yellow (eal) 094 @Pt.AcceptedRating Red (cxh) 095 @see TypedIOPort 096 @see ptolemy.data.expr.Constants 097 */ 098public class TypeAttribute extends Parameter { 099 /** Construct a parameter in the specified workspace with an empty 100 * string as a name. 101 * If the workspace argument is null, then use the default workspace. 102 * The object is added to the list of objects in the workspace. 103 * Increment the version number of the workspace. 104 * @param workspace The workspace that will list the parameter. 105 */ 106 public TypeAttribute(Workspace workspace) { 107 super(workspace); 108 } 109 110 /** Construct an attribute with the given name contained by the specified 111 * port. The container argument must not be null, or a 112 * NullPointerException will be thrown. This attribute will use the 113 * workspace of the container for synchronization and version counts. 114 * If the name argument is null, then the name is set to the empty 115 * string. The object is added to the directory of the workspace 116 * if the container is null. 117 * Increment the version of the workspace. 118 * @param container The container. 119 * @param name The name of this attribute. 120 * @exception IllegalActionException If the attribute is not of an 121 * acceptable class for the container, or if the name contains a period. 122 * @exception NameDuplicationException If the name coincides with 123 * an attribute already in the container. 124 */ 125 public TypeAttribute(TypedIOPort container, String name) 126 throws IllegalActionException, NameDuplicationException { 127 super(container, name); 128 } 129 130 /** Construct an attribute with the given name contained by the specified 131 * port. The container argument must not be null, or a 132 * NullPointerException will be thrown. This attribute will use the 133 * workspace of the container for synchronization and version counts. 134 * If the name argument is null, then the name is set to the empty 135 * string. The object is added to the directory of the workspace 136 * if the container is null. 137 * Increment the version of the workspace. 138 * @param container The container. 139 * @param name The name of this attribute. 140 * @exception IllegalActionException If the attribute is not of an 141 * acceptable class for the container, or if the name contains a period. 142 * @exception NameDuplicationException If the name coincides with 143 * an attribute already in the container. 144 */ 145 public TypeAttribute(Attribute container, String name) 146 throws IllegalActionException, NameDuplicationException { 147 super(container, name); 148 } 149 150 /////////////////////////////////////////////////////////////////// 151 //// public methods //// 152 153 /** Override the base class to remove any other instances of TypeAttribute. 154 * @param container The proposed container. 155 * @exception IllegalActionException If the proposed container is not a 156 * TypedIOPort, or if the base class throws it. 157 * @exception NameDuplicationException If the container already has 158 * an attribute with the name of this attribute that is not an instance 159 * of TypeAttribute. 160 */ 161 @Override 162 public void setContainer(NamedObj container) 163 throws IllegalActionException, NameDuplicationException { 164 _checkContainer(container); 165 try { 166 workspace().getWriteAccess(); 167 if (container != null) { 168 List<TypeAttribute> attributes = container 169 .attributeList(TypeAttribute.class); 170 for (TypeAttribute attribute : attributes) { 171 if (attribute != this) { 172 try { 173 attribute.setContainer(null); 174 } catch (NameDuplicationException e) { 175 throw new InternalErrorException(e); 176 } 177 } 178 } 179 } 180 NamedObj previousContainer = getContainer(); 181 if (container != previousContainer) { 182 // Container is changing. Restore the previous 183 // container to its previous type, and record 184 // the previous type of the new container. 185 if (previousContainer instanceof Typeable) { 186 // Notice that if the previous type is UNKNOWN, then this 187 // delegate to type resolution. 188 ((Typeable) previousContainer).setTypeEquals(_previousType); 189 if (previousContainer instanceof Actor) { 190 Director previousDirector = ((Actor) previousContainer) 191 .getDirector(); 192 previousDirector.invalidateResolvedTypes(); 193 } 194 } 195 if (container instanceof Typeable) { 196 InequalityTerm term = ((Typeable) container).getTypeTerm(); 197 if (term.isSettable()) { 198 // If the type term is a variable, then we want to 199 // delegate to type resolution. 200 _previousType = BaseType.UNKNOWN; 201 } else { 202 // If the type term is a constant, then we want to record 203 // the constant. 204 _previousType = ((Typeable) container).getType(); 205 } 206 if (container instanceof Actor) { 207 Director director = ((Actor) container).getDirector(); 208 director.invalidateResolvedTypes(); 209 } 210 } 211 } 212 super.setContainer(container); 213 } finally { 214 workspace().doneWriting(); 215 } 216 } 217 218 /////////////////////////////////////////////////////////////////// 219 //// protected methods //// 220 221 /** Override the base class to ensure that the proposed container 222 * is a TypedIOPort or a Kepler PortAttribute. 223 * @param container The proposed container. 224 * @exception IllegalActionException If the proposed container is not a 225 * TypedIOPort, or if the base class throws it. 226 */ 227 /* 228 @Override 229 protected void _checkContainer(NamedObj container) 230 throws IllegalActionException { 231 if (container != null && !(container instanceof TypedIOPort)) { 232 // FIXME: this is a bit of hack brought on by 233 // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=4767 234 if (!container.getClass().getName() 235 .equals("org.kepler.moml.PortAttribute")) { 236 throw new IllegalActionException( 237 container, 238 this, 239 "TypeAttribute can only be contained by instances " 240 + "of TypedIOPort or org.kepler.moml.PortAttribute."); 241 242 } 243 244 } 245 } 246 */ 247 248 /////////////////////////////////////////////////////////////////// 249 //// private fields //// 250 251 /** Previous resolved type before this attribute was added to its current container. */ 252 private Type _previousType = BaseType.UNKNOWN; 253}