001/* 002 * Copyright (C) 2014 Jörg Prante 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.xbib.elasticsearch.plugin.jdbc.util; 017 018import org.elasticsearch.common.xcontent.ToXContent; 019import org.elasticsearch.common.xcontent.XContentBuilder; 020 021import java.io.IOException; 022 023/** 024 * This class represents one or many values. Each value is represented at most 025 * once. New values are appended. 026 */ 027public class Values<O extends Object> implements ToXContent { 028 029 /** 030 * The values are implemented as an object array 031 */ 032 @SuppressWarnings({"unchecked"}) 033 private O[] values = (O[]) new Object[0]; 034 035 /** 036 * Create new Values from an existing values by appending a value. 037 * 038 * @param old existing values or null if values should be created 039 * @param value a new value 040 * @param sequence true if value should be splitted by commas to multiple values 041 */ 042 @SuppressWarnings({"unchecked"}) 043 public Values(Object old, O value, boolean sequence) { 044 if (old instanceof Values) { 045 O[] vals = (O[]) ((Values) old).getValues(); 046 if (vals != null) { 047 this.values = vals; 048 } 049 } 050 O[] newValues; 051 if (sequence && value != null) { 052 newValues = (O[]) value.toString().split(","); 053 } else if (value instanceof Object[]) { 054 newValues = (O[]) value; 055 } else { 056 newValues = (O[]) new Object[]{value}; 057 } 058 for (O v : newValues) { 059 addValue(v); 060 } 061 } 062 063 /** 064 * Append value to existing values. 065 * 066 * @param v the value to add 067 */ 068 @SuppressWarnings({"unchecked"}) 069 public void addValue(O v) { 070 int l = this.values.length; 071 for (O aValue : this.values) { 072 if (v != null && v.equals(aValue)) { 073 //value already found, do nothing 074 return; 075 } 076 } 077 if (l == 0) { 078 this.values = (O[]) new Object[]{v}; 079 } else { 080 // never add a null value to an existing list of values 081 if (v != null) { 082 if (l == 1 && this.values[0] == null) { 083 // if there's one existing value and it's null, replace it with the new one 084 this.values = (O[]) new Object[]{v}; 085 } else { 086 // otherwise copy the existing value(s) and add the new one 087 O[] oldValues = this.values; 088 this.values = (O[]) new Object[l + 1]; 089 System.arraycopy(oldValues, 0, this.values, 0, l); 090 this.values[l] = v; 091 } 092 } 093 } 094 } 095 096 /** 097 * Get the values. 098 * 099 * @return the values 100 */ 101 public O[] getValues() { 102 return this.values; 103 } 104 105 public boolean isNull() { 106 return this.values.length == 0 || (this.values.length == 1 && this.values[0] == null); 107 } 108 109 @Override 110 public String toString() { 111 StringBuilder sb = new StringBuilder(); 112 if (this.values.length > 1) { 113 sb.append('['); 114 } 115 for (int i = 0; i < this.values.length; i++) { 116 if (i > 0) { 117 sb.append(','); 118 } 119 sb.append(format(this.values[i])); 120 } 121 if (this.values.length > 1) { 122 sb.append(']'); 123 } 124 return sb.toString(); 125 } 126 127 /** 128 * Format a value for JSON. 129 * 130 * @param o the value 131 * @return the formtted value 132 */ 133 private String format(Object o) { 134 if (o == null) { 135 return "null"; 136 } 137 if (o instanceof Integer) { 138 return Integer.toString((Integer) o); 139 } 140 if (o instanceof Long) { 141 return Long.toString((Long) o); 142 } 143 if (o instanceof Boolean) { 144 return Boolean.toString((Boolean) o); 145 } 146 if (o instanceof Float) { 147 // suppress scientific notation 148 return String.format("%.12f", (Float) o); 149 } 150 if (o instanceof Double) { 151 // suppress scientific notation 152 return String.format("%.12f", (Double) o); 153 } 154 // stringify 155 String t = o.toString(); 156 t = t.replaceAll("\"", "\\\""); 157 return '"' + t + '"'; 158 } 159 160 @Override 161 public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { 162 if (this.values.length == 0) { 163 builder.nullValue(); 164 return builder; 165 } 166 if (this.values.length > 1) { 167 builder.startArray(); 168 } 169 for (O aValue : this.values) { 170 builder.value(aValue); 171 } 172 if (this.values.length > 1) { 173 builder.endArray(); 174 } 175 return builder; 176 } 177}