use of java.text.FieldPosition in project sis by apache.
the class RangeFormatTest method testFormatDatesToCharacterIterator.
/**
* Tests the {@link RangeFormat#formatToCharacterIterator(Object)} method with dates.
*/
@Test
public void testFormatDatesToCharacterIterator() {
format = new RangeFormat(Locale.FRANCE, TimeZone.getTimeZone(UTC));
minPos = new FieldPosition(RangeFormat.Field.MIN_VALUE);
maxPos = new FieldPosition(RangeFormat.Field.MAX_VALUE);
parsePos = new ParsePosition(0);
final long HOUR = 60L * 60 * 1000;
final long DAY = 24L * HOUR;
final long YEAR = round(365.25 * DAY);
Range<Date> range = new Range<>(Date.class, new Date(15 * DAY + 18 * HOUR), true, new Date(20 * YEAR + 15 * DAY + 9 * HOUR), true);
AttributedCharacterIterator it = format.formatToCharacterIterator(range);
String text = it.toString();
findYears(it, RangeFormat.Field.MIN_VALUE, minPos);
findYears(it, RangeFormat.Field.MAX_VALUE, maxPos);
assertEquals("[16/01/70 18:00 … 16/01/90 09:00]", text);
assertEquals(7, minPos.getBeginIndex());
assertEquals(9, minPos.getEndIndex());
assertEquals(24, maxPos.getBeginIndex());
assertEquals(26, maxPos.getEndIndex());
assertEquals(range, parse(text));
/*
* Try again with the infinity symbol in one endpoint.
*/
range = new Range<>(Date.class, (Date) null, true, new Date(20 * YEAR), true);
it = format.formatToCharacterIterator(range);
text = it.toString();
findYears(it, RangeFormat.Field.MAX_VALUE, maxPos);
assertEquals("(−∞ … 01/01/90 00:00]", text);
assertEquals(12, maxPos.getBeginIndex());
assertEquals(14, maxPos.getEndIndex());
assertEquals(range, parse(text));
range = new Range<>(Date.class, new Date(20 * YEAR), true, (Date) null, true);
it = format.formatToCharacterIterator(range);
text = it.toString();
findYears(it, RangeFormat.Field.MIN_VALUE, minPos);
assertEquals("[01/01/90 00:00 … ∞)", text);
assertEquals(7, minPos.getBeginIndex());
assertEquals(9, minPos.getEndIndex());
assertEquals(range, parse(text));
}
use of java.text.FieldPosition in project sis by apache.
the class RangeFormatTest method testAlternateFormat.
/**
* Tests the {@link RangeFormat#format(Object, StringBuffer, FieldPosition)} method
* using the alternate format.
*/
@Test
public void testAlternateFormat() {
format = new RangeFormat(Locale.CANADA);
minPos = new FieldPosition(RangeFormat.Field.MIN_VALUE);
maxPos = new FieldPosition(RangeFormat.Field.MAX_VALUE);
format.setAlternateForm(true);
assertEquals("[-10 … 20]", format(NumberRange.create(-10, true, 20, true)));
assertEquals("]-3 … 4[", format(NumberRange.create(-3, false, 4, false)));
assertEquals("[2 … 8[", format(NumberRange.create(2, true, 8, false)));
}
use of java.text.FieldPosition in project sis by apache.
the class ParameterFormat method format.
/**
* Implementation of public {@code format(…)} methods for all content levels except {@code NAME_SUMMARY}.
*
* @param name the group name, usually {@code descriptor.getName().getCode()}.
* @param group the parameter descriptor, usually {@code values.getDescriptor()}.
* @param values the parameter values, or {@code null} if none.
* @throws IOException if an error occurred while writing to the given appendable.
*/
private void format(final String name, final ParameterDescriptorGroup group, final ParameterValueGroup values, final Appendable out) throws IOException {
final boolean isBrief = (contentLevel == ContentLevel.BRIEF);
final boolean showObligation = !isBrief || (values == null);
final boolean hasColors = (colors != null);
final String lineSeparator = this.lineSeparator;
final Map<String, Integer> remarks = new LinkedHashMap<>();
final ParameterTableRow header = new ParameterTableRow(group, displayLocale, preferredCodespaces, remarks, isBrief);
final String groupCodespace = header.getCodeSpace();
/*
* Prepares the informations to be printed later as table rows. We scan all rows before to print them
* in order to compute the width of codespaces. During this process, we split the objects to be printed
* later in two collections: simple parameters are stored as (descriptor,value) pairs, while groups are
* stored in an other collection for deferred formatting after the simple parameters.
*/
int codespaceWidth = 0;
final Collection<?> elements = (values != null) ? values.values() : group.descriptors();
final Map<GeneralParameterDescriptor, ParameterTableRow> descriptorValues = new LinkedHashMap<>(hashMapCapacity(elements.size()));
// To be created only if needed (it is usually not).
List<Object> deferredGroups = null;
for (final Object element : elements) {
final GeneralParameterValue parameter;
final GeneralParameterDescriptor descriptor;
if (values != null) {
parameter = (GeneralParameterValue) element;
descriptor = parameter.getDescriptor();
} else {
parameter = null;
descriptor = (GeneralParameterDescriptor) element;
}
if (descriptor instanceof ParameterDescriptorGroup) {
if (deferredGroups == null) {
deferredGroups = new ArrayList<>(4);
}
deferredGroups.add(element);
continue;
}
/*
* In the vast majority of cases, there is only one value for each parameter. However
* if we find more than one value, we will append all extra occurrences in a "multiple
* values" list to be formatted in the same row.
*/
Object value = null;
Unit<?> unit = null;
if (parameter instanceof ParameterValue<?>) {
final ParameterValue<?> p = (ParameterValue<?>) parameter;
value = p.getValue();
unit = p.getUnit();
} else if (descriptor instanceof ParameterDescriptor<?>) {
final ParameterDescriptor<?> p = (ParameterDescriptor<?>) descriptor;
value = p.getDefaultValue();
unit = p.getUnit();
}
ParameterTableRow row = descriptorValues.get(descriptor);
if (row == null) {
row = new ParameterTableRow(descriptor, displayLocale, preferredCodespaces, remarks, isBrief);
descriptorValues.put(descriptor, row);
if (row.codespaceWidth > codespaceWidth) {
codespaceWidth = row.codespaceWidth;
}
}
row.addValue(value, unit);
}
/*
* Finished to collect the values. Now transform the values:
*
* - Singleton value of array types (either primitive or not) are wrapped into a list.
* - Values are formatted.
* - Value domains are formatted.
* - Position of the character on which to do the alignment are remembered.
*/
int unitWidth = 0;
int valueDomainAlignment = 0;
boolean writeCodespaces = (groupCodespace == null);
final StringBuffer buffer = new StringBuffer();
final FieldPosition dummyFP = new FieldPosition(-1);
for (final Map.Entry<GeneralParameterDescriptor, ParameterTableRow> entry : descriptorValues.entrySet()) {
final GeneralParameterDescriptor descriptor = entry.getKey();
if (descriptor instanceof ParameterDescriptor<?>) {
final ParameterTableRow row = entry.getValue();
/*
* Verify if all rows use the same codespace than the header, in which case we can omit
* row codespace formatting.
*/
if (!writeCodespaces && !groupCodespace.equals(entry.getValue().getCodeSpace())) {
writeCodespaces = true;
}
/*
* Format the value domain, so we can compute the character position on which to perform alignment.
*/
final Range<?> valueDomain = Parameters.getValueDomain((ParameterDescriptor<?>) descriptor);
if (valueDomain != null) {
final int p = row.setValueDomain(valueDomain, getFormat(Range.class), buffer);
if (p > valueDomainAlignment) {
valueDomainAlignment = p;
}
}
/*
* Singleton array conversion. Because it may be an array of primitive types, we can not just
* cast to Object[]. Then formats the units, with a space before the unit if the symbol is a
* letter or digit (i.e. we do not put a space in front of ° symbol for instance).
*/
row.expandSingleton();
final int length = row.units.size();
for (int i = 0; i < length; i++) {
final Object unit = row.units.get(i);
if (unit != null) {
if (getFormat(Unit.class).format(unit, buffer, dummyFP).length() != 0) {
if (Character.isLetterOrDigit(buffer.codePointAt(0))) {
buffer.insert(0, ' ');
}
}
final String symbol = buffer.toString();
row.units.set(i, symbol);
buffer.setLength(0);
final int p = symbol.length();
if (p > unitWidth) {
unitWidth = p;
}
}
}
}
}
/*
* Finished to prepare information. Now begin the actual writing.
* First, formats the table header (i.e. the column names).
*/
final Vocabulary resources = Vocabulary.getResources(displayLocale);
header.writeIdentifiers(out, true, colors, false, lineSeparator);
out.append(lineSeparator);
final char horizontalBorder = isBrief ? '─' : '═';
final TableAppender table = (isBrief || !columnSeparator.equals(SEPARATOR)) ? new TableAppender(out, columnSeparator) : new TableAppender(out);
table.setMultiLinesCells(true);
table.nextLine(horizontalBorder);
int numColumnsBeforeValue = 0;
for (int i = 0; ; i++) {
boolean end = false;
final short key;
switch(i) {
case 0:
{
key = Vocabulary.Keys.Name;
break;
}
case 1:
{
key = Vocabulary.Keys.Type;
break;
}
case 2:
{
if (!showObligation) {
continue;
}
key = Vocabulary.Keys.Obligation;
break;
}
case 3:
{
key = Vocabulary.Keys.ValueDomain;
break;
}
case 4:
{
key = (values == null) ? Vocabulary.Keys.DefaultValue : Vocabulary.Keys.Value;
end = true;
break;
}
default:
throw new AssertionError(i);
}
if (hasColors)
table.append(X364.BOLD.sequence());
table.append(resources.getString(key));
if (hasColors)
table.append(X364.NORMAL.sequence());
if (!writeCodespaces && i == 0) {
table.append(" (").append(groupCodespace).append(')');
}
if (end)
break;
nextColumn(table);
numColumnsBeforeValue++;
}
table.nextLine();
/*
* Now process to the formatting of (descriptor,value) pairs. Each descriptor's alias
* will be formatted on its own line in a table row. If there is more than one value,
* then each value will be formatted on its own line as well. Note that the values may
* be null if there is none.
*/
char horizontalLine = horizontalBorder;
for (final Map.Entry<GeneralParameterDescriptor, ParameterTableRow> entry : descriptorValues.entrySet()) {
if (horizontalLine != 0) {
table.nextLine('─');
}
horizontalLine = isBrief ? 0 : '─';
final ParameterTableRow row = entry.getValue();
row.codespaceWidth = codespaceWidth;
row.writeIdentifiers(table, writeCodespaces, null, hasColors, lineSeparator);
nextColumn(table);
final GeneralParameterDescriptor generalDescriptor = entry.getKey();
if (generalDescriptor instanceof ParameterDescriptor<?>) {
/*
* Writes value type.
*/
final ParameterDescriptor<?> descriptor = (ParameterDescriptor<?>) generalDescriptor;
final Class<?> valueClass = descriptor.getValueClass();
if (valueClass != null) {
// Should never be null, but let be safe.
table.append(getFormat(Class.class).format(valueClass, buffer, dummyFP).toString());
}
nextColumn(table);
buffer.setLength(0);
/*
* Writes the obligation (mandatory or optional).
*/
if (showObligation) {
final int minimumOccurs = descriptor.getMinimumOccurs();
final int maximumOccurs = descriptor.getMaximumOccurs();
if (maximumOccurs == 1) {
table.append(resources.getString(minimumOccurs == 0 ? Vocabulary.Keys.Optional : Vocabulary.Keys.Mandatory));
} else {
final Format f = getFormat(Integer.class);
table.append(f.format(minimumOccurs, buffer, dummyFP).toString()).append(" … ");
buffer.setLength(0);
if (maximumOccurs == Integer.MAX_VALUE) {
table.append('∞');
} else {
table.append(f.format(maximumOccurs, buffer, dummyFP).toString());
buffer.setLength(0);
}
}
nextColumn(table);
}
/*
* Writes minimum and maximum values, together with the unit of measurement (if any).
*/
final String valueDomain = row.valueDomain;
if (valueDomain != null) {
table.append(CharSequences.spaces(valueDomainAlignment - row.valueDomainAlignment)).append(valueDomain);
}
nextColumn(table);
/*
* Writes the values, each on its own line, together with their unit of measurement.
*/
final byte alignment = Number.class.isAssignableFrom(valueClass) ? TableAppender.ALIGN_RIGHT : TableAppender.ALIGN_LEFT;
table.setCellAlignment(alignment);
final int length = row.values.size();
for (int i = 0; i < length; i++) {
Object value = row.values.get(i);
if (value != null) {
if (i != 0) {
/*
* If the same parameter is repeated more than once (not allowed by ISO 19111,
* but this extra flexibility is allowed by Apache SIS), write the ditto mark
* in all previous columns (name, type, etc.) on a new row.
*/
final String ditto = resources.getString(Vocabulary.Keys.DittoMark);
table.nextLine();
table.setCellAlignment(TableAppender.ALIGN_CENTER);
for (int j = 0; j < numColumnsBeforeValue; j++) {
table.append(ditto);
nextColumn(table);
}
table.setCellAlignment(alignment);
}
/*
* Format the value followed by the unit of measure, or followed by spaces if there is no unit
* for this value. The intent is the right align the numerical value rather than the numerical
* + unit tupple.
*/
final Format format = getFormat(value.getClass());
if (format != null) {
if (format instanceof NumberFormat && value instanceof Number) {
configure((NumberFormat) format, Math.abs(((Number) value).doubleValue()));
}
value = format.format(value, buffer, dummyFP);
}
table.append(value.toString());
buffer.setLength(0);
int pad = unitWidth;
final String unit = (String) row.units.get(i);
if (unit != null) {
table.append(unit);
pad -= unit.length();
}
table.append(CharSequences.spaces(pad));
}
}
}
table.nextLine();
table.setCellAlignment(TableAppender.ALIGN_LEFT);
}
table.nextLine(horizontalBorder);
table.flush();
/*
* Write remarks, if any.
*/
for (final Map.Entry<String, Integer> remark : remarks.entrySet()) {
ParameterTableRow.writeFootnoteNumber(out, remark.getValue());
out.append(' ').append(remark.getKey()).append(lineSeparator);
}
/*
* Now formats all groups deferred to the end of this table, with recursive calls to
* this method (recursive calls use their own TableWriter instance, so they may result
* in a different cell layout). Most of the time, there is no such additional group.
*/
if (deferredGroups != null) {
for (final Object element : deferredGroups) {
final ParameterValueGroup value;
final ParameterDescriptorGroup descriptor;
if (element instanceof ParameterValueGroup) {
value = (ParameterValueGroup) element;
descriptor = value.getDescriptor();
} else {
value = null;
descriptor = (ParameterDescriptorGroup) element;
}
out.append(lineSeparator);
format(name + '/' + descriptor.getName().getCode(), descriptor, value, out);
}
}
}
use of java.text.FieldPosition in project sis by apache.
the class RangeFormat method format.
/**
* Implementation of the format methods.
*
* @param range the range to format.
* @param toAppendTo where the text is to be appended.
* @param pos identifies a field in the formatted text, or {@code null} if none.
* @param characterIterator the character iterator for which the attributes need to be set, or null if none.
*/
@SuppressWarnings("fallthrough")
private void format(final Range<?> range, final StringBuffer toAppendTo, final FieldPosition pos, final FormattedCharacterIterator characterIterator) {
/*
* Special case for an empty range. This is typically formatted as "{}". The field
* position is unconditionally set to the empty substring inside the brackets.
*/
int fieldPos = getField(pos);
if (range.isEmpty()) {
toAppendTo.appendCodePoint(openSet);
if (fieldPos >= MIN_VALUE_FIELD && fieldPos <= UNIT_FIELD) {
final int p = toAppendTo.length();
// First index, inclusive.
pos.setBeginIndex(p);
// Last index, exclusive
pos.setEndIndex(p);
}
toAppendTo.appendCodePoint(closeSet);
return;
}
/*
* Format a non-empty range by looping over all possible fields.
*
* Secial case: if minimal and maximal values are the same,
* formats only the maximal value.
*/
final Comparable<?> minValue = range.getMinValue();
final Comparable<?> maxValue = range.getMaxValue();
final boolean isSingleton = (minValue != null) && minValue.equals(maxValue);
int field = MIN_VALUE_FIELD;
if (isSingleton) {
if (fieldPos == MIN_VALUE_FIELD) {
fieldPos = MAX_VALUE_FIELD;
}
field = MAX_VALUE_FIELD;
}
// Select the char for the first condition to be true below:
toAppendTo.appendCodePoint(isSingleton ? openSet : range.isMinIncluded() ? openInclusive : alternateForm ? openExclusiveAlt : /* otherwise */
openExclusive);
for (; field <= UNIT_FIELD; field++) {
final Object value;
switch(field) {
case MIN_VALUE_FIELD:
value = minValue;
break;
case MAX_VALUE_FIELD:
value = maxValue;
break;
case UNIT_FIELD:
value = range.unit();
break;
default:
throw new AssertionError(field);
}
int startPosition = toAppendTo.length();
if (value == null) {
switch(field) {
// Fall through
case MIN_VALUE_FIELD:
toAppendTo.append(minusSign != '-' ? minusSign : '−');
case MAX_VALUE_FIELD:
toAppendTo.append(infinity);
break;
}
} else {
final Format format;
if (field == UNIT_FIELD) {
if (insertSpaceBeforeUnit((Unit) value)) {
startPosition = toAppendTo.append(' ').length();
}
format = unitFormat;
} else {
format = elementFormat;
}
if (characterIterator != null) {
characterIterator.append(format.formatToCharacterIterator(value), toAppendTo);
} else {
format.format(value, toAppendTo, new FieldPosition(-1));
}
}
/*
* At this point, the field has been formatted. Now store the field index,
* then append the separator between this field and the next one.
*/
if (characterIterator != null) {
characterIterator.addFieldLimit(Field.forCode(field), value, startPosition);
}
if (field == fieldPos) {
pos.setBeginIndex(startPosition);
pos.setEndIndex(toAppendTo.length());
}
switch(field) {
case MIN_VALUE_FIELD:
{
toAppendTo.append(' ').append(separator).append(' ');
break;
}
case MAX_VALUE_FIELD:
{
// Select the char for the first condition to be true below:
toAppendTo.appendCodePoint(isSingleton ? closeSet : range.isMaxIncluded() ? closeInclusive : alternateForm ? closeExclusiveAlt : /* otherwise */
closeExclusive);
break;
}
}
}
}
use of java.text.FieldPosition in project tomcat70 by apache.
the class ServerCookie method appendCookieValue.
// -------------------- Cookie parsing tools
public static void appendCookieValue(StringBuffer headerBuf, int version, String name, String value, String path, String domain, String comment, int maxAge, boolean isSecure, boolean isHttpOnly) {
StringBuffer buf = new StringBuffer();
// Servlet implementation checks name
buf.append(name);
buf.append("=");
// Servlet implementation does not check anything else
/*
* The spec allows some latitude on when to send the version attribute
* with a Set-Cookie header. To be nice to clients, we'll make sure the
* version attribute is first. That means checking the various things
* that can cause us to switch to a v1 cookie first.
*
* Note that by checking for tokens we will also throw an exception if a
* control character is encountered.
*/
// Start by using the version we were asked for
int newVersion = version;
// If it is v0, check if we need to switch
if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(value) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(value))) {
// HTTP token in value - need to use v1
newVersion = 1;
}
if (newVersion == 0 && comment != null) {
// Using a comment makes it a v1 cookie
newVersion = 1;
}
if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(path) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(path))) {
// HTTP token in path - need to use v1
newVersion = 1;
}
if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(domain) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(domain))) {
// HTTP token in domain - need to use v1
newVersion = 1;
}
// Now build the cookie header
// Value
maybeQuote(buf, value);
// Add version 1 specific information
if (newVersion == 1) {
// Version=1 ... required
buf.append("; Version=1");
// Comment=comment
if (comment != null) {
buf.append("; Comment=");
maybeQuote(buf, comment);
}
}
// Add domain information, if present
if (domain != null) {
buf.append("; Domain=");
maybeQuote(buf, domain);
}
// Max-Age=secs ... or use old "Expires" format
if (maxAge >= 0) {
if (newVersion > 0) {
buf.append("; Max-Age=");
buf.append(maxAge);
}
// They do understand Expires, even with V1 cookies!
if (newVersion == 0 || CookieSupport.ALWAYS_ADD_EXPIRES) {
// Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
buf.append("; Expires=");
// To expire immediately we need to set the time in past
if (maxAge == 0) {
buf.append(ancientDate);
} else {
OLD_COOKIE_FORMAT.get().format(new Date(System.currentTimeMillis() + maxAge * 1000L), buf, new FieldPosition(0));
}
}
}
// Path=path
if (path != null) {
buf.append("; Path=");
maybeQuote(buf, path);
}
// Secure
if (isSecure) {
buf.append("; Secure");
}
// HttpOnly
if (isHttpOnly) {
buf.append("; HttpOnly");
}
headerBuf.append(buf);
}
Aggregations