/* * Copyright 2011 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.remoting.avro; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.avro.ipc.Transceiver; import org.apache.avro.ipc.specific.SpecificRequestor; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.remoting.avro.clients.NettyTransceiverCreationCallback; import org.springframework.remoting.avro.clients.TransceiverCreationCallback; import org.springframework.remoting.support.RemoteAccessor; import org.springframework.util.Assert; import java.lang.reflect.Method; import java.net.InetSocketAddress; /** * {@link org.springframework.beans.factory.FactoryBean} that builds client-side proxies that * in turn talk to remote Avro RPC implementations * * @author Josh Long * @see org.springframework.remoting.avro.clients.TransceiverCreationCallback */ public class AvroProxyFactoryBean<T> extends RemoteAccessor implements InitializingBean, MethodInterceptor, FactoryBean<T> { private TransceiverCreationCallback transceiverCreationCallback; private int port = 2003; private Transceiver transceiver; private Object serviceProxy; private InetSocketAddress address; private Object client; public void setPort(int port) { this.port = port; } public void setTransceiver(Transceiver transceiver) { this.transceiver = transceiver; } @Override public T getObject() throws Exception { return (T) serviceProxy; } @Override public Class<?> getObjectType() { return getServiceInterface(); } @Override public boolean isSingleton() { return true; } /** * <p> Useful if you want to tailor the creation of the {@link Transceiver } that's used to handle the client side networking.</p> * <p/> * <p> This is not a required field because, by default, the implementation uses {@link NettyTransceiverCreationCallback} </p> * * @param transceiverCreationCallback the transceiver creation callback */ public void setTransceiverCreationCallback(TransceiverCreationCallback transceiverCreationCallback) { this.transceiverCreationCallback = transceiverCreationCallback; } @Override public void afterPropertiesSet() throws Exception { if (null == this.address) { Assert.isTrue(this.port > 0, "the port must be greater than 0"); this.address = new InetSocketAddress(port); } if (this.transceiverCreationCallback == null) { this.transceiverCreationCallback = new NettyTransceiverCreationCallback(); } if (this.transceiver == null) { this.transceiver = transceiverCreationCallback.buildTransceiver(this.address); } this.client = SpecificRequestor.getClient(getServiceInterface(), transceiver); Assert.notNull(client, "we weren't able to build a serviceProxy"); this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader()); } @Override public Object invoke(MethodInvocation invocation) throws Throwable { // now, unless i miss my mark, the interface of this proxy and the proxy we've created locally are the same, // so it should be a simple matter to forward the MethodInvocation on to the local serviceProxy Method method = invocation.getMethod(); if (logger.isDebugEnabled()) { logger.debug("invoking " + invocation.toString() + " on the serviceProxy proxy"); } return method.invoke(this.client, invocation.getArguments()); } }