com.hp.autonomy.aci.content.fieldtext.Specifier.java Source code

Java tutorial

Introduction

Here is the source code for com.hp.autonomy.aci.content.fieldtext.Specifier.java

Source

/*
 * 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:
 *
 * <pre>OPERATOR{values}:fields</pre>
 *
 * In the most general case, the <tt>values</tt> consist of comma-separated, URL-encoded <tt>Strings</tt> and the
 * <tt>fields</tt> are colon-separated <tt>Strings</tt>. 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.
 * <p>
 * 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<String> fields;

    private final List<String> 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.
     *
     * <pre>    new Specifier("OPERATOR", "TITLE", "1 2", "3 4").toString();</pre>
     *
     * evaluates to:
     *
     * <pre>    "OPERATOR{1%202,3%204}:TITLE"</pre>
     *
     * @param operator The fieldtext operator of the specifier.
     * @param field The name of the IDOL field.
     * @param values A <tt>String...</tt> 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 <tt>Iterable</tt> 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.
     *
     * <pre>    new Specifier("OPERATOR", new String[]{"A", "B"}, new String[]{"1 2", "3 4"}).toString();</pre>
     *
     * evaluates to:
     *
     * <pre>    "OPERATOR{1%202,3%204}:A:B"</pre>
     *
     * @param operator The fieldtext operator of the specifier.
     * @param fields A <tt>String[]</tt> of field names.
     * @param values A <tt>String...</tt> 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 <tt>String[]</tt> of field names.
     * @param values An <tt>Iterable</tt> 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.
     *
     * <pre>
     *     List&lt;String&gt; fields = new ArrayList&lt;String&gt;();
     *     fields.add("A");
     *     fields.add("B:C");
     *
     *     new Specifier("OPERATOR", fields, "yes", "no").toString();
     * </pre>
     *
     * evaluates to:
     *
     * <pre>    "OPERATOR{yes,no}:A:B_C"</pre>
     *
     * @param operator The fieldtext operator of the specifier.
     * @param fields An <tt>Iterable</tt> of field names.
     * @param values A <tt>String...</tt> 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 <tt>Iterable</tt> of field names.
     * @param values An <tt>Iterable</tt> 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<String> 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<String> resolveFields(final Iterable<? extends String> fields) {
        final List<String> fieldList = new ArrayList<String>();

        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<String> resolveValues(final Iterable<? extends String> values) {
        final List<String> valuesList = new ArrayList<String>();

        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 <tt>1</tt>.
     *
     * @return <tt>1</tt>.
     */
    @Override
    public final int size() {
        return 1;
    }

    /**
     * Specifiers cannot be empty.
     *
     * @return <tt>false</tt>.
     */
    @Override
    public final boolean isEmpty() {
        return false;
    }

    /**
     * Accessor for the <tt>OPERATOR</tt> field.
     *
     * @return The <tt>OPERATOR</tt> field.
     */
    public final String getOperator() {
        return OPERATOR;
    }

    /**
     * Accessor for the colon-separated, <tt>String</tt> 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<String> 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 <tt>String</tt> - neither the list nor its values should ever be
     * <tt>null</tt>.
     *
     * As instances are immutable, the returned list does not support modifications.
     *
     * @return A clone of the list of field values.
     */
    public final List<String> getValues() {
        return values;
    }

    /**
     * The <tt>String</tt> representation of the specifier, as it should be sent
     * to IDOL.
     *
     * @return An IDOL fieldtext <tt>String</tt>.
     */
    @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();
    }

}