com.facebook.swift.service.guice.ThriftClientBinder Maven / Gradle / Ivy
/*
* Copyright (C) 2012 Facebook, Inc.
*
* 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.facebook.swift.service.guice;
import com.facebook.swift.service.ThriftClient;
import com.facebook.swift.service.ThriftClientConfig;
import com.facebook.swift.service.ThriftClientEventHandler;
import com.facebook.swift.service.ThriftClientManager;
import com.facebook.swift.service.ThriftClientManager.ThriftClientMetadata;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import org.weakref.jmx.guice.ExportBinder;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.UUID;
import static com.facebook.swift.service.ThriftClientManager.DEFAULT_NAME;
import static com.facebook.swift.service.metadata.ThriftServiceMetadata.getThriftServiceAnnotation;
import static io.airlift.configuration.ConfigBinder.configBinder;
import static java.lang.String.format;
public class ThriftClientBinder
{
public static ThriftClientBinder thriftClientBinder(Binder binder)
{
return new ThriftClientBinder(binder);
}
private final Binder binder;
private ThriftClientBinder(Binder binder)
{
this.binder = binder;
}
public ClientEventHandlersBinder bindThriftClient(Class clientInterface)
{
Preconditions.checkNotNull(clientInterface, "clientInterface is null");
String typeName = getServiceName(clientInterface);
// Bind ThriftClientConfig with random @Named annotation
// We generate a random Named annotation for binding the ThriftClientConfig because we
// need one of these for each clientType+annotationType pair. Without this, the
// ThriftClientConfig bindings collapse to a single instance which is shared by all
// clients.
Named thriftClientConfigKey = Names.named(typeName + "-" + UUID.randomUUID().toString());
configBinder(binder).bindConfig(ThriftClientConfig.class, thriftClientConfigKey, typeName);
// Bind ThriftClient to a provider which knows how to find the ThriftClientConfig using
// the random @Named annotation
Multibinder eventHandlersBinder = Multibinder.newSetBinder(binder,
ThriftClientEventHandler.class, thriftClientConfigKey);
ThriftClientProvider provider = new ThriftClientProvider<>(clientInterface, DEFAULT_NAME,
Key.get(ThriftClientConfig.class, thriftClientConfigKey),
Key.get(new TypeLiteral>() {}, thriftClientConfigKey));
TypeLiteral> typeLiteral = toThriftClientTypeLiteral(clientInterface);
binder.bind(typeLiteral).toProvider(provider).in(Scopes.SINGLETON);
// Export client to jmx
ExportBinder.newExporter(binder)
.export(Key.get(typeLiteral))
.as(format("com.facebook.swift.client:type=%s,clientName=%s",
typeName,
DEFAULT_NAME));
// Add the provider itself to a SetBinding so later we can export the thrift methods to JMX
Multibinder.newSetBinder(binder, ThriftClientProvider.class).addBinding().toInstance(provider);
return new ClientEventHandlersBinder(eventHandlersBinder);
}
public ClientEventHandlersBinder bindThriftClient(Class clientInterface, Class extends Annotation> annotationType)
{
Preconditions.checkNotNull(clientInterface, "clientInterface is null");
String typeName = getServiceName(clientInterface);
String name = annotationType.getSimpleName();
// Bind ThriftClientConfig with random @Named annotation
// see comment on random Named annotation above
Named thriftClientConfigKey = Names.named(typeName + "-" + UUID.randomUUID().toString());
String prefix = String.format("%s.%s", typeName, name);
configBinder(binder).bindConfig(ThriftClientConfig.class, thriftClientConfigKey, prefix);
// Bind ThriftClient to a provider which knows how to find the ThriftClientConfig using
// the random @Named annotation
Multibinder eventHandlersBinder = Multibinder.newSetBinder(binder,
ThriftClientEventHandler.class, thriftClientConfigKey);
ThriftClientProvider provider = new ThriftClientProvider<>(clientInterface,
name,
Key.get(ThriftClientConfig.class, thriftClientConfigKey),
Key.get(new TypeLiteral>() {}, thriftClientConfigKey));
TypeLiteral> typeLiteral = toThriftClientTypeLiteral(clientInterface);
binder.bind(Key.get(typeLiteral, annotationType)).toProvider(provider).in(Scopes.SINGLETON);
// Export client to jmx
ExportBinder.newExporter(binder)
.export(Key.get(typeLiteral))
.as(format("com.facebook.swift.client:type=%s,clientName=%s",
typeName,
name));
// Add the provider itself to a SetBinding so later we can export the thrift methods to JMX
Multibinder.newSetBinder(binder, ThriftClientProvider.class).addBinding().toInstance(provider);
return new ClientEventHandlersBinder(eventHandlersBinder);
}
private static String getServiceName(Class> clientInterface)
{
String serviceName = getThriftServiceAnnotation(clientInterface).value();
if (!serviceName.isEmpty()) {
return serviceName;
}
return clientInterface.getSimpleName();
}
/**
* @return TypeLiteral>
*/
private static TypeLiteral> toThriftClientTypeLiteral(Class clientInterface)
{
// build a TypeLiteral> where T is bound to the actual clientInterface class
@SuppressWarnings("serial")
Type javaType = new TypeToken>() {}
.where(new TypeParameter() {}, TypeToken.of(clientInterface))
.getType();
return (TypeLiteral>) TypeLiteral.get(javaType);
}
public static class ThriftClientProvider implements Provider>
{
private final Class clientType;
private final String clientName;
private final Key configKey;
private final Key> eventHandlersKey;
private ThriftClientManager clientManager;
private Injector injector;
public ThriftClientProvider(Class clientType, String clientName, Key configKey,
Key> eventHandlersKey)
{
Preconditions.checkNotNull(clientType, "clientInterface is null");
Preconditions.checkNotNull(clientName, "clientName is null");
Preconditions.checkNotNull(configKey, "configKey is null");
Preconditions.checkNotNull(eventHandlersKey, "eventHandlersKey is null");
this.eventHandlersKey = eventHandlersKey;
this.clientType = clientType;
this.clientName = clientName;
this.configKey = configKey;
}
@Inject
public void setClientManager(ThriftClientManager clientManager)
{
this.clientManager = clientManager;
}
@Inject
public void setInjector(Injector injector)
{
this.injector = injector;
}
@Override
public ThriftClient get()
{
Preconditions.checkState(clientManager != null, "clientManager has not been set");
Preconditions.checkState(injector != null, "injector has not been set");
ThriftClientConfig clientConfig = injector.getInstance(configKey);
Set handlersSet = injector.getInstance(eventHandlersKey);
return new ThriftClient<>(clientManager, clientType, clientConfig, clientName, ImmutableList.copyOf(handlersSet));
}
public ThriftClientMetadata getClientMetadata()
{
Preconditions.checkState(clientManager != null, "clientManager has not been set");
return clientManager.getClientMetadata(clientType, clientName);
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ThriftClientProvider> that = (ThriftClientProvider>) o;
if (!clientName.equals(that.clientName)) {
return false;
}
if (!clientType.equals(that.clientType)) {
return false;
}
return true;
}
@Override
public int hashCode()
{
int result = clientType.hashCode();
result = 31 * result + clientName.hashCode();
return result;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy