All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alogic.ac.AbstractACMAccessController Maven / Gradle / Ivy

package com.alogic.ac;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.alogic.metrics.Dimensions;
import com.alogic.metrics.Fragment;
import com.alogic.metrics.Measures;
import com.alogic.metrics.Fragment.Method;
import com.alogic.metrics.impl.DefaultFragment;
import com.alogic.metrics.stream.MetricsCollector;
import com.anysoft.util.JsonTools;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.XmlTools;
import com.logicbus.backend.AccessController;
import com.logicbus.backend.Context;
import com.logicbus.models.catalog.Path;
import com.logicbus.models.servant.ServiceDescription;

/**
 * 基于ACM访问控制器的虚基类
 * 
 * @author yyduan
 * 
 * @since 1.6.10.6
 * 
 * @version 1.6.10.7 [20171115 duanyy] 
* - AccessStat中增加被Denied的统计信息
* * @version 1.6.10.12 [20171211 duanyy]
* - 兼容混合模式
* * @version 1.6.12.29 [20190409]
* - 优化指标输出模型,对接Prometheus;
* - 优化访问控制算法
* * @version 1.6.12.34 [20190507]
* - 统计数据支持按周期重置
*/ public abstract class AbstractACMAccessController implements AccessController { /** * a logger of slf4j */ protected static final Logger LOG = LoggerFactory.getLogger(AbstractACMAccessController.class); /** * 访问统计 */ protected Map statsData = null; /** * 统计周期 */ protected long statsCycle = 0; /** * 统计周期长度,毫秒 */ protected long statsCycleLength = 24 * 60 * 60 * 1000L; /** * 锁 */ protected ReentrantLock lock = new ReentrantLock(); /** * 指标ID */ protected String metricsId = "acm.stat"; public AbstractACMAccessController(){ } protected Map getStats(long now){ long cycle = (now / statsCycleLength)*statsCycleLength; if (cycle != statsCycle || statsData == null){ //新的周期开始 statsData = new ConcurrentHashMap(); statsCycle = cycle; } return statsData; } @Override public void configure(Element e, Properties props) { XmlElementProperties p = new XmlElementProperties(e,props); configure(p); } @Override public void configure(Properties props) { metricsId = PropertiesConstants.getString(props, "acm.metrics.id", metricsId); statsCycleLength = PropertiesConstants.getLong(props, "acm.stat.cycleLength", statsCycleLength); statsCycleLength = statsCycleLength <= 0? 24 * 60 * 60 * 1000L : statsCycleLength; } @Override public String [] getGroupList(){ return new String[]{"default"}; } @Override public AccessController getGroup(String id){ return this; } /** * 根据绘画获取ACM控制对象id * @param sessionId 会话id * @param serviceId 本次会话调用的服务 * @param servant 服务定义 * @param ctx 上下文 * @return 对象id */ protected String getACMObject(String sessionId,Path serviceId, ServiceDescription servant, Context ctx){ return sessionId; } /** * 根据会话获取ACM模型 * @param sessionId 会话id * @param serviceId 本次会话调用的服务 * @param servant 服务定义 * @param ctx 上下文 * @return ACM模型 */ abstract protected AccessControlModel getACM(String sessionId,Path serviceId, ServiceDescription servant, Context ctx); /** * 获取当前调用者的ip * @param ctx 上下文 * @return 调用者ip */ protected String getClientIp(Context ctx){ return ctx.getClientIp(); } @Override public int accessStart(String sessionId,Path serviceId, ServiceDescription servant, Context ctx) { AccessControlModel acm = getACM(sessionId,serviceId,servant,ctx); if (acm == null){ return -2; } lock.lock(); try{ long timestamp = System.currentTimeMillis(); Map stats = this.getStats(timestamp); String acmObject = getACMObject(sessionId,serviceId,servant,ctx); AccessStat current = stats.get(acmObject); if (current == null){ current = new AccessStat(); stats.put(acmObject, current); } current.timesTotal ++; current.thread ++; current.waitCnt = lock.getQueueLength(); timestamp = (timestamp / 60000)*60000; if (timestamp != current.timestamp){ //新的周期 current.timesOneMin = 1; current.deniedOneMin = 0; current.thread = 1; current.timestamp = timestamp; }else{ current.timesOneMin ++; } int priority = acm.getPriority(getClientIp(ctx), serviceId.getPath(), current); if (priority < 0){ current.deniedTotal ++; current.deniedOneMin ++; } return priority; }finally{ lock.unlock(); } } @Override public int accessEnd(String sessionId,Path serviceId, ServiceDescription servant, Context ctx) { lock.lock(); try{ Map stats = this.getStats(System.currentTimeMillis()); String acmObject = getACMObject(sessionId,serviceId,servant,ctx); AccessStat current = stats.get(acmObject); if (current != null){ current.thread --; } }finally{ lock.unlock(); } return 0; } @Override public void report(Element root) { if (root != null){ XmlTools.setLong(root, "cycle", this.statsCycle); XmlTools.setLong(root, "cycleLength", this.statsCycleLength); Map stats = this.getStats(System.currentTimeMillis()); int offset = XmlTools.getInt(root, "offset", 0); int limit = XmlTools.getInt(root,"limit",30); String keyword = XmlTools.getString(root, "keyword", ""); Document doc = root.getOwnerDocument(); Iterator iter = stats.keySet().iterator(); int current = 0; while (iter.hasNext()){ String key = iter.next(); boolean match = StringUtils.isEmpty(keyword) || key.contains(keyword); if (match){ if (current >= offset && current < offset + limit){ AccessStat value = stats.get(key); Element eAcl = doc.createElement("acl"); eAcl.setAttribute("session", key); eAcl.setAttribute("currentThread", String.valueOf(value.thread)); eAcl.setAttribute("timesTotal", String.valueOf(value.timesTotal)); eAcl.setAttribute("timesOneMin",String.valueOf(value.timesOneMin)); eAcl.setAttribute("waitCnt", String.valueOf(value.waitCnt)); eAcl.setAttribute("deniedTotal", String.valueOf(value.deniedTotal)); eAcl.setAttribute("deniedOneMin", String.valueOf(value.deniedOneMin)); root.appendChild(eAcl); } current ++; } } XmlTools.setInt(root, "total", current); XmlTools.setInt(root, "all", stats.size()); XmlTools.setString(root,"module",getClass().getName()); } } @Override public void report(Map json) { if (json != null){ JsonTools.setLong(json, "cycle", this.statsCycle); JsonTools.setLong(json, "cycleLength", this.statsCycleLength); Map stats = this.getStats(System.currentTimeMillis()); int offset = JsonTools.getInt(json, "offset", 0); int limit = JsonTools.getInt(json, "limit", 30); String keyword = JsonTools.getString(json,"keyword",""); List acls = new ArrayList(); Iterator iter = stats.keySet().iterator(); int current = 0; while (iter.hasNext()){ String key = iter.next(); boolean match = StringUtils.isEmpty(keyword) || key.contains(keyword); if (match){ if (current >= offset && current < offset + limit){ AccessStat value = stats.get(key); Map mAcl = new HashMap(); mAcl.put("session", key); mAcl.put("currentThread", String.valueOf(value.thread)); mAcl.put("timesTotal", String.valueOf(value.timesTotal)); mAcl.put("timesOneMin",String.valueOf(value.timesOneMin)); mAcl.put("waitCnt", String.valueOf(value.waitCnt)); mAcl.put("deniedTotal", String.valueOf(value.deniedTotal)); mAcl.put("deniedOneMin", String.valueOf(value.deniedOneMin)); acls.add(mAcl); } current ++; } } JsonTools.setInt(json, "total", current); JsonTools.setInt(json,"all",stats.size()); JsonTools.setString(json, "module", getClass().getName()); json.put("acl", acls); } } @Override public void report(MetricsCollector collector,Properties p) { if (collector != null){ Map stats = this.getStats(System.currentTimeMillis()); Iterator iter = stats.keySet().iterator(); while (iter.hasNext()){ String key = iter.next(); AccessStat value = stats.get(key); Fragment f = new DefaultFragment(metricsId); Dimensions dims = f.getDimensions(); if (dims != null){ dims.set("session", key, true); } Measures meas = f.getMeasures(); if (meas != null){ meas.set("thread", value.thread, Method.lst); meas.set("timesTotal", value.timesTotal,Method.lst); meas.set("timesOneMin", value.timesOneMin,Method.lst); meas.set("waitCnt", value.waitCnt,Method.lst); meas.set("deniedTotal", value.deniedTotal,Method.lst); meas.set("deniedOneMin", value.deniedOneMin,Method.lst); } collector.metricsIncr(f); } } } }