001/* 002 * Copyright (c) 2005-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.sms; 031 032import java.util.Iterator; 033import java.util.StringTokenizer; 034 035import ptolemy.actor.TypedIOPort; 036import ptolemy.data.type.ArrayType; 037import ptolemy.data.type.BaseType; 038import ptolemy.data.type.MatrixType; 039import ptolemy.data.type.RecordType; 040import ptolemy.data.type.StructuredType; 041import ptolemy.data.type.Type; 042import ptolemy.kernel.Entity; 043import ptolemy.kernel.util.IllegalActionException; 044import ptolemy.kernel.util.NameDuplicationException; 045import ptolemy.kernel.util.NamedObj; 046 047/** 048 * A refinement port is a virtual port that denotes a particular nested 049 * structure within a port's value. A refinement port (and virtual ports in 050 * general) can be annotated using semantic types. For example, given an actor 051 * with a port p1 having type {lat=int, lon=int}, i.e., the port type is a 052 * record having a lat and lon component, a port refinement 'p1/lat' can be 053 * constructed that denotes the lat values (integers); and a semantic type such 054 * as "Latitude" can be assigned to 'p1/lat'. 055 * <p> 056 * A port refinement may <b>only</b> be contained within an entity (e.g., an 057 * actor). All port refinements are required to have a well-formed port name, 058 * representing the actual "pointer" into the port's data structure. The pointer 059 * 'elem' is used to denote traversal into an array (list) or matrix, and the 060 * component name (e.g., 'lat') is used to denote traversal into a record. 061 * 062 * @author Shawn Bowers 063 * @created June 16, 2005 064 */ 065 066public class KeplerRefinementIOPort extends KeplerVirtualIOPort { 067 068 /** 069 * Constructor 070 * 071 * @param container 072 * Description of the Parameter 073 * @param name 074 * The value of the property 075 * @exception IllegalActionException 076 * Description of the Exception 077 * @exception NameDuplicationException 078 * Description of the Exception 079 */ 080 public KeplerRefinementIOPort(NamedObj container, String name) 081 throws IllegalActionException, NameDuplicationException { 082 super(container, name); 083 if (name == null) 084 throw new IllegalActionException(this, 085 "Refinement port pointer cannot be null"); 086 if (!_wellFormedPointer(name)) 087 throw new IllegalActionException(this, 088 "Badly formed refinement port pointer '" + name + "'"); 089 if (_pointerType(name) == null) 090 throw new IllegalActionException(this, 091 "Invalid refinement port pointer '" + name + "'"); 092 } 093 094 /** 095 * Calls setRefinedPortPointer to set the pointer. 096 */ 097 public void setName(String name) throws IllegalActionException, 098 NameDuplicationException { 099 if (name == null) 100 throw new IllegalActionException(this, 101 "Refined port pointer cannot be null"); 102 else if (!_wellFormedPointer(name)) 103 throw new IllegalActionException(this, 104 "Badly formed refinement port pointer '" + name + "'"); 105 else if (_pointerType(name) == null) 106 throw new IllegalActionException(this, 107 "Invalid refinement port pointer '" + name + "'"); 108 super.setName(name); 109 } 110 111 /** 112 * Assign the given pointer (name) to the port. The pointer cannot be null 113 * and must be well-formed. A well-formed pointer takes the form: p/s_1/s_2/ 114 * ... /s_n for n > 0, where p is a port name, and s_1 to s_n are strings. 115 */ 116 public void setPointer(String pointer) throws IllegalActionException, 117 NameDuplicationException { 118 setName(pointer); 119 } 120 121 /** 122 * @return Retrieve the ptolemy port refined by this virtual port. Note that 123 * the port must reside within the same actor as this refinement. 124 */ 125 public TypedIOPort getRefinedPort() { 126 return _getPort(getPointer()); 127 } 128 129 /** 130 * 131 */ 132 public TypedIOPort _getPort(String pointer) { 133 // get the pointer "steps" 134 String[] steps = pointer.split("/"); 135 // should be greater than zero 136 if (!(steps.length > 0)) 137 return null; 138 // grab port name 139 String portName = steps[0]; 140 141 // iterate to first entity container 142 NamedObj container = getContainer(); 143 while (container != null && !(container instanceof Entity)) 144 container = container.getContainer(); 145 146 // couldn't find a container 147 if (container == null) 148 return null; 149 150 // find the corresponding port 151 Entity actor = (Entity) container; 152 for (Iterator ports = actor.portList().iterator(); ports.hasNext();) { 153 Object obj = (Object) ports.next(); 154 if (!(obj instanceof TypedIOPort)) 155 continue; 156 TypedIOPort port = (TypedIOPort) obj; 157 if (portName == null && port.getName() == null) 158 return port; 159 else if (portName.equals(port.getName())) 160 return port; 161 } 162 return null; 163 } 164 165 /** 166 * @return Returns the pointer (i.e., name) of the port. 167 */ 168 public String getPointer() { 169 return getName(); 170 } 171 172 /** 173 * @return True if the refined port is an output port. 174 */ 175 public boolean isOutput() { 176 return getRefinedPort().isOutput(); 177 } 178 179 /** 180 * @return True if the refined port is an input port. 181 */ 182 public boolean isInput() { 183 return getRefinedPort().isInput(); 184 } 185 186 /** 187 * ... 188 * 189 * @return The type associated with the pointer. 190 */ 191 public Type getType() { 192 return _pointerType(getPointer()); 193 } 194 195 /** 196 * 197 */ 198 private Type _pointerType(String pointer) { 199 TypedIOPort port = _getPort(pointer); 200 201 // can't find the port 202 if (port == null) 203 return BaseType.UNKNOWN; 204 205 // get the type 206 Type type = port.getType(); 207 208 // we don't know the type or base type 209 if (type.equals(BaseType.UNKNOWN)) 210 return BaseType.UNKNOWN; 211 212 // exclude "atomic" base types and other funky types 213 if (!(type instanceof StructuredType)) 214 return null; 215 216 // get the steps 217 String[] steps = pointer.split("/"); 218 if (steps.length <= 0) 219 return null; 220 221 // start it here 222 for (int i = 1; i < steps.length; i++) { 223 type = _applyStep(steps[i], type); 224 if (type == null) 225 return null; 226 } 227 228 return type; 229 } 230 231 private Type _applyStep(String step, Type type) { 232 if (step.equals("elem")) { 233 if (type instanceof ArrayType) 234 return ((ArrayType) type).getElementType(); 235 if (type instanceof MatrixType.BooleanMatrixType) 236 return BaseType.BOOLEAN; 237 if (type instanceof MatrixType.DoubleMatrixType) 238 return BaseType.DOUBLE; 239 if (type instanceof MatrixType.FixMatrixType) 240 return BaseType.FIX; 241 if (type instanceof MatrixType.IntMatrixType) 242 return BaseType.INT; 243 if (type instanceof MatrixType.LongMatrixType) 244 return BaseType.LONG; 245 } 246 if (type instanceof RecordType) 247 return ((RecordType) type).get(step); 248 249 return null; 250 } 251 252 /** 253 * A valid pointer takes the form: p/s_1/s_2/ ... /s_n for n > 0, where p is 254 * a port name, and s_1 to s_n are strings. 255 */ 256 private boolean _wellFormedPointer(String pointer) { 257 if (pointer == null) 258 return false; 259 StringTokenizer st = new StringTokenizer(pointer, "/", true); 260 if (st.countTokens() < 3) 261 return false; 262 boolean delimNeeded = false; 263 264 while (st.hasMoreTokens()) { 265 String str = st.nextToken(); 266 if (!delimNeeded && str.equals("/")) 267 return false; 268 if (delimNeeded && !str.equals("/")) 269 return false; 270 delimNeeded = true ? !delimNeeded : false; 271 } 272 273 return true; 274 } 275 276 public String getTargetName() { 277 String[] steps = getName().split("/"); 278 // should be greater than zero 279 if (!(steps.length > 0)) 280 return ""; 281 // grab port name 282 return steps[steps.length - 1]; 283 } 284 285 /** 286 * 287 */ 288 public String toString() { 289 return getName(); 290 } 291 292 /** PRIVATE MEMBERS */ 293 private String _pointer; 294 295} // KeplerRefinementIOPort