/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* FieldName.java
* Created: Sept 28, 2004
* By: Bo Ilic
*/
package org.openquark.cal.compiler;
import java.util.Comparator;
/**
* Models field names in a CAL record or data constructor argument.
* Field names are of 2 types: ordinal, such as #1, #2, #145 and textual, such as "name", "orderDate", "shipDate".
* @author Bo Ilic
*/
public abstract class FieldName implements Comparable<FieldName> {
/**
* Provides a comparator for field names in their CAL source form
* as Strings. Ordinal fields are sorted by their int parts prior
* to the textual fields, which are sorted alphabetically (via the
* default ordering on Strings).
* @author Bo Ilic
*/
public static class CalSourceFormComparator implements Comparator<String> {
public int compare(String s1, String s2) {
if (s1.charAt(0) == '#') {
if (s2.charAt(0) == '#') {
int ordinal1 = Integer.parseInt(s1.substring(1));
int ordinal2 = Integer.parseInt(s2.substring(1));
return (ordinal1 < ordinal2) ? -1 : (ordinal1 == ordinal2 ? 0 : 1);
}
return -1;
}
if (s2.charAt(0) == '#') {
return 1;
}
return s1.compareTo(s2);
}
}
/**
* Ordinal field names, which always start with a # followed by a natural number
* in CAL source.
* @author Bo Ilic
*/
public static final class Ordinal extends FieldName {
static final int serializationSchema = 0;
/** must be greater than 0. */
private final int ordinal;
private static final Ordinal ORD_1 = new Ordinal(1);
private static final Ordinal ORD_2 = new Ordinal(2);
private static final Ordinal ORD_3 = new Ordinal(3);
private static final Ordinal ORD_4 = new Ordinal(4);
private static final Ordinal ORD_5 = new Ordinal(5);
private static final Ordinal ORD_6 = new Ordinal(6);
private static final Ordinal ORD_7 = new Ordinal(7);
private static final Ordinal ORD_8 = new Ordinal(8);
private static final Ordinal ORD_9 = new Ordinal(9);
private static final Ordinal ORD_10 = new Ordinal(10);
private static final Ordinal ORD_11 = new Ordinal(11);
private static final Ordinal ORD_12 = new Ordinal(12);
private static final Ordinal ORD_13 = new Ordinal(13);
private static final Ordinal ORD_14 = new Ordinal(14);
private static final Ordinal ORD_15 = new Ordinal(15);
private Ordinal (int ordinal) {
if (ordinal <= 0) {
throw new IllegalArgumentException("ordinal must be greater than 0");
}
this.ordinal = ordinal;
}
private static Ordinal make(int ordinal) {
switch (ordinal) {
case 1: return ORD_1;
case 2: return ORD_2;
case 3: return ORD_3;
case 4: return ORD_4;
case 5: return ORD_5;
case 6: return ORD_6;
case 7: return ORD_7;
case 8: return ORD_8;
case 9: return ORD_9;
case 10: return ORD_10;
case 11: return ORD_11;
case 12: return ORD_12;
case 13: return ORD_13;
case 14: return ORD_14;
case 15: return ORD_15;
default: return new Ordinal(ordinal);
}
}
/**
* @param ordinalFieldName for example, "#123" or "#17"
* @return true if ordinalFieldName is of the form ('#') ('1'..'9') ('0'..'9')* and the resulting
* int value is <= Integer.MAX_VALUE.
*/
public static boolean isValidCalSourceForm (String ordinalFieldName) {
if (ordinalFieldName == null ||
ordinalFieldName.length() < 2 ||
ordinalFieldName.charAt(0) != '#') {
return false;
}
//verify the pattern (1-9)(0-9)*
char c = ordinalFieldName.charAt(1);
if (c < '1' || c > '9') {
return false;
}
for (int i = 2, length = ordinalFieldName.length(); i < length; ++i) {
c = ordinalFieldName.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
//verify that the resulting integer is in range e.g. <= Integer.MAX_VALUE.
try {
Integer.parseInt(ordinalFieldName.substring(1));
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
public int getOrdinal() {
return ordinal;
}
@Override
public String getCalSourceForm() {
return "#" + ordinal;
}
@Override
public String toString () {
return getCalSourceForm();
}
@Override
public boolean equals (Object other) {
if (other instanceof Ordinal) {
return ordinal == ((Ordinal)other).ordinal;
}
return false;
}
@Override
public int hashCode () {
return ordinal;
}
public int compareTo(FieldName other) {
if (other instanceof Textual) {
//ordinals are always less than textuals
return -1;
}
if (other instanceof Ordinal) {
int otherOrdinal = ((Ordinal)other).ordinal;
return ordinal < otherOrdinal ? -1 : (ordinal == otherOrdinal ? 0 : 1);
}
//incomparable types must throw a ClassCastException
throw new ClassCastException();
}
}
/**
* Textual field names. These are lowercase starting valid CAL identifiers.
* @author Bo Ilic
*/
public static final class Textual extends FieldName {
private final String name;
private Textual (String name) {
if (name == null) {
throw new NullPointerException();
}
this.name = name;
}
@Override
public String getCalSourceForm() {
return name;
}
/**
* @param textualFieldName for example, "orderDate"
* @return true if textualFieldName is a valid textual field name. This is the same condition as being a valid
* function name i.e. starts with a lowercase letter, and not a keyword name.
*/
public static boolean isValidCalSourceForm (String textualFieldName) {
return LanguageInfo.isValidFunctionName(textualFieldName);
}
@Override
public String toString () {
return getCalSourceForm();
}
@Override
public boolean equals(Object other) {
if (other instanceof Textual) {
return name.equals(((Textual)other).name);
}
return false;
}
@Override
public int hashCode () {
return name.hashCode();
}
public int compareTo(FieldName other) {
if (other instanceof Ordinal) {
//textuals are always greater than ordinals
return 1;
}
if (other instanceof Textual) {
return name.compareTo(((Textual)other).name);
}
//incomparable types must throw a ClassCastException
throw new ClassCastException();
}
}
/**
* @param calSourceFormFieldName fieldName as a String, e.g. "#2", "#454", "orderDate" etc.
* @return FieldName null if calSourceFormFieldName is not a valid field name.
*/
public static FieldName make(String calSourceFormFieldName) {
if (!FieldName.isValidCalSourceForm(calSourceFormFieldName)) {
return null;
}
if (calSourceFormFieldName.charAt(0) == '#'){
return Ordinal.make(Integer.parseInt(calSourceFormFieldName.substring(1)));
}
return new Textual(calSourceFormFieldName);
}
/**
* @return the field name in the form used in CAL source code e.g. #3, orderDate etc.
*/
abstract public String getCalSourceForm();
public static boolean isValidCalSourceForm (String fieldName) {
return Ordinal.isValidCalSourceForm(fieldName) || Textual.isValidCalSourceForm(fieldName);
}
public static FieldName.Ordinal makeOrdinalField(int ordinal) {
return Ordinal.make(ordinal);
}
public static FieldName.Textual makeTextualField(String name) {
if (!isValidCalSourceForm(name)) {
return null;
}
return new Textual(name);
}
}