/*
* Copyright (c) 2012-2015 Spotify AB
*
* 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 com.spotify.netty4.handler.codec.zmtp;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import static com.spotify.netty4.handler.codec.zmtp.ZMTPUtils.checkNotNull;
import static io.netty.util.CharsetUtil.UTF_8;
/**
* Configuration for a ZMTP session and {@link ZMTPCodec}. Can be reused and shared across multiple
* channel instances.
*/
public class ZMTPConfig {
public static final ByteBuffer ANONYMOUS = ByteBuffer.allocate(0).asReadOnlyBuffer();
private final ZMTPProtocol protocol;
private final boolean interop;
private final ZMTPSocketType socketType;
private final ByteBuffer localIdentity;
private final ZMTPEncoder.Factory encoder;
private final ZMTPDecoder.Factory decoder;
private final ZMTPIdentityGenerator identityGenerator;
private ZMTPConfig(final Builder builder) {
this.protocol = checkNotNull(builder.protocol, "protocol");
this.interop = checkNotNull(builder.interop, "interop");
this.socketType = checkNotNull(builder.socketType, "socketType");
this.localIdentity = checkNotNull(builder.localIdentity, "localIdentity");
this.encoder = checkNotNull(builder.encoder, "encoder");
this.decoder = checkNotNull(builder.decoder, "decoder");
this.identityGenerator = checkNotNull(builder.identityGenerator, "identityGenerator");
}
public ZMTPProtocol protocol() {
return protocol;
}
public boolean interop() {
return interop;
}
public ZMTPSocketType socketType() {
return socketType;
}
public ByteBuffer localIdentity() {
return localIdentity;
}
public ZMTPEncoder.Factory encoder() {
return encoder;
}
public ZMTPDecoder.Factory decoder() {
return decoder;
}
public ZMTPIdentityGenerator identityGenerator() {
return identityGenerator;
}
public Builder toBuilder() {
return new Builder(this);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private ZMTPProtocol protocol = ZMTPProtocols.ZMTP20;
private boolean interop = true;
private ZMTPSocketType socketType;
private ByteBuffer localIdentity = ANONYMOUS;
private ZMTPEncoder.Factory encoder = ZMTPMessageEncoder.FACTORY;
private ZMTPDecoder.Factory decoder = ZMTPMessageDecoder.FACTORY;
private ZMTPIdentityGenerator identityGenerator = ZMTPLongIdentityGenerator.GLOBAL;
private Builder() {
}
private Builder(final ZMTPConfig config) {
this.protocol = config.protocol;
this.interop = config.interop;
this.socketType = config.socketType;
this.localIdentity = config.localIdentity;
this.encoder = config.encoder;
this.decoder = config.decoder;
}
public Builder protocol(final ZMTPProtocol protocol) {
this.protocol = protocol;
return this;
}
public Builder interop(final boolean interop) {
this.interop = interop;
return this;
}
public Builder socketType(final ZMTPSocketType socketType) {
this.socketType = socketType;
return this;
}
public Builder localIdentity(final CharSequence localIdentity) {
return localIdentity(UTF_8.encode(localIdentity.toString()));
}
public Builder localIdentity(final byte[] localIdentity) {
return localIdentity(ByteBuffer.wrap(localIdentity));
}
public Builder localIdentity(final ByteBuffer localIdentity) {
this.localIdentity = localIdentity;
return this;
}
public Builder encoder(final ZMTPEncoder.Factory encoder) {
this.encoder = encoder;
return this;
}
public Builder encoder(final Class<? extends ZMTPEncoder> encoder) {
return encoder(new ZMTPEncoderClassFactory(encoder));
}
public Builder decoder(final ZMTPDecoder.Factory decoder) {
this.decoder = decoder;
return this;
}
public Builder decoder(final Class<? extends ZMTPDecoder> decoder) {
return decoder(new ZMTPDecoderClassFactory(decoder));
}
public Builder identityGenerator(final ZMTPIdentityGenerator identityGenerator) {
this.identityGenerator = identityGenerator;
return this;
}
public ZMTPConfig build() {
return new ZMTPConfig(this);
}
}
@Override
public String toString() {
return "ZMTPConfig{" +
"protocol=" + protocol +
", interop=" + interop +
", socketType=" + socketType +
", localIdentity=" + localIdentity +
", encoder=" + encoder +
", decoder=" + decoder +
'}';
}
private static class ZMTPEncoderClassFactory implements ZMTPEncoder.Factory {
private final Constructor<? extends ZMTPEncoder> constructor;
public ZMTPEncoderClassFactory(final Class<? extends ZMTPEncoder> encoder) {
checkNotNull(encoder, "encoder");
try {
constructor = encoder.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class must have default constructor: " + encoder);
}
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
}
@Override
public ZMTPEncoder encoder(final ZMTPSession session) {
try {
return constructor.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "ZMTPEncoderClassFactory{" +
"constructor=" + constructor +
'}';
}
}
private static class ZMTPDecoderClassFactory implements ZMTPDecoder.Factory {
private final Constructor<? extends ZMTPDecoder> constructor;
public ZMTPDecoderClassFactory(final Class<? extends ZMTPDecoder> decoder) {
checkNotNull(decoder, "decoder");
try {
constructor = decoder.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class must have default constructor: " + decoder);
}
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
}
@Override
public ZMTPDecoder decoder(final ZMTPSession session) {
try {
return constructor.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "ZMTPDecoderClassFactory{" +
"constructor=" + constructor +
'}';
}
}
}