
ars.invoke.StandardRouter Maven / Gradle / Ivy
The newest version!
package ars.invoke;
import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.LinkedList;
import java.util.Collections;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ars.util.Cache;
import ars.util.Strings;
import ars.util.SimpleCache;
import ars.invoke.request.Requester;
import ars.invoke.event.InvokeEvent;
import ars.invoke.event.InvokeListener;
import ars.invoke.event.InvokeAfterEvent;
import ars.invoke.event.InvokeErrorEvent;
import ars.invoke.event.InvokeBeforeEvent;
import ars.invoke.event.InvokeCompleteEvent;
import ars.invoke.request.AccessDeniedException;
/**
* 请求资源路由标准实现
*
* @author wuyongqiang
*/
public class StandardRouter implements Router {
private Cache cache; // 缓存处理接口
private List apis; // 资源接口集合
private Cacheable[] cacheables; // 可缓存资源数组
private Map caches; // 缓存目标资源地址/缓存规则映射
private Map> refreshs; // 触发缓存刷新资源地址映射
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Map forwards = new HashMap(0); // 请求转发资源映射
private final Map wrappers = new HashMap(0); // 请求调用包装器资源映射
private final List> invokeBeforeListeners = new LinkedList>(); // 请求调用之前监听器集合
private final List> invokeAfterListeners = new LinkedList>(); // 请求调用成功监听器集合
private final List> invokeErrorListeners = new LinkedList>(); // 请求调用失败监听器集合
private final List> invokeCompleteListeners = new LinkedList>(); // 请求调用完成监听器集合
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 请求调用包装类
*
* @author wuyongqiang
*/
class InvokeWrapper {
public final Invoker invoker;
public final Resource resource;
public InvokeWrapper(Invoker invoker, Resource resource) {
if (invoker == null) {
throw new IllegalArgumentException("Invoker must not be null");
}
if (resource == null) {
throw new IllegalArgumentException("Resource must not be null");
}
this.invoker = invoker;
this.resource = resource;
}
/**
* 执行请求调用
*
* @param requester 请求对象
* @return 调用结果
* @throws Exception 操作异常
*/
public Object execute(Requester requester) throws Exception {
return this.invoker.execute(requester, this.resource);
}
@Override
public String toString() {
return new StringBuffer(this.invoker.toString()).append("->").append(this.resource).toString();
}
}
/**
* 请求调用之前执行
*
* @param requester 请求对象
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected void beforeInvoke(Requester requester) {
if (!this.invokeBeforeListeners.isEmpty()) {
InvokeEvent event = new InvokeBeforeEvent(requester);
for (InvokeListener listener : this.invokeBeforeListeners) {
listener.onInvokeEvent(event);
}
}
}
/**
* 请求调用成功执行
*
* @param requester 请求对象
* @param value 请求结果
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected void afterInvoke(Requester requester, Object value) {
if (!this.invokeAfterListeners.isEmpty()) {
InvokeEvent event = new InvokeAfterEvent(requester, value);
for (InvokeListener listener : this.invokeAfterListeners) {
listener.onInvokeEvent(event);
}
}
}
/**
* 请求调用失败执行
*
* @param requester 请求对象
* @param e 调用异常
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected void errorInvoke(Requester requester, Throwable e) {
if (!this.invokeErrorListeners.isEmpty()) {
InvokeEvent event = new InvokeErrorEvent(requester, e);
for (InvokeListener listener : this.invokeErrorListeners) {
listener.onInvokeEvent(event);
}
}
}
/**
* 请求调用完成执行
*
* @param requester 请求对象
* @param value 调用结果
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected void completeInvoke(Requester requester, Object value) {
if (!this.invokeCompleteListeners.isEmpty()) {
InvokeEvent event = new InvokeCompleteEvent(requester, value);
for (InvokeListener listener : this.invokeCompleteListeners) {
listener.onInvokeEvent(event);
}
}
}
/**
* 查找请求调用包装对象
*
* @param requester 请求对象
* @return 请求调用包装对象
*/
protected InvokeWrapper lookupInvokeWrapper(Requester requester) {
String uri = requester.getUri();
if (!this.forwards.isEmpty()) {
String forward = this.forwards.get(uri);
if (forward != null) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Request forward from {} to {}", uri, forward);
}
uri = forward;
}
}
InvokeWrapper wrapper = this.wrappers.get(uri);
if (wrapper == null) {
synchronized (uri.intern()) {
if ((wrapper = this.wrappers.get(uri)) == null) {
for (Entry entry : this.wrappers.entrySet()) {
if (Strings.matches(uri, entry.getKey())) {
wrapper = entry.getValue();
this.wrappers.put(uri, wrapper);
return wrapper;
}
}
throw new AccessDeniedException("error.resource.undefined");
}
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Request invoke target: {}", wrapper);
}
return wrapper;
}
/**
* 请求访问
*
* @param requester 请求对象
* @return 请求结果
* @throws Exception 操作异常
*/
protected Object access(Requester requester) throws Exception {
return this.lookupInvokeWrapper(requester).execute(requester);
}
@Override
public void initialize() {
if (this.cache == null) {
synchronized (this) {
if (this.cache == null) {
this.logger.info("Initialization default cache with class {}", SimpleCache.class.getName());
this.cache = new SimpleCache();
}
}
}
if (this.apis == null) {
synchronized (this) {
if (this.apis == null) {
String[] keys = this.wrappers.keySet().toArray(Strings.EMPTY_ARRAY);
Arrays.sort(keys);
this.apis = Collections.unmodifiableList(Arrays.asList(keys));
}
}
}
if (this.caches == null || this.refreshs == null) {
synchronized (this) {
if (this.caches == null || this.refreshs == null) {
if (this.cacheables == null || this.cacheables.length == 0) {
this.caches = Collections.emptyMap();
this.refreshs = Collections.emptyMap();
} else {
this.logger.info("Initialization cacheable mappings");
this.caches = new HashMap();
this.refreshs = new HashMap>();
for (int i = 0; i < this.apis.size(); i++) {
String api = this.apis.get(i);
for (Cacheable cacheable : cacheables) {
if (cacheable.getTarget() == null) {
throw new RuntimeException("Cacheable target resource must not be empty");
}
if (Strings.matches(api, cacheable.getTarget())) {
this.caches.put(api, cacheable);
break;
} else if (!Strings.matches(api, cacheable.getRefresh())) {
continue;
}
for (int n = 0; n < this.apis.size(); n++) {
String resource = this.apis.get(n);
if (Strings.matches(resource, cacheable.getTarget())) {
Set resources = this.refreshs.get(api);
if (resources == null) {
resources = new HashSet();
this.refreshs.put(api, resources);
}
resources.add(resource);
}
}
}
}
}
}
}
}
}
@Override
public List getApis() {
return this.apis;
}
@Override
public boolean isRegistered(String api) {
return this.wrappers.containsKey(api);
}
@Override
public Object routing(Requester requester) {
Object result = null;
boolean debug = this.logger.isDebugEnabled();
if (debug) {
this.logger.debug("Request: {}", requester.getParameters());
}
try {
this.beforeInvoke(requester);
Cacheable cacheable = this.caches.get(requester.getUri());
if (debug) {
this.logger.debug("Cache configuration: {}", cacheable);
}
if (cacheable == null) {
result = this.access(requester);
Set refresh = this.refreshs.get(requester.getUri());
if (refresh != null && !refresh.isEmpty()) {
for (String uri : refresh) {
if (debug) {
this.logger.debug("Refresh cache of uri: {}", uri);
}
this.lock.writeLock().lock();
try {
this.cache.remove(new StringBuilder("{").append(uri).append("}*").toString());
} finally {
this.lock.writeLock().unlock();
}
}
}
} else {
String key = cacheable.getKey(requester);
if (debug) {
this.logger.debug("Build cache key: {}", key);
}
this.lock.readLock().lock();
try {
if (this.cache.exists(key)) {
if (debug) {
this.logger.debug("Getting data from the cache");
}
result = this.cache.get(key);
} else {
this.lock.readLock().unlock();
this.lock.writeLock().lock();
try {
if (this.cache.exists(key)) {
if (debug) {
this.logger.debug("Getting data from the cache");
}
result = this.cache.get(key);
} else {
result = this.access(requester);
if (debug) {
this.logger.debug("Setting data into the cache");
}
this.cache.set(key, result, cacheable.getTimeout());
}
} finally {
this.lock.writeLock().unlock();
this.lock.readLock().lock();
}
}
} finally {
this.lock.readLock().unlock();
}
}
if (debug) {
this.logger.debug("Response: {}", result);
}
this.afterInvoke(requester, result);
} catch (Throwable e) {
result = e;
this.errorInvoke(requester, e);
} finally {
this.completeInvoke(requester, result);
}
return result;
}
@Override
public void register(String api, Invoker invoker, Resource resource) {
this.register(api, invoker, resource, false);
}
@Override
public void register(String api, Invoker invoker, Resource resource, boolean cover) {
if (api == null) {
throw new IllegalArgumentException("Api must not be null");
}
if (invoker == null) {
throw new IllegalArgumentException("Invoker must not be null");
}
if (!cover && this.isRegistered(api)) {
throw new IllegalStateException("Api already registered:" + api);
}
this.wrappers.put(api, new InvokeWrapper(invoker, resource));
}
@Override
public void setCache(Cache cache) {
this.cache = cache;
}
@Override
public void setCacheables(Cacheable... cacheables) {
this.cacheables = cacheables;
}
@Override
public void setForwards(Map forwards) {
this.forwards.clear();
if (forwards != null && !forwards.isEmpty()) {
this.forwards.putAll(forwards);
}
}
@Override
public void setListeners(Class type, InvokeListener... listeners) {
if (listeners.length > 0) {
List> list = Arrays.asList(listeners);
if (type == InvokeBeforeEvent.class) {
this.invokeBeforeListeners.clear();
this.invokeBeforeListeners.addAll(list);
} else if (type == InvokeAfterEvent.class) {
this.invokeAfterListeners.clear();
this.invokeAfterListeners.addAll(list);
} else if (type == InvokeErrorEvent.class) {
this.invokeErrorListeners.clear();
this.invokeErrorListeners.addAll(list);
} else if (type == InvokeCompleteEvent.class) {
this.invokeCompleteListeners.clear();
this.invokeCompleteListeners.addAll(list);
} else {
this.invokeBeforeListeners.clear();
this.invokeAfterListeners.clear();
this.invokeErrorListeners.clear();
this.invokeCompleteListeners.clear();
this.invokeBeforeListeners.addAll(list);
this.invokeAfterListeners.addAll(list);
this.invokeErrorListeners.addAll(list);
this.invokeCompleteListeners.addAll(list);
}
}
}
@Override
public void destroy() {
if (this.cache != null) {
synchronized (this) {
if (this.cache != null) {
this.logger.info("Destroy cache");
this.cache.destroy();
this.cache = null;
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy