/* A property constraint attribute.
*
* Copyright (c) 2007-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.
*/
package ptolemy.data.properties.lattice;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import ptolemy.data.properties.Property;
import ptolemy.data.properties.PropertyAttribute;
import ptolemy.data.properties.lattice.exampleSetLattice.Lattice;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;
import ptolemy.kernel.util.NamedObj;
/**
A property constraint attribute.
@author Man-kit (Jackie) Leung.
@version $Id$
@since Ptolemy II 8.0
@Pt.ProposedRating Red (cxh)
@Pt.AcceptedRating Red (cxh)
*/
public class PropertyConstraintAttribute extends PropertyAttribute {
/**
* Construct a PropertyConstraintAttribute with the given container and
* name. Its expression is a property resolved by the constraint solver.
* @param container The container of this attribute.
* @param name The given of the attribute.
* @exception IllegalActionException
* @exception NameDuplicationException
*/
public PropertyConstraintAttribute(NamedObj container, String name)
throws IllegalActionException, NameDuplicationException {
super(container, name);
}
/**
* Set the expression. This method takes the descriptive form and determines
* the internal form (by parsing the descriptive form) and stores it.
* @param expression A String that is the descriptive form of either a Unit
* or a UnitEquation.
* @see ptolemy.kernel.util.Settable#setExpression(java.lang.String)
*/
public void setExpression(String expression) throws IllegalActionException {
super.setExpression(expression);
if (expression.length() > 0) {
String latticeName = getName().substring(
getName().indexOf("::") + 2);
PropertyLattice lattice = PropertyLattice
.getPropertyLattice(latticeName);
try {
if (lattice instanceof PropertySetLattice) {
_property = _parseSetExpression(lattice, expression);
} else {
_property = _parsePropertyExpression(lattice, expression);
}
} catch (Exception ex) {
throw new IllegalActionException(this, ex,
"Cannot resolve the property expression: \""
+ expression + "\"");
}
}
}
/**
* Return the index of a specific character in the string starting from the
* given index. It find the first occurence of the character that is not
* embedded inside parentheses "()".
* @param ch The character to search for.
* @param string The given string to search from.
* @param fromIndex The index to start the search.
* @return The first occurence of the character in the string that is not
* embedded in parentheses.
*/
public static int _indexOf(String ch, String string, int fromIndex) {
int parenIndex = fromIndex;
int result = -1;
int closedParenIndex = parenIndex;
do {
result = string.indexOf(ch, closedParenIndex);
parenIndex = string.indexOf('{', closedParenIndex);
if (parenIndex >= 0) {
try {
closedParenIndex = _findClosedBracket(string, parenIndex);
} catch (IllegalActionException e) {
closedParenIndex = -1;
}
}
} while (result > parenIndex && result < closedParenIndex);
return result;
}
public static List<String> _parseList(String parameters) {
List<String> result = new ArrayList<String>();
int previousCommaIndex = 0;
int commaIndex = _indexOf(",", parameters, 0);
while (commaIndex >= 0) {
String item = parameters.substring(previousCommaIndex, commaIndex)
.trim();
result.add(item);
previousCommaIndex = commaIndex + 1;
commaIndex = _indexOf(",", parameters, previousCommaIndex);
}
String item = parameters.substring(previousCommaIndex,
parameters.length()).trim();
if (item.trim().length() > 0) {
result.add(item);
}
return result;
}
public static void main(String[] args) throws IllegalActionException {
Lattice lattice = new Lattice();
System.out.println(_parseSetExpression(lattice, "{A, B, C}"));
System.out.println(_parseSetExpression(lattice, "{A, B, }C"));
System.out.println(_parseSetExpression(lattice, "A{, B, C}"));
System.out.println(_parseSetExpression(lattice, "A{, B}, C"));
System.out.println(_parseSetExpression(lattice, "A, {B}, C"));
}
/**
* Find the paired close parenthesis given a string and an index which is
* the position of an open parenthesis. Return -1 if no paired close
* parenthesis is found.
* @param string The given string.
* @param pos The given index.
* @return The index which indicates the position of the paired close
* parenthesis of the string.
* @exception IllegalActionException If the character at the given position
* of the string is not an open parenthesis or if the index is less than 0
* or past the end of the string.
*/
private static int _findClosedBracket(String string, int pos)
throws IllegalActionException {
if (pos < 0 || pos >= string.length()) {
throw new IllegalActionException("The character index " + pos
+ " is past the end of string \"" + string
+ "\", which has a length of " + string.length() + ".");
}
if (string.charAt(pos) != '(') {
throw new IllegalActionException("The character at index " + pos
+ " of string: " + string + " is not a open parenthesis.");
}
int nextOpenParen = string.indexOf("(", pos + 1);
if (nextOpenParen < 0) {
nextOpenParen = string.length();
}
int nextCloseParen = string.indexOf(")", pos);
if (nextCloseParen < 0) {
return -1;
}
int count = 1;
int beginIndex = pos + 1;
while (beginIndex > 0) {
if (nextCloseParen < nextOpenParen) {
count--;
if (count == 0) {
return nextCloseParen;
}
beginIndex = nextCloseParen + 1;
nextCloseParen = string.indexOf(")", beginIndex);
if (nextCloseParen < 0) {
return -1;
}
}
if (nextOpenParen < nextCloseParen) {
count++;
beginIndex = nextOpenParen + 1;
nextOpenParen = string.indexOf("(", beginIndex);
if (nextOpenParen < 0) {
nextOpenParen = string.length();
}
}
}
return -1;
}
/**
* Return a property in the specified lattice that is identified by the
* given expression. Return null if the expression is case-insensitively
* equivalent to "nil".
* @param lattice The specified lattice. If the expression is not NIL, then
* the lattice must not be null.
* @param expression The expression string.
* @return A property in the specified lattice, or null if the expression is
* equal "nil".
* @exception IllegalActionException If the lattice does not contain such
* element and the expression is not "nil".
*
*/
private static LatticeProperty _parseElementExpression(
PropertyLattice lattice, String expression)
throws IllegalActionException {
expression = expression.trim();
String fieldName = expression.toUpperCase();
if (!fieldName.equalsIgnoreCase("NIL")) {
if (lattice == null) {
throw new IllegalActionException("The lattice was null?"
+ " The expression was \"" + expression + "\"");
}
return lattice.getElement(fieldName);
}
return null;
}
/**
* Parse the given expression for an arbitrary Property.
* @param lattice The lattice.
* @param expression The expression
* @return The LatticeProperty that corresponds with the lattice and
* expression.
* @exception IllegalActionException If thrown by
* {@link #_parseElementExpression(PropertyLattice, String)}
*/
private static LatticeProperty _parsePropertyExpression(
PropertyLattice lattice, String expression)
throws IllegalActionException {
if (expression.startsWith("{") && expression.endsWith("}")) {
// Parsing RecordProperty.
List<String> fieldExpressions = _parseList(expression.substring(1,
expression.length() - 1));
int size = fieldExpressions.size();
String[] labels = new String[size];
LatticeProperty[] fieldProperties = new LatticeProperty[size];
for (int i = 0; i < size; i++) {
String fieldExpression = fieldExpressions.get(i);
String[] labelAndProperty = fieldExpression.split("=", 2);
// 11/09/09 Charles Shelton - added trim() method call to remove
// extra whitespace characters.
// Labels were getting set with an extra space in the name,
// which was causing regression tests with record properties to fail.
labels[i] = labelAndProperty[0].trim();
fieldProperties[i] = _parsePropertyExpression(lattice,
labelAndProperty[1].trim());
}
return new RecordProperty(lattice, labels, fieldProperties);
}
return _parseElementExpression(lattice, expression);
}
private static PropertySet _parseSetExpression(PropertyLattice lattice,
String setExpression) throws IllegalActionException {
LinkedList result = new LinkedList();
int start = 0;
int openBrackets = 0;
int i;
setExpression = setExpression.trim();
if (!setExpression.startsWith("{") && !setExpression.endsWith("}")) {
result.add(_parseElementExpression(lattice, setExpression));
return new PropertySet(lattice, result);
}
setExpression = setExpression.substring(1);
for (i = 0; i < setExpression.length(); i++) {
if (setExpression.charAt(i) == ',' && openBrackets == 0) {
String element = setExpression.substring(start, i);
if (element.trim().length() != 0) {
result.addAll(_parseSetExpression(lattice, element));
start = i + 1;
} else {
throw new IllegalActionException(
"Cannot resolve the property expression: \""
+ element + "\"");
}
} else if (setExpression.charAt(i) == '{') {
//start++;
openBrackets++;
} else if (setExpression.charAt(i) == '}') {
openBrackets--;
if (openBrackets == -1) {
String element = setExpression.substring(start, i);
if (element.trim().length() != 0) {
result.addAll(_parseSetExpression(lattice, element));
start = i + 1;
} else {
// Return the empty set.
if (result.isEmpty()) {
return new PropertySet(lattice, new Property[0]);
}
throw new IllegalActionException(
"Cannot resolve the property expression: \""
+ element + "\"");
}
}
}
}
// String element = setExpression.substring(start, i - start);
// if (!element.trim().isEmpty()) {
// result.add(parseSetExpression(lattice, element));
// }
return new PropertySet(lattice, result);
}
}