/* * Copyright 2002-2013 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.data.gemfire.function.execution; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** * A Proxy FactoryBean for all non-Region Function Execution interfaces. * * @author David Turanski * @author John Blum * @see java.lang.reflect.Method * @see org.aopalliance.intercept.MethodInterceptor * @see org.springframework.beans.factory.BeanClassLoaderAware * @see org.springframework.beans.factory.FactoryBean */ public class GemfireFunctionProxyFactoryBean implements FactoryBean<Object>, MethodInterceptor, BeanClassLoaderAware { private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private volatile boolean initialized; private final Class<?> functionExecutionInterface; private volatile Object functionExecutionProxy; private final GemfireFunctionOperations gemfireFunctionOperations; protected Log logger = LogFactory.getLog(this.getClass()); private FunctionExecutionMethodMetadata<MethodMetadata> methodMetadata; /** * @param functionExecutionInterface the proxied interface * @param gemfireFunctionOperations an interface used to delegate the function invocation (typically a GemFire function template) */ public GemfireFunctionProxyFactoryBean(Class<?> functionExecutionInterface, GemfireFunctionOperations gemfireFunctionOperations) { Assert.notNull(functionExecutionInterface, "'functionExecutionInterface' must not be null"); Assert.isTrue(functionExecutionInterface.isInterface(), "'functionExecutionInterface' must be an interface"); this.functionExecutionInterface = functionExecutionInterface; this.gemfireFunctionOperations = gemfireFunctionOperations; this.methodMetadata = new DefaultFunctionExecutionMethodMetadata(functionExecutionInterface); } protected GemfireFunctionOperations getGemfireFunctionOperations() { return gemfireFunctionOperations; } @Override public void setBeanClassLoader(ClassLoader classLoader) { beanClassLoader = classLoader; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { if (AopUtils.isToStringMethod(invocation.getMethod())) { return "GemFire Function Proxy for service interface [" + this.functionExecutionInterface + "]"; } if (logger.isDebugEnabled()) { logger.debug("invoking method " + invocation.getMethod().getName()); } return invokeFunction(invocation.getMethod(), invocation.getArguments()); } protected Object invokeFunction(Method method, Object[] args) { return this.gemfireFunctionOperations.executeAndExtract( methodMetadata.getMethodMetadata(method).getFunctionId(), args); } @Override public Object getObject() throws Exception { if (functionExecutionProxy == null) { onInit(); Assert.notNull(functionExecutionProxy, "failed to initialize proxy"); } return functionExecutionProxy; } @Override public Class<?> getObjectType() { return this.functionExecutionInterface; } @Override public boolean isSingleton() { return true; } protected void onInit() { if (!initialized) { ProxyFactory proxyFactory = new ProxyFactory(functionExecutionInterface, this); functionExecutionProxy = proxyFactory.getProxy(beanClassLoader); initialized = true; } } }