/*
* Copyright (C) 2007 ETH Zurich
*
* This file is part of Fosstrak (www.fosstrak.org).
*
* Fosstrak is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* Fosstrak is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Fosstrak; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package org.fosstrak.ale.server;
import org.fosstrak.ale.exception.ECSpecValidationException;
/**
* This clas represents a data field of a tag, filter or group pattern.
*
* @author regli
*/
public class PatternDataField {
/** string representation of this data field */
private final String stringRepresentation;
/** indicates if this datafield contains an asterisk */
private final boolean isAsterisk;
/** indicates if this datafield conains an X */
private final boolean isX;
/** indicates if this data field contains an int */
private final boolean isInt;
/** indicates if this data field contains a range */
private final boolean isRange;
/** value of this data field if it is an int field */
private long value;
/** lower limit of the range of this data field if this data field contains a range */
private int low;
/** higher limit of the range of this data field if this data field contains a range */
private int high;
/**
* Constructor parses and validates the string representation of the data field.
*
* @param stringRepresentation of the data field
* @param usage of the pattern this data field belongs to
* @throws ECSpecValidationException if the data field is invalid
*/
public PatternDataField(String stringRepresentation, PatternUsage usage) throws ECSpecValidationException {
this.stringRepresentation = stringRepresentation;
// check for asterisk
if ((usage == PatternUsage.FILTER || usage == PatternUsage.GROUP) && "*".equals(stringRepresentation)) {
isAsterisk = true;
isX = false;
isInt = false;
isRange = false;
return;
} else {
isAsterisk = false;
}
// check for X if usage is group
if (usage == PatternUsage.GROUP && "X".equals(stringRepresentation)) {
isX = true;
isInt = false;
isRange = false;
return;
} else {
isX = false;
}
// check for int
try {
//value = Integer.parseInt(stringRepresentation);
value = Long.parseLong(stringRepresentation);
} catch(NumberFormatException e) {
if (usage == PatternUsage.TAG) {
throw new ECSpecValidationException("Invalid data field '" + stringRepresentation + "'. " +
"Only 'int' is allowed.");
}
// check for range
String[] parts = stringRepresentation.split("-");
if (parts.length != 2 || !parts[0].startsWith("[") || !parts[1].endsWith("]")) {
throw new ECSpecValidationException("Invalid data field '" + stringRepresentation + "'. " +
"Only '*', " + (usage == PatternUsage.GROUP ? "'X', " : "") + "'[lo-hi]' or 'int' are allowed.");
}
try {
low = Integer.parseInt(parts[0].substring(1));
high = Integer.parseInt(parts[1].substring(0, parts[1].length() - 1));
} catch (NumberFormatException e1) {
throw new ECSpecValidationException("Invalid data field '" + stringRepresentation + "'. " +
"Only '*', " + (usage == PatternUsage.GROUP ? "'X', " : "") + "'[lo-hi]' or 'int' are allowed.");
}
// check if low is lower than high
if (low <= high) {
isRange = true;
} else {
throw new ECSpecValidationException("Invalid range '" + stringRepresentation + "'. " + "Range must have the form '[lo-hi]' with lo <= hi.");
}
isInt = false;
return;
}
// check if value is positive
if (value >= 0) {
isInt = true;
} else {
throw new ECSpecValidationException("Invalid data field '" + stringRepresentation + "' in pattern '. " +
"Only positive int is allowed.");
}
isRange = false;
}
/**
* This method indicates if this data field contains an asterisk.
*
* @return true if this data field contains an asterisk and false otherwise
*/
public boolean isAsterisk() {
return isAsterisk;
}
/**
* This method indicates if this data field contains an X.
*
* @return true if this data field contains an X and false otherwise
*/
public boolean isX() {
return isX;
}
/**
* This method indicates if this data field contains an int.
*
* @return true if this data field contains an int and false otherwise
*/
public boolean isInt() {
return isInt;
}
/**
* This method indicates if this data field contains a range.
*
* @return true if this data field contains a range and false otherwise
*/
public boolean isRange() {
return isRange;
}
/**
* This method returns the value of this data field if this data field contains an int
* and throws an exception otherwise.
*
* @return value of data field
* @throws ECSpecValidationException if the data field contains not an int
*/
public long getValue() throws ECSpecValidationException {
if (isInt) {
return value;
} else {
throw new ECSpecValidationException("Data field is not an int.");
}
}
/**
* This method returns the lower limit of the range of this data field if this data field
* contains a range and throws an exception otherwise.
*
* @return lower limit of the range of this data field
* @throws ECSpecValidationException if the data field contains not a range
*/
public int getLow() throws ECSpecValidationException {
if (isRange) {
return low;
} else {
throw new ECSpecValidationException("Data field is not a range.");
}
}
/**
* This method returns the higher limit of the range of this data field if this data field
* contains a range and throws an exception otherwise.
*
* @return higher limit of the range of this data field
* @throws ECSpecValidationException if the data field contains not a range
*/
public int getHigh() throws ECSpecValidationException {
if (isRange) {
return high;
} else {
throw new ECSpecValidationException("Data field is not a range.");
}
}
/**
* This method indicates if this data field is disjoint to the specified data field.
*
* @param field to check disjointness
* @return true if the data field are disjoint and false otherwise
* @throws ECSpecValidationException if an implementation exception occurs
*/
public boolean isDisjoint(PatternDataField field) throws ECSpecValidationException {
if (isAsterisk || isX || field.isAsterisk() || field.isX()) {
return false;
}
if (isInt) {
if (field.isInt()) {
if (value == field.getValue()) {
return false;
} else {
return true;
}
} else if (field.isRange()) {
if (field.getLow() <= value && value <= field.getHigh()) {
return false;
} else {
return true;
}
}
} else if (isRange) {
if (field.isInt()) {
if (low <= field.getValue() && field.getValue() <= high) {
return false;
} else {
return true;
}
} else if (field.isRange()) {
if ((field.getLow() <= low && low <= field.getHigh()) || (field.getLow() <= high && high <= field.getHigh())) {
return false;
} else {
return true;
}
}
}
return false;
}
/**
* This method indicates if the specified field value is a member of this data field.
*
* @param fieldValue to check for member.
* @return true if the specified value is member of this data field
*/
public boolean isMember(long fieldValue) {
if (isInt) {
// if pattern field is an int, the tag field must be the same int
if (value != fieldValue) {
return false;
}
} else if (isRange) {
// if pattern field is a range, the tag field must be in this range
if (fieldValue < low || fieldValue > high) {
return false;
}
}
return true;
}
/**
* This method returns a string representation of this data field.
*
* @return string representation
*/
public String toString() {
return stringRepresentation;
}
}