/* * Copyright (C) 2015 SoftIndex LLC. * * 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 io.datakernel.config; import com.google.common.base.Preconditions; import io.datakernel.eventloop.InetAddressRange; import io.datakernel.exception.ParseException; import io.datakernel.net.DatagramSocketSettings; import io.datakernel.net.ServerSocketSettings; import io.datakernel.net.SocketSettings; import io.datakernel.util.MemSize; import io.datakernel.util.StringUtils; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static io.datakernel.net.ServerSocketSettings.DEFAULT_BACKLOG; import static io.datakernel.util.Preconditions.checkArgument; import static java.lang.Integer.parseInt; import static java.util.Collections.emptyList; /** * Provides comprehensive static factory methods returning converters for * different data types. * <p> * There are plenty of converter implementations available besides wrappers for * primitives and frequently used standard classes. Consider converters for * classes from DataKernel framework: * {@link #ofMemSize()}, {@link #ofServerSocketSettings()}, * {@link #ofSocketSettings()}, {@link #ofDatagramSocketSettings()} * </li> * </ul> * * @see AbstractConfigConverter */ @SuppressWarnings("unused, WeakerAccess") public final class ConfigConverters { public static AbstractConfigConverter<String> ofString() { return new AbstractConfigConverter<String>() { @Override public String fromString(String string) { return string; } @Override public String fromEmptyString() { return ""; } @Override public String toString(String item) { return item; } }; } public static AbstractConfigConverter<Byte> ofByte() { return new AbstractConfigConverter<Byte>() { @Override public Byte fromString(String string) { return Byte.parseByte(string); } @Override public String toString(Byte item) { return Byte.toString(item); } }; } public static AbstractConfigConverter<Integer> ofInteger() { return new AbstractConfigConverter<Integer>() { @Override public Integer fromString(String string) { return Integer.parseInt(string); } @Override public String toString(Integer item) { return Integer.toString(item); } }; } public static AbstractConfigConverter<Long> ofLong() { return new AbstractConfigConverter<Long>() { @Override public Long fromString(String string) { return Long.parseLong(string); } @Override public String toString(Long item) { return Long.toString(item); } }; } public static AbstractConfigConverter<Float> ofFloat() { return new AbstractConfigConverter<Float>() { @Override public Float fromString(String string) { return Float.parseFloat(string); } @Override public String toString(Float item) { return Float.toString(item); } }; } public static AbstractConfigConverter<Double> ofDouble() { return new AbstractConfigConverter<Double>() { @Override public Double fromString(String string) { return Double.parseDouble(string); } @Override public String toString(Double item) { return Double.toString(item); } }; } public static AbstractConfigConverter<Boolean> ofBoolean() { return new AbstractConfigConverter<Boolean>() { @Override public Boolean fromString(String string) { return Boolean.parseBoolean(string); } @Override public String toString(Boolean item) { return Boolean.toString(item); } }; } public static <E extends Enum<E>> AbstractConfigConverter<E> ofEnum(Class<E> enumClass) { final Class<E> enumClass1 = enumClass; return new AbstractConfigConverter<E>() { private final Class<E> enumClass = enumClass1; @Override public E fromString(String string) { return Enum.valueOf(enumClass, string); } @Override public String toString(E item) { return item.name(); } }; } public static AbstractConfigConverter<InetAddress> ofInetAddress() { return new AbstractConfigConverter<InetAddress>() { @Override public InetAddress fromString(String address) { try { return InetAddress.getByName(address); } catch (UnknownHostException e) { throw new IllegalArgumentException(e); } } @Override public String toString(InetAddress item) { return item.getAddress().toString(); } }; } /** * Creates a converter of {@link InetSocketAddress}. This address may * include IP address or hostname and port number. Conversion to string * creates a string with IP address regardless of whether a host part of an * address was represented by a hostname or IP address. * * @return converter of {@code InetSocketAddress} */ public static AbstractConfigConverter<InetSocketAddress> ofInetSocketAddress() { return new AbstractConfigConverter<InetSocketAddress>() { @Override public InetSocketAddress fromString(String addressPort) { int portPos = addressPort.lastIndexOf(':'); checkArgument(portPos != -1, "Invalid address. Port is not specified"); String addressStr = addressPort.substring(0, portPos); String portStr = addressPort.substring(portPos + 1); int port = parseInt(portStr); checkArgument(port > 0 && port < 65536, "Invalid address. Port is not in range (0, 65536) " + addressStr); InetSocketAddress socketAddress; if ("*".equals(addressStr)) { socketAddress = new InetSocketAddress(port); } else { try { InetAddress address = InetAddress.getByName(addressStr); socketAddress = new InetSocketAddress(address, port); } catch (UnknownHostException e) { throw new IllegalArgumentException(e); } } return socketAddress; } @Override public String toString(InetSocketAddress item) { return item.getAddress().getHostAddress() + ":" + item.getPort(); } }; } /** * Creates a converter capable to convert a list. Provide a concrete * implementation of {@code AbstractConfigConverter<T>} for objects in list * and char sequence of separators. * * @param elementConverter converter of list objects type * @param separators sequence of separators of config property * @param <T> type of objects in list * @return converter of list */ public static <T> ConfigConverter<List<T>> ofList(AbstractConfigConverter<T> elementConverter, CharSequence separators) { final AbstractConfigConverter<T> elementConverter1 = elementConverter; final CharSequence separators1 = separators; return new AbstractConfigConverter<List<T>>() { private final AbstractConfigConverter<T> elementConverter = elementConverter1; private final CharSequence separators = separators1; private final char joinSeparator = separators1.charAt(0); @Override public List<T> fromEmptyString() { return Collections.emptyList(); } @Override public List<T> fromString(String string) { string = string.trim(); if (string.isEmpty()) return emptyList(); List<T> list = new ArrayList<>(); for (String elementString : StringUtils.splitToList(separators, string)) { T element = elementConverter.fromString(elementString.trim()); list.add(element); } return Collections.unmodifiableList(list); } @Override public String toString(List<T> item) { List<String> strings = new ArrayList<>(item.size()); for (T e : item) { strings.add(elementConverter.toString(e)); } return StringUtils.join(joinSeparator, strings); } }; } public static <T> ConfigConverter<List<T>> ofList(AbstractConfigConverter<T> elementConverter) { return ofList(elementConverter, ",;"); } public static AbstractConfigConverter<MemSize> ofMemSize() { return new AbstractConfigConverter<MemSize>() { @Override public MemSize fromString(String string) { return MemSize.valueOf(string); } @Override public String toString(MemSize item) { return item.format(); } }; } public static ConfigConverter<ServerSocketSettings> ofServerSocketSettings() { return new ConfigConverter<ServerSocketSettings>() { @Override public ServerSocketSettings get(Config config) { return get(config, ServerSocketSettings.create(DEFAULT_BACKLOG)); } @Override public ServerSocketSettings get(Config config, ServerSocketSettings defaultValue) { ServerSocketSettings result = Preconditions.checkNotNull(defaultValue); result = result.withBacklog(config.get(ofInteger(), "backlog", result.getBacklog())); MemSize receiveBufferSize = config.get(ofMemSize(), "receiveBufferSize", result.hasReceiveBufferSize() ? MemSize.of(result.getReceiveBufferSize()) : null); if (receiveBufferSize != null) { result = result.withReceiveBufferSize(receiveBufferSize); } Boolean reuseAddress = config.get(ofBoolean(), "reuseAddress", result.hasReuseAddress() ? result.getReuseAddress() : null); if (reuseAddress != null) { result = result.withReuseAddress(reuseAddress); } return result; } }; } public static ConfigConverter<SocketSettings> ofSocketSettings() { return new ConfigConverter<SocketSettings>() { @Override public SocketSettings get(Config config) { return get(config, SocketSettings.create()); } @Override public SocketSettings get(Config config, SocketSettings defaultValue) { SocketSettings result = Preconditions.checkNotNull(defaultValue); MemSize receiveBufferSize = config.get(ofMemSize(), "receiveBufferSize", result.hasReceiveBufferSize() ? MemSize.of(result.getReceiveBufferSize()) : null); if (receiveBufferSize != null) { result = result.withReceiveBufferSize(receiveBufferSize); } MemSize sendBufferSize = config.get(ofMemSize(), "sendBufferSize", result.hasSendBufferSize() ? MemSize.of(result.getSendBufferSize()) : null); if (sendBufferSize != null) { result = result.withSendBufferSize(sendBufferSize); } Boolean reuseAddress = config.get(ofBoolean(), "reuseAddress", result.hasReuseAddress() ? result.getReuseAddress() : null); if (reuseAddress != null) { result = result.withReuseAddress(reuseAddress); } Boolean keepAlive = config.get(ofBoolean(), "keepAlive", result.hasKeepAlive() ? result.getKeepAlive() : null); if (keepAlive != null) { result = result.withKeepAlive(keepAlive); } Boolean tcpNoDelay = config.get(ofBoolean(), "tcpNoDelay", result.hasTcpNoDelay() ? result.getTcpNoDelay() : null); if (tcpNoDelay != null) { result = result.withTcpNoDelay(tcpNoDelay); } Long implReadTimeout = config.get(ofLong(), "implReadTimeout", result.hasImplReadTimeout() ? result.getImplReadTimeout() : null); if (implReadTimeout != null) { result = result.withImplReadTimeout(implReadTimeout); } Long implWriteTimeout = config.get(ofLong(), "implWriteTimeout", result.hasImplWriteTimeout() ? result.getImplWriteTimeout() : null); if (implWriteTimeout != null) { result = result.withImplWriteTimeout(implWriteTimeout); } MemSize implReadSize = config.get(ofMemSize(), "implReadSize", result.hasImplReadSize() ? MemSize.of(result.getImplReadSize()) : null); if (implReadSize != null) { result = result.withImplReadSize(implReadSize); } MemSize implWriteSize = config.get(ofMemSize(), "implWriteSize", result.hasImplWriteSize() ? MemSize.of(result.getImplWriteSize()) : null); if (implWriteSize != null) { result = result.withImplWriteSize(implWriteSize); } return result; } }; } /** * Creates a converter of {@link DatagramSocketSettings}. * * @return converter of provided type */ public static ConfigConverter<DatagramSocketSettings> ofDatagramSocketSettings() { return new ConfigConverter<DatagramSocketSettings>() { @Override public DatagramSocketSettings get(Config config) { return get(config, DatagramSocketSettings.create()); } @Override public DatagramSocketSettings get(Config config, DatagramSocketSettings defaultValue) { DatagramSocketSettings result = Preconditions.checkNotNull(DatagramSocketSettings.create()); MemSize receiveBufferSize = config.get(ofMemSize(), "receiveBufferSize", result.hasReceiveBufferSize() ? MemSize.of(result.getReceiveBufferSize()) : null); if (receiveBufferSize != null) { result = result.withReceiveBufferSize(receiveBufferSize); } MemSize sendBufferSize = config.get(ofMemSize(), "sendBufferSize", result.hasSendBufferSize() ? MemSize.of(result.getSendBufferSize()) : null); if (sendBufferSize != null) { result = result.withSendBufferSize(sendBufferSize); } Boolean reuseAddress = config.get(ofBoolean(), "reuseAddress", result.hasReuseAddress() ? result.getReuseAddress() : null); if (reuseAddress != null) { result = result.withReuseAddress(reuseAddress); } Boolean broadcast = config.get(ofBoolean(), "broadcast", result.hasBroadcast() ? result.getBroadcast() : null); if (broadcast != null) { result = result.withBroadcast(broadcast); } return result; } }; } /** * Creates a converter of {@link InetAddressRange}. An InetAddressRange supports a lot * of range types, including CIDR, standalone and ranges of addresses. * * @return converter of provided type */ public static AbstractConfigConverter<InetAddressRange> ofInetAddressRange() { return new AbstractConfigConverter<InetAddressRange>() { @Override public InetAddressRange fromString(String string) { try { return InetAddressRange.parse(string); } catch (ParseException e) { throw new IllegalArgumentException("Can't parse inetAddressRange config", e); } } @Override public String toString(InetAddressRange item) { return item.toString(); } }; } }