package com.gustz.dove.cli.api.app.service.impl; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.sinovatech.fw.api.vo.Order; import com.sinovatech.fw.dao.SqlDao; import com.sinovatech.fw.query.util.QueryInfo; import com.sinovatech.fw.query.util.QueryInfoBuilder; import com.sinovatech.fw.service.impl.AbstractDataService; import com.gustz.dove.cli.api.app.vo.ClientAppVo; import com.gustz.dove.cli.api.service.util.ClientConstants; import com.sinovatech.rd.wcsb.repo.app.AppConstants; import com.sinovatech.rd.wcsb.repo.app.dao.ClientAppDao; import com.sinovatech.rd.wcsb.repo.app.po.ClientAppPo; import com.sinovatech.rd.wcsb.repo.dict.DictConstants; /** * * TODO: 客户端应用服务接口的实现 * * @author ZHENFENG ZHANG * @since [Jan 19, 2015] */ @Service public class ClientAppService extends AbstractDataService<ClientAppVo, ClientAppPo, String> { private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private SqlDao sqlDao; private ClientAppDao dao; private final Lock lock = new ReentrantLock(); private ConcurrentMap<String, ClientAppVo> cacheMap = new ConcurrentHashMap<String, ClientAppVo>(); @Autowired public void needDao(ClientAppDao dao) { super.setDao(dao); this.dao = dao; } public String getId(ClientAppVo vo) { return vo.getId(); } /** * Init data */ @PostConstruct private void init() { List<ClientAppVo> _list = this.listActive(); if (_list == null || _list.isEmpty()) { logger.warn("Client app data list is empty."); return; } for (ClientAppVo vo : _list) { if (vo == null) { continue; } String accountCode = vo.getAccountCode(); String cliAppCode = vo.getCliAppCode(); String websCodes = vo.getWebsCodes(); String receiveUrl = vo.getReceiveUrl(); String oauthCbUrl = vo.getOauthCbUrl(); if (StringUtils.isBlank(accountCode) || StringUtils.isBlank(cliAppCode) || StringUtils.isBlank(websCodes) || StringUtils.isBlank(receiveUrl) || StringUtils.isBlank(oauthCbUrl)) { logger.error("Client app [{}]: accountCode/cliAppCode/websCodes/receiveUrl/oauthCbUrl is empty!.", vo.getCliAppName()); continue; } cacheMap.put(vo.getAccountCode(), vo); // logger.info("客户端应用[ {} ]已被成功加载到缓存中 \n", vo.getCliAppName()); } } public void reloadCliApp() { lock.lock(); try { this.init(); } finally { lock.unlock(); } } /** * 查询全部活动的应用 * * @return */ public List<ClientAppVo> listActive() { // return this.listAll(new ClientAppVo(null, AppConstants.StatusGc.S0.name())); } /** * 查询全部 * * @param search * @return */ public List<ClientAppVo> listAll(ClientAppVo search) { QueryInfo info = this.prepareQuery(search).build(); // List<ClientAppVo> _list = sqlDao.listAll(info.getSql(), ClientAppVo.class, info.getParArr()); return _list; } /** * 分页查询 * * @param search * @param start * @param limit * @param orders * @return */ private List<ClientAppVo> ecList(ClientAppVo search, int start, int limit, List<Order> orders) { QueryInfo queryInfo = prepareQuery(search).order(orders).build(); // List<ClientAppVo> _list = sqlDao.list(queryInfo.getSql(), start, limit, ClientAppVo.class, queryInfo.getParArr()); return _list; } private QueryInfoBuilder prepareQuery(ClientAppVo search) { String hql = "select t.*,t1.ACCOUNT_NAME,t1.WEC_APP_ID,t1.WEC_APP_SECRET from WCSB_CLIENT_APP t,WCSB_ACCOUNT t1 where t.ACCOUNT_CODE=t1.ACCOUNT_CODE "; QueryInfoBuilder builder = QueryInfoBuilder.ins(hql) // .andEq("t.IS_DELETE", ClientConstants.NO) // .andEq("t.CLI_APP_CODE", search.getCliAppCode()) // 编码 // .andContains("t.CLI_APP_NAME", search.getCliAppName()) // 名称 .andIn("t.WEBS_CODES", search.getWebsCodesIn()) // 服务编码集 .andEq("t.STATUS", search.getStatus()) // 状态 .andIn("t.STATUS", search.getStatusIn()) // 状态多个 .andEq("t.ACCOUNT_CODE", search.getAccountCode()) // 账号 .andEq("t.IS_REPLY_MSG", search.getIsReplyMsg()) // .andEq("t1.IS_DELETE", ClientConstants.NO) // .andEq("t1.STATUS", DictConstants.RunStateGc.S0.name()) // 账户状态:S0已启用 // .orderDesc("t.CREATE_TIME"); return builder; } /** * 获取当前接入的客户端APP * * <pre> * 状态为S99的客户端APP(唯一) * </pre> * @return */ public ClientAppVo getCurrCliApp() { List<ClientAppVo> _list = this.ecList(new ClientAppVo(null, AppConstants.StatusGc.S99.name()), 1, 1, null); if (_list != null && !_list.isEmpty()) { return _list.get(0); } return null; } /** * 启用客户端APP */ public void enableCliApp() { lock.lock(); try { ClientAppVo _appVo = this.getCurrCliApp(); if (_appVo != null) { // 启用 ClientAppPo po = this.dao.get(_appVo.getId()); po.setStatus(AppConstants.StatusGc.S0.name()); // this.dao.update(po); // 更新缓存数据 this.cacheMap.put(_appVo.getAccountCode(), _appVo); } } finally { lock.unlock(); } } /** * 获取缓存中可用的客户端应用 * * @return key=AccountCode value=ClientAppVo */ public ConcurrentMap<String, ClientAppVo> getActiveCacheByAcc() { this.lock.lock(); try { if (this.cacheMap.isEmpty()) { this.init(); } } finally { this.lock.unlock(); } return this.cacheMap; } /** * 获取有效的客户端应用 * * @return key=CliAppCode value=ClientAppVo */ public Map<String, ClientAppVo> getActiveCliApp() { Map<String, ClientAppVo> _map = new HashMap<String, ClientAppVo>(); // Map<String, ClientAppVo> _cacheMap = this.getActiveCacheByAcc(); if (_cacheMap != null && _cacheMap.size() > 0) { for (Map.Entry<String, ClientAppVo> _entry : _cacheMap.entrySet()) { _map.put(_entry.getValue().getCliAppCode(), _entry.getValue()); } } _cacheMap = null; return _map; } /** * 校验客户端APP * * @param vo * @return */ public void checkCliApp(final ClientAppVo vo) { // 客户端APP编码 1. final String cliAppCode = vo.getCliAppCode(); this.hasRequired("cliAppCode", cliAppCode); // 客户端APP密码 2. final String cliAppPwd = vo.getCliAppPwd(); this.hasRequired("cliAppPwd", cliAppPwd); // 开发者账号 3. String accountCode = vo.getAccountCode(); this.hasRequired("accountCode", accountCode); // 服务编码(请求服务的接口编码)4. TODO // String websCodes = vo.getWebsCodes(); // this.hasRequired("websCodes", websCodes); // 客户端IP地址 5. String[] cliIpAddrs = vo.getCliIpAddrsIn(); this.hasRequireds("cliIpAddrs", cliIpAddrs); // --------------- 授权校验 --------------- begin ClientAppVo _vo2 = this.getActiveCliApp().get(cliAppCode); // 1. if (_vo2 == null) { throw new IllegalArgumentException("Client app is not authorized."); } if (!cliAppPwd.equals(_vo2.getCliAppPwd())) { throw new IllegalArgumentException("Client password is error."); } if (!accountCode.equals(_vo2.getAccountCode())) { throw new IllegalArgumentException("Client dev account code is not authorized."); } // 服务编码(请求服务的接口编码)TODO // String[] _tgWebsCodes = _vo2.getWebsCodes().split(","); // if (!this.isContain(websCodes.split(","), _tgWebsCodes)) { // throw new IllegalArgumentException(String.format("Web service code[ %1$s ] is not authorized.", websCodes)); // } // IPs -- begin String[] _tgCliIpAddrs = _vo2.getCliIpAddrs().split(","); if (!this.isContain(cliIpAddrs, _tgCliIpAddrs)) { throw new IllegalArgumentException("Client IP address list is not authorized."); } // IPs -- end // --------------- 授权校验 --------------- end } /** * Is contain * * @param srcs * @param tgs * @return */ private boolean isContain(String[] srcs, String[] tgs) { for (String _ts : tgs) { for (String _ss : srcs) { if (_ts.equals(_ss)) { return true; } } } return false; } /** * Has required * * @param field * @param data */ private void hasRequired(final String field, final String data) { if (StringUtils.isBlank(data)) { throw new IllegalArgumentException(String.format("Arg '%1$s[ %2$s ]' is required.", field, data)); } } /** * Has required * * @param field * @param datas */ private void hasRequireds(final String field, final String[] datas) { if (datas == null || datas.length == 0) { throw new IllegalArgumentException(String.format("Arg '%1$s[ null ]' is required.", field)); } } }