/* * Copyright 2013-2015 the original author or authors. * * 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.springframework.xd.tuple; import java.text.DateFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.UUID; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.util.AlternativeJdkIdGenerator; import org.springframework.util.Assert; import org.springframework.util.IdGenerator; /** * Builder class to create Tuple instances. * * Default Locale is US for NumberFormat and default DatePattern is "yyyy-MM-dd" * * <em>Note:</em> Using a custom conversion service that is instance based (not configured * as a singleton) will have <em>significant</em> performance impacts. * * @author Mark Pollack * @author David Turanski * @author Michael Minella * @author Gunnar Hillert * */ public class TupleBuilder { private List<String> names = new ArrayList<>(); private List<Object> values = new ArrayList<>(); private static final ConfigurableConversionService defaultConversionService; private ConfigurableConversionService customConversionService = null; private final static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; private final static Locale DEFAULT_LOCALE = Locale.US; private static Converter<Tuple, String> tupleToStringConverter = new TupleToJsonStringConverter(); private static Converter<String, Tuple> stringToTupleConverter = new JsonStringToTupleConverter(); private static final IdGenerator defaultIdGenerator = new AlternativeJdkIdGenerator(); static { defaultConversionService = new DefaultTupleConversionService(); defaultConversionService.addConverterFactory(new LocaleAwareStringToNumberConverterFactory(NumberFormat .getInstance(DEFAULT_LOCALE))); DateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN); dateFormat.setLenient(false); defaultConversionService.addConverter(new StringToDateConverter(dateFormat)); } public static TupleBuilder tuple() { return new TupleBuilder(); } public Tuple of(String k1, Object v1) { return newTuple(namesOf(k1), valuesOf(v1)); } public Tuple of(String k1, Object v1, String k2, Object v2) { addEntry(k1, v1); addEntry(k2, v2); return build(); } public Tuple of(String k1, Object v1, String k2, Object v2, String k3, Object v3) { addEntry(k1, v1); addEntry(k2, v2); addEntry(k3, v3); return build(); } public Tuple of(String k1, Object v1, String k2, Object v2, String k3, Object v3, String k4, Object v4) { addEntry(k1, v1); addEntry(k2, v2); addEntry(k3, v3); addEntry(k4, v4); return build(); } public Tuple ofNamesAndValues(List<String> names, List<Object> values) { this.names = names; this.values = values; return build(); } public TupleBuilder put(String k1, Object v1) { addEntry(k1, v1); return this; } /** * Add all names and values of the tuple to the built tuple. * @param tuple names and value to add to the tuple being built * @return builder to continue creating a new tuple instance */ public TupleBuilder putAll(Tuple tuple) { for (int i = 0; i < tuple.size(); i++) { Object value = tuple.getValues().get(i); String name = tuple.getFieldNames().get(i); addEntry(name, value); } return this; } public Tuple build() { return newTuple(names, values); } public static Tuple fromString(String source) { return stringToTupleConverter.convert(source); } public TupleBuilder setConfigurableConversionService(ConfigurableConversionService formattingConversionService) { Assert.notNull(formattingConversionService); this.customConversionService = formattingConversionService; return this; } public ConversionServiceBuilder setFormats(Locale locale, DateFormat dateFormat) { return new ConversionServiceBuilder(this, locale, dateFormat); } void addEntry(String k1, Object v1) { names.add(k1); values.add(v1); } static List<Object> valuesOf(Object v1) { ArrayList<Object> values = new ArrayList<>(); values.add(v1); return Collections.unmodifiableList(values); } static List<String> namesOf(String k1) { List<String> fields = new ArrayList<>(1); fields.add(k1); return Collections.unmodifiableList(fields); } protected Tuple newTuple(List<String> names, List<Object> values) { DefaultTuple tuple; if(customConversionService != null) { tuple = new DefaultTuple(names, values, customConversionService); } else { tuple = new DefaultTuple(names, values, defaultConversionService); } tuple.setTupleToStringConverter(tupleToStringConverter); return tuple; } /** * Provides the ability to inject a {@link ConfigurableConversionService} as a way to * customize conversion behavior in the built {@link Tuple}. * * @author Michael Minella */ public static class ConversionServiceBuilder { private TupleBuilder builder; private Locale locale; private DateFormat dateFormat; ConversionServiceBuilder(TupleBuilder builder, Locale locale, DateFormat dateFormat) { this.builder = builder; this.locale = locale; this.dateFormat = dateFormat; } public TupleBuilder setConfigurableConversionService(ConfigurableConversionService formattingConversionService) { Assert.notNull(formattingConversionService); if(locale != null) { formattingConversionService.addConverterFactory(new LocaleAwareStringToNumberConverterFactory(NumberFormat .getInstance(locale))); } if(dateFormat != null) { formattingConversionService.addConverter(new StringToDateConverter(dateFormat)); } builder.setConfigurableConversionService(formattingConversionService); return builder; } } }