com.hp.autonomy.aci.content.fieldtext.Specifier Maven / Gradle / Ivy
Show all versions of content-parameter-api Show documentation
/*
* Copyright 2009-2015 Hewlett-Packard Development Company, L.P.
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
*/
package com.hp.autonomy.aci.content.fieldtext;
import com.autonomy.aci.client.util.AciURLCodec;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* A class to represent a general fieldtext specifier of the form:
*
* OPERATOR{values}:fields
*
* In the most general case, the values consist of comma-separated, URL-encoded Strings and the
* fields are colon-separated Strings. Subclasses may wish to impose further restrictions on
* the forms of these aspects of the specifier, for example allowing only numeric values. As there is no reliable way to
* distinguish between colons in XML namespaces and colons in metafields (e.g. autn:date), only namespaces will be
* escaped automatically. To use a metafield the colon must be escaped to an underscore manually.
*
* It should not usually be necessary to instantiate this class directly as subclasses exist for all common fieldtext
* operators. This class and its known subclasses are all immutable but each class provides a number of constructors to
* make instantiation as convenient as possible.
*
*/
public class Specifier extends AbstractFieldText {
private final List fields;
private final List values;
/**
* The fieldtext operator for the specifier. It will be in uppercase and interned, allowing == comparison to String
* literals.
*/
public final String OPERATOR;
/**
* Creates a new specifier. e.g.
*
* new Specifier("OPERATOR", "TITLE", "1 2", "3 4").toString();
*
* evaluates to:
*
* "OPERATOR{1%202,3%204}:TITLE"
*
* @param operator The fieldtext operator of the specifier.
* @param field The name of the IDOL field.
* @param values A String... of field values.
*/
public Specifier(final String operator, final String field, final String... values) {
this(operator, Collections.singletonList(field), toIterable(values));
}
/**
* Creates a new specifier.
*
* @param operator The fieldtext operator of the specifier.
* @param field The name of the IDOL field.
* @param values An Iterable of field values.
*/
public Specifier(final String operator, final String field, final Iterable extends String> values) {
this(operator, Collections.singletonList(field), values);
}
/**
* Creates a new specifier. Colons in field names will be converted to underscores. e.g.
*
* new Specifier("OPERATOR", new String[]{"A", "B"}, new String[]{"1 2", "3 4"}).toString();
*
* evaluates to:
*
* "OPERATOR{1%202,3%204}:A:B"
*
* @param operator The fieldtext operator of the specifier.
* @param fields A String[] of field names.
* @param values A String... of field values.
*/
public Specifier(final String operator, final String[] fields, final String... values) {
this(operator, toIterable(fields), toIterable(values));
}
/**
* Creates a new specifier. Colons in field names will be converted to underscores.
*
* @param operator The fieldtext operator of the specifier.
* @param fields A String[] of field names.
* @param values An Iterable of field values.
*/
public Specifier(final String operator, final String[] fields, final Iterable extends String> values) {
this(operator, toIterable(fields), values);
}
/**
* Creates a new specifier. Colons in field names will be converted to underscores. e.g.
*
*
* List<String> fields = new ArrayList<String>();
* fields.add("A");
* fields.add("B:C");
*
* new Specifier("OPERATOR", fields, "yes", "no").toString();
*
*
* evaluates to:
*
* "OPERATOR{yes,no}:A:B_C"
*
* @param operator The fieldtext operator of the specifier.
* @param fields An Iterable of field names.
* @param values A String... of field values.
*/
public Specifier(final String operator, final Iterable extends String> fields, final String... values) {
this(operator, fields, toIterable(values));
}
/**
* Creates a new specifier. Colons in field names will be converted to underscores.
*
* @param operator The fieldtext operator for the specifier.
* @param fields An Iterable of field names.
* @param values An Iterable of field values.
*/
public Specifier(final String operator, final Iterable extends String> fields, final Iterable extends String> values) {
Validate.isTrue(StringUtils.isNotBlank(operator), "Operator must not be blank");
Validate.notNull(fields, "Fields must not be null");
Validate.notNull(values, "Values must not be null");
this.fields = Collections.unmodifiableList(resolveFields(fields));
Validate.notEmpty(this.fields, "No valid fields were specified");
OPERATOR = operator.trim().toUpperCase(Locale.ENGLISH).intern();
this.values = Collections.unmodifiableList(resolveValues(values));
}
/**
* Private helper function for converting a String[] to an Iterable.
*
* @param strings A String[] or null.
* @return An Iterable or null.
*/
private static Iterable toIterable(final String[] strings) {
if (strings == null) {
return null;
}
return Arrays.asList(strings);
}
/**
* Private helper method for setting the field names. It converts colons to underscores and removes any blanks or
* excess whitespace. Instances are immutable so this method cannot be made public.
*
* @param fields A non-null Iterable of field names.
*/
private static List resolveFields(final Iterable extends String> fields) {
final List fieldList = new ArrayList();
for (final String field : fields) {
Validate.isTrue(StringUtils.isNotBlank(field), "One of the specified fields was blank");
fieldList.add(field.trim());
}
return fieldList;
}
/**
* Private helper method for setting the field values. nulls are not permitted. Instances are immutable so this
* method cannot be made public.
*
* @param values A non-null Iterable of field values.
*/
private static List resolveValues(final Iterable extends String> values) {
final List valuesList = new ArrayList();
for(final String value : values) {
Validate.notNull(value, "One of the specified values was null");
valuesList.add(value);
}
return valuesList;
}
/**
* All specifiers have a size of 1.
*
* @return 1.
*/
@Override
public final int size() {
return 1;
}
/**
* Specifiers cannot be empty.
*
* @return false.
*/
@Override
public final boolean isEmpty() {
return false;
}
/**
* Accessor for the OPERATOR field.
*
* @return The OPERATOR field.
*/
public final String getOperator() {
return OPERATOR;
}
/**
* Accessor for the colon-separated, String representation of the field names for this specifier.
*
* @return The combined field names.
*/
private String getFieldsString() {
final StringBuilder fieldsString = new StringBuilder();
for (final String field : fields) {
// XML namespaces require that the colon be percent-escaped but nothing else
fieldsString.append(':').append(field.replace(":", "%3A"));
}
return fieldsString.toString();
}
/**
* Accessor for the list of field names for this specifier. Some specifiers
* place restrictions on the number of fields they require and may provide
* more suitable accessors for accessing the field names.
*
* As instances are immutable, the returned list does not support modifications.
*
* @return The list of field names.
*/
public final List getFields() {
return fields;
}
/**
* Accessor for the specifier's values. The values are URL encoded and
* separated by commas.
*
* @return The specifier's value.
*/
protected String getValuesString() {
final StringBuilder builder = new StringBuilder();
for(final String value : values) {
builder.append(AciURLCodec.getInstance().encode(value)).append(',');
}
if(builder.length() > 0) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.toString();
}
/**
* Accessor for the list of field values for this specifier. An empty value
* could be signified by either an empty list or a list containing just the
* empty String - neither the list nor its values should ever be
* null.
*
* As instances are immutable, the returned list does not support modifications.
*
* @return A clone of the list of field values.
*/
public final List getValues() {
return values;
}
/**
* The String representation of the specifier, as it should be sent
* to IDOL.
*
* @return An IDOL fieldtext String.
*/
@Override
public final String toString() {
return OPERATOR + '{' + getValuesString() + '}' + getFieldsString();
}
@Override
public final FieldText AND(final FieldText fieldText) {
return super.AND(fieldText);
}
@Override
public final FieldText OR(final FieldText fieldText) {
return super.OR(fieldText);
}
@Override
public final FieldText NOT() {
return super.NOT();
}
@Override
public final FieldText XOR(final FieldText fieldText) {
return super.XOR(fieldText);
}
// For now we only allow Specifier WHEN Specifier
@Override
public final FieldText WHEN(final FieldText fieldText) {
return super.WHEN(fieldText);
}
// For now we only allow Specifier WHENn Specifier
@Override
public final FieldText WHEN(final int depth, final FieldText fieldText) {
return super.WHEN(depth, fieldText);
}
@Override
public final boolean equals(final Object obj) {
return super.equals(obj);
}
@Override
public final int hashCode() {
return super.hashCode();
}
}