/* * Copyright (C) 2014 Jörg Prante * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xbib.elasticsearch.common.util; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import java.io.IOException; /** * This class represents one or many values. Each value is represented at most * once. New values are appended. */ public class Values<O extends Object> implements ToXContent { /** * The values are implemented as an object array */ @SuppressWarnings({"unchecked"}) private O[] values = (O[]) new Object[0]; /** * Create new Values from an existing values by appending a value. * * @param old existing values or null if values should be created * @param value a new value * @param sequence true if value should be splitted by commas to multiple values */ @SuppressWarnings({"unchecked"}) public Values(Object old, O value, boolean sequence) { if (old instanceof Values) { O[] vals = (O[]) ((Values) old).getValues(); if (vals != null) { this.values = vals; } } O[] newValues; if (sequence && value != null) { newValues = (O[]) value.toString().split(","); } else if (value instanceof Object[]) { newValues = (O[]) value; } else { newValues = (O[]) new Object[]{value}; } for (O v : newValues) { addValue(v); } } /** * Append value to existing values. * * @param v the value to add */ @SuppressWarnings({"unchecked"}) public void addValue(O v) { int l = this.values.length; for (O aValue : this.values) { if (v != null && v.equals(aValue)) { //value already found, do nothing return; } } if (l == 0) { this.values = (O[]) new Object[]{v}; } else { // never add a null value to an existing list of values if (v != null) { if (l == 1 && this.values[0] == null) { // if there's one existing value and it's null, replace it with the new one this.values = (O[]) new Object[]{v}; } else { // otherwise copy the existing value(s) and add the new one O[] oldValues = this.values; this.values = (O[]) new Object[l + 1]; System.arraycopy(oldValues, 0, this.values, 0, l); this.values[l] = v; } } } } /** * Get the values. * * @return the values */ public O[] getValues() { return this.values; } public boolean isNull() { return this.values.length == 0 || (this.values.length == 1 && this.values[0] == null); } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (this.values.length > 1) { sb.append('['); } for (int i = 0; i < this.values.length; i++) { if (i > 0) { sb.append(','); } sb.append(format(this.values[i])); } if (this.values.length > 1) { sb.append(']'); } return sb.toString(); } /** * Format a value for JSON. * * @param o the value * @return the formtted value */ private String format(Object o) { if (o == null) { return "null"; } if (o instanceof Integer) { return Integer.toString((Integer) o); } if (o instanceof Long) { return Long.toString((Long) o); } if (o instanceof Boolean) { return Boolean.toString((Boolean) o); } if (o instanceof Float) { // suppress scientific notation return String.format("%.12f", (Float) o); } if (o instanceof Double) { // suppress scientific notation return String.format("%.12f", (Double) o); } // stringify String t = o.toString(); t = t.replaceAll("\"", "\\\""); return '"' + t + '"'; } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { if (this.values.length == 0) { builder.nullValue(); return builder; } if (this.values.length > 1 || params.paramAsBoolean("force_array", false)) { builder.startArray(); } for (O aValue : this.values) { builder.value(aValue); } if (this.values.length > 1 || params.paramAsBoolean("force_array", false)) { builder.endArray(); } return builder; } }