package com.ctriposs.baiji.rpc.server; import com.ctriposs.baiji.rpc.common.HasResponseStatus; import com.ctriposs.baiji.specific.SpecificRecord; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OperationHandler { private static final Logger _logger = LoggerFactory.getLogger(OperationHandler.class); private String _methodName; private Method _method; private Class<? extends SpecificRecord> _requestType; private Class<? extends SpecificRecord> _responseType; private Constructor<? extends SpecificRecord> _requestConstructor; private Constructor<? extends SpecificRecord> _responseConstructor; private Class<?> _serviceType; private Constructor<?> _serviceConstructor; private static final ConcurrentMap<Class<?>, Object> _singletonServiceInstances = new ConcurrentHashMap<Class<?>, Object>(); private ServiceConfig _config; public String getMethodName() { return this._methodName; } public Method getMethod() { return this._method; } public Class<? extends SpecificRecord> getResponseType() { return this._responseType; } public Class<? extends SpecificRecord> getRequestType() { return this._requestType; } public Class<?> getServiceType() { return this._serviceType; } @SuppressWarnings("unchecked") public OperationHandler(ServiceConfig config, Class<?> serviceType, Method method) { if (config == null) { throw new IllegalArgumentException("missing required serviceConfig"); } if (serviceType == null) { throw new IllegalArgumentException("missing required serviceType"); } if (method == null) { throw new IllegalArgumentException("missing required method"); } this._config = config; this._method = method; this._methodName = method.getName(); // service type this._serviceType = serviceType; try { this._serviceConstructor = serviceType.getConstructor(); } catch (Exception ex) { throw new IllegalArgumentException("missing public parameterless constructor on service Type " + this._serviceType, ex); } // response type this._responseType = (Class<? extends SpecificRecord>) method.getReturnType(); if (this._responseType == null) { throw new IllegalArgumentException("missing required responseType(returnType) on method " + this._methodName); } if (!HasResponseStatus.class.isAssignableFrom(this._responseType)) { throw new IllegalArgumentException("Response type " + this._responseType + " does not implement required interface " + HasResponseStatus.class); } try { this._responseConstructor = this._responseType.getConstructor(); } catch (Exception ex) { throw new IllegalArgumentException("missing public parameterless constructor on response Type " + this._responseType, ex); } // request type if (this._method.getParameterTypes() == null || this._method.getParameterTypes().length != 1) { throw new IllegalArgumentException("One and only one request type is required/allowed on method " + this._methodName); } this._requestType = (Class<? extends SpecificRecord>) method.getParameterTypes()[0]; try { this._requestConstructor = this._requestType.getConstructor(); } catch (Exception ex) { throw new IllegalArgumentException("missing public parameterless constructor on request Type " + this._requestType, ex); } } public SpecificRecord getEmptyRequestInstance() throws Exception { return this._requestConstructor.newInstance(); } public SpecificRecord getEmptyResponseInstance() throws Exception { return this._responseConstructor.newInstance(); } public Object getServiceInstance() throws Exception { if (this._config.isNewServiceInstancePerRequest()) { return _serviceConstructor.newInstance(); } else { // Lazy initialization Object instance = _singletonServiceInstances.get(_serviceType); if (instance == null) { instance = _serviceConstructor.newInstance(); Object existedInstance = _singletonServiceInstances.putIfAbsent(_serviceType, instance); if (existedInstance != null) { instance = existedInstance; } } return instance; } } // invoke target service public SpecificRecord invoke(OperationContext context) throws Exception { Object serviceInstance = this.getServiceInstance(); return (SpecificRecord) this._method.invoke(serviceInstance, context.getRequestObject()); } }