Merge branch 'jenkins_with_weblogic' of ssh://git@192.168.240.178:18081/eapim/eapim-online.git into jenkins_with_weblogic

This commit is contained in:
Yunsam.Eo
2025-12-12 08:46:04 +09:00
37 changed files with 1964 additions and 496 deletions
@@ -87,8 +87,10 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
if (adptUri == null) {
logError(servletRequest);
// throw new Exception("can not find Adapter Uri");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("can not find Adapter Uri");
String errorMsg = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_SERVICE_NOT_FOUND, "can not find Adapter Uri");
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.contentType(MediaType.APPLICATION_JSON)
.body(errorMsg);
}
//Received time , jwhong
@@ -100,8 +102,10 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
AdapterGroupVO adapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(adapterGroupName);
AdapterVO adapterVO = AdapterManager.getInstance().getAdapterVO(adapterGroupName, adapterName);
if (adapterVO == null) {
// throw new Exception("Adapter not found error");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Adapter not found error");
String errorMsg = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AP_ERROR, "Adapter not found error");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(errorMsg);
}
Properties httpProp = AdapterPropManager.getInstance().getProperties(adapterVO.getPropGroupName());
@@ -152,17 +156,19 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
}
} catch (HttpStatusException e) {
logger.warn("ApiAdapterController] " + adapterGroupName + "-" + adapterName + ">>" + e.getMessage());
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, MessageUtil.ERROR_CODE_AP_ERROR,
e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(e.getStatus()).contentType(mediaType).body(errorMsg);
} catch (JwtAuthException e) {
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, MessageUtil.ERROR_CODE_AUTH_FAIL,
e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(HttpStatus.UNAUTHORIZED).contentType(mediaType).body(errorMsg);
} catch (Exception e) {
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType).body(e);
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, MessageUtil.ERROR_CODE_AP_ERROR,
e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType).body(errorMsg);
} finally {
/**
* 로깅 인터셉터에 데이터를 전달하기 위한 처리
@@ -0,0 +1,65 @@
package com.eactive.eai.authserver.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
@ControllerAdvice
public class WebMvcConfig {
@ExceptionHandler({
HttpMessageNotReadableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestParameterException.class,
BindException.class
})
public String handleBadRequest(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_BAD_REQUEST);
request.setAttribute("errorMessage", "400 Bad Request");
return "forward:/error.jsp";
}
@ExceptionHandler(NoHandlerFoundException.class)
public String handleNotFound(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_NOT_FOUND);
request.setAttribute("errorMessage", "404 Not Found");
return "forward:/error.jsp";
}
@ExceptionHandler(AuthenticationException.class)
public String handleUnauthorized(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("errorMessage", "401 Unauthorized");
return "forward:/error.jsp";
}
@ExceptionHandler(AccessDeniedException.class)
public String handleAccessDenied(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("errorMessage", "403 Forbidden");
return "forward:/error.jsp";
}
@ExceptionHandler(Exception.class)
public String handleException(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
request.setAttribute("errorMessage", ex.getMessage());
return "forward:/error.jsp";
}
}
@@ -14,6 +14,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletResponse;
@Configuration
@EnableWebSecurity
@Order(1)
@@ -29,8 +31,23 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/error.jsp").permitAll()
.antMatchers("/**").permitAll()
.and()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("errorMessage", "401 Unauthorized");
request.getRequestDispatcher("/error.jsp").forward(request, response);
})
.accessDeniedHandler((request, response, accessDeniedException) -> {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("errorMessage", "403 Forbidden");
request.getRequestDispatcher("/error.jsp").forward(request, response);
})
.and()
.formLogin();
// .and()
// .httpBasic();
@@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.authserver.service.OAuth2Manager;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
@RestController
@RequestMapping("/auth/oauth/v2")
@@ -75,20 +76,12 @@ public class BearerTokenContoller {
return ResponseEntity.ok(resObject);
} catch (JwtAuthException e) {
logger.error(e);
JSONObject errorJson = new JSONObject();
errorJson.put("error", e.getCode());
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
return ResponseEntity.status(401).body(resObject);
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, e.getMessage());
return ResponseEntity.status(401).body(errorJson);
} catch (Exception e) {
logger.error(e);
JSONObject errorJson = new JSONObject();
errorJson.put("error", "invalid_request");
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
return ResponseEntity.status(500).body(resObject);
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage());
return ResponseEntity.status(500).body(errorJson);
}
}
@@ -16,6 +16,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
@Component
public class BearerTokenFilter extends OncePerRequestFilter{
@@ -35,8 +36,6 @@ public class BearerTokenFilter extends OncePerRequestFilter{
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
JSONObject resObject = new JSONObject();
try {
String auth = request.getHeader("Authorization");
@@ -62,23 +61,16 @@ public class BearerTokenFilter extends OncePerRequestFilter{
filterChain.doFilter(request, response);
} catch (JwtAuthException jae) {
logger.debug(jae.getMessage());
JSONObject errorJson = new JSONObject();
errorJson.put("error", jae.getCode());
errorJson.put("error_description", jae.getMessage());
resObject.putAll(errorJson);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 설정
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, jae.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(resObject.toJSONString());
response.getWriter().write(errorJson);
} catch (Exception e) {
logger.error(e.getMessage());
JSONObject errorJson = new JSONObject();
errorJson.put("error", "invalid_request");
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500 설정
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage());
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(resObject.toJSONString());
response.getWriter().write(errorJson);
}
}
}
@@ -1,14 +1,11 @@
package com.eactive.eai.authserver.custom;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Principal;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.HashMap;
@@ -39,7 +36,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.authserver.config.IssueLimitOAuth2Exception;
import com.eactive.eai.authserver.config.AuthorizationServerConfig;
import com.eactive.eai.authserver.config.RequestContextData;
import com.eactive.eai.authserver.dao.TokenIssuanceLogDAO;
import com.eactive.eai.authserver.service.OAuth2Manager;
@@ -48,8 +44,10 @@ import com.eactive.eai.authserver.vo.ClientVO;
import com.eactive.eai.common.dao.DAOException;
import com.eactive.eai.common.logger.EAIDBLogControl;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.UUID;
import com.eactive.eai.data.entity.onl.authserver.TokenIssuanceLog;
import com.fasterxml.jackson.databind.ObjectMapper;
@Controller
public class KjbMGOAuth2Controller {
@@ -63,7 +61,7 @@ public class KjbMGOAuth2Controller {
@RequestMapping(value = "/mapi/oauth2/token", method = RequestMethod.POST, produces = "application/json; charset=\"UTF-8\"")
@ResponseBody
public KjbMGOAuth2AccessTokenResponse token(@RequestBody KjbMGOAuth2AccessTokenRequest tokenRequest,
public ResponseEntity<String> token(@RequestBody KjbMGOAuth2AccessTokenRequest tokenRequest,
HttpServletRequest request, HttpServletResponse response) {
if (logger.isDebug()) {
logger.debug(tokenRequest.toString());
@@ -96,7 +94,7 @@ public class KjbMGOAuth2Controller {
ClientDetails clientDetails = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId);
verifyClient(clientDetails, clientId, scopeSet);
String traceId = UUID.randomUUID().toString().replace("-", "");
String traceId = UUID.randomUUID().toString().replace("-", "");
response.setHeader(HEADER_TRACEID, traceId);
HashMap<String, String> authorizationParameters = new HashMap<String, String>();
@@ -123,19 +121,22 @@ public class KjbMGOAuth2Controller {
responseToken.setExpiresOn(System.currentTimeMillis() + (token.getExpiresIn() * 1000));
responseToken.setScope(tokenRequest.getScope());
responseToken.setResource(tokenRequest.getResource());
// 성공 시 JSON 문자열로 변환하여 반환
ObjectMapper mapper = new ObjectMapper();
String successJson = mapper.writeValueAsString(responseToken);
return ResponseEntity.ok(successJson);
} catch (JwtAuthException e) {
response.setStatus(NumberUtils.toInt(StringUtils.left(e.getCode(), 3), HttpStatus.UNAUTHORIZED.value()));
responseToken.setResponseCode(e.getCode());
responseToken.setResponseMessage(e.getMessage());
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, e.getMessage());
int statusCode = NumberUtils.toInt(StringUtils.left(e.getCode(), 3), HttpStatus.UNAUTHORIZED.value());
return ResponseEntity.status(statusCode).body(errorJson);
} catch (Exception e) {
logger.error(e.getMessage());
response.setStatus(HttpStatus.UNAUTHORIZED.value());
responseToken.setResponseCode(
String.format("%d%s%s", HttpStatus.UNAUTHORIZED.value(), SERVICE_CODE_ACCESS_TOKEN, "00"));
responseToken.setResponseMessage("Unauthorized. [Unknown]");
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, "Unauthorized. [Unknown]");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(errorJson);
}
return responseToken;
}
private void verifyClient(ClientDetails clientDetails, String clientId, Set<String> scopeSet)
@@ -1,425 +0,0 @@
package com.eactive.eai.custom.inflow;
import java.time.Duration;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.dao.DAOFactory;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.inflow.CustomBucket;
import com.eactive.eai.common.inflow.InflowControlDAO;
import com.eactive.eai.common.inflow.InflowControlManager;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.lifecycle.Lifecycle;
import com.eactive.eai.common.lifecycle.LifecycleException;
import com.eactive.eai.common.lifecycle.LifecycleListener;
import com.eactive.eai.common.lifecycle.LifecycleSupport;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket4j;
import io.github.bucket4j.local.LocalBucketBuilder;
public class InflowControlManagerSBI implements Lifecycle, com.eactive.eai.common.inflow.Bucket
{
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
private static InflowControlManagerSBI manager;
private HashMap<String,CustomBucket> adapterBucketList;
private HashMap<String,CustomBucket> interfaceBucketList;
private boolean started;
private LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
* 1. 기능 : Default Constructor
* 2. 처리 개요 : C2RServiceVO Rule 정보를 저장하기 위한 HashMap을 초기화한다.
* 3. 주의사항
*
**/
private InflowControlManagerSBI() {
adapterBucketList = new HashMap<String, CustomBucket>();
interfaceBucketList = new HashMap<String, CustomBucket>();
}
/**
* 1. 기능 : InflowControlManagerSBI Singleton Object를 반환하는 getter method
* 2. 처리 개요 : C2RServiceManager Singleton Object를 반환한다.
* 3. 주의사항
*
* @return InflowControlManagerSBI Singleton object
**/
public static InflowControlManagerSBI getInstance() {
if(manager == null) {
synchronized(InflowControlManagerSBI.class) {
if(manager == null) {
manager = new InflowControlManagerSBI();
}
}
}
return manager;
}
public static com.eactive.eai.common.inflow.Bucket getBucket() {
if(manager == null) {
synchronized(InflowControlManagerSBI.class) {
if(manager == null) {
manager = new InflowControlManagerSBI();
}
}
}
return manager;
}
/**
* 유량제어 대상인 거래인지 체크한다.(사이트에 맞게 구성)
* @param eaiServerManager
* @param eaiMessage
* @return
*/
public static Boolean isTargetOfInflowControl(EAIServerManager eaiServerManager, EAIMessage eaiMessage) {
// 1. 모든 요청거래
InterfaceMapper mapper = eaiMessage.getMapper();
String returnType = mapper.getSendRecvDivision(eaiMessage.getStandardMessage()); // S|R
if (STDMessageKeys.SEND_RECV_CD_SEND.equals(returnType)) {
return new Boolean(true);
}
return new Boolean(false);
}
public void start() throws LifecycleException {
if (started)
throw new LifecycleException("RECEAICMM201");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STARTING_EVENT, this);
// C2RServiceVO Table Initializing ....
try {
init();
} catch(Exception e) {
//throw new LifecycleException("RECEAICMM202");
throw new LifecycleException(ExceptionUtil.getErrorCode(e,"RECEAICMM202"));
}
started = true;
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
}
private void init() throws Exception {
initAdapter();
initInterface();
}
private void initAdapter() throws Exception {
// Initializing ....
adapterBucketList = new HashMap<String, CustomBucket>();
InflowControlDAO dao = null;
dao = (InflowControlDAO) DAOFactory.newInstance().create(InflowControlDAO.class);
List<InflowTargetVO> inflowAdapterVoList = dao.getInflowAdapterList();
for (InflowTargetVO inflowVo : inflowAdapterVoList) {
if (InflowControlManagerSBI.isInflowTarget(inflowVo)) {
CustomBucket bucket = makeBucketUsingInflowVO(inflowVo);
if (bucket != null) {
adapterBucketList.put(inflowVo.getName(), bucket);
}
}
}
}
private void initInterface() throws Exception {
// Initializing ....
interfaceBucketList = new HashMap<String, CustomBucket>();
InflowControlDAO dao = null;
dao = (InflowControlDAO) DAOFactory.newInstance().create(InflowControlDAO.class);
List<InflowTargetVO> inflowInterfaceVoList = dao.getInflowInterfaceList();
for (InflowTargetVO inflowVo : inflowInterfaceVoList) {
if (InflowControlManagerSBI.isInflowTarget(inflowVo)) {
CustomBucket bucket = makeBucketUsingInflowVO(inflowVo);
if (bucket != null) {
interfaceBucketList.put(inflowVo.getName(), bucket);
}
}
}
}
public synchronized void reloadAdapter() throws Exception {
if(logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload all Started ...");
}
initAdapter();
if(logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload all finished ...");
}
}
public synchronized void reloadInterface() throws Exception {
if(logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload all Started ...");
}
initInterface();
if(logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload all finished ...");
}
}
public synchronized void reloadAdapter(String adapter) throws Exception {
if (logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload Started ...");
}
InflowControlDAO dao = null;
dao = (InflowControlDAO) DAOFactory.newInstance().create(InflowControlDAO.class);
Map<String, InflowTargetVO> map = dao.getInflowTargetByAdater(adapter);
if (map != null) {
Iterator it = map.keySet().iterator();
String key = "";
for (int i = 0; it.hasNext(); i++) {
key = (String) it.next();
InflowTargetVO inflowTarget = map.get(key);
if (InflowControlManagerSBI.isInflowTarget(inflowTarget)) {
CustomBucket bucket = makeBucketUsingInflowVO(inflowTarget);
if (bucket != null) {
adapterBucketList.put(inflowTarget.getName(), bucket);
} else {
adapterBucketList.remove(inflowTarget.getName());
}
} else {
adapterBucketList.remove(inflowTarget.getName());
}
}
}
if (logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload finished ...");
}
}
public synchronized void reloadInterface(String inter) throws Exception {
if (logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload Started ...");
}
InflowControlDAO dao = null;
dao = (InflowControlDAO) DAOFactory.newInstance().create(InflowControlDAO.class);
Map<String, InflowTargetVO> map = dao.getInflowTargetByInterface(inter);
if (map != null) {
Iterator it = map.keySet().iterator();
String key = "";
for (int i = 0; it.hasNext(); i++) {
key = (String) it.next();
InflowTargetVO inflowTarget = map.get(key);
if (InflowControlManagerSBI.isInflowTarget(inflowTarget)) {
CustomBucket bucket = makeBucketUsingInflowVO(inflowTarget);
if (bucket != null) {
interfaceBucketList.put(inflowTarget.getName(), bucket);
} else {
interfaceBucketList.remove(inflowTarget.getName());
}
} else {
interfaceBucketList.remove(inflowTarget.getName());
}
}
}
if (logger.isWarn()) {
logger.warn("InflowControlManagerSBI] reload finished ...");
}
}
/**
* 1. 기능 : Lifecycle의 stop 메서드로 C2RServiceManager를 종료하는 메서드
* 2. 처리 개요 : 멤버에 캐싱한 C2RServiceVO Rule 정보를 clear한다.
* 3. 주의사항
*
* @exception LifecycleException 이미 종료된 경우 발생(RECEAICMM203)
**/
public void stop() throws LifecycleException {
// Validate and update our current component state
if (!started)
throw new LifecycleException("RECEAICMM203");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STOPING_EVENT, this);
adapterBucketList.clear();
interfaceBucketList.clear();
started = false;
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
}
/**
* 1. 기능 : LifecycleListener를 등록하는 메서드
* 2. 처리 개요 : LifecycleListener를 등록한다.
* 3. 주의사항
*
* @param listener LifecycleEvent를 수신한 LifecycleListener
**/
public void addLifecycleListener(LifecycleListener listener)
{
lifecycle.addLifecycleListener(listener);
}
public LifecycleListener[] findLifecycleListeners()
{
return lifecycle.findLifecycleListeners();
}
public void removeLifecycleListener(LifecycleListener listener)
{
lifecycle.removeLifecycleListener(listener);
}
public boolean isStarted() {
return this.started;
}
public String[] getAdapterAllKeys() {
Iterator it = this.adapterBucketList.keySet().iterator();
String[] svcCd = new String[this.adapterBucketList.size()];
for(int i = 0; it.hasNext(); i++){
svcCd[i] = (String)it.next();
}
Arrays.sort(svcCd);
return svcCd;
}
public String[] getInterfaceAllKeys() {
Iterator it = this.interfaceBucketList.keySet().iterator();
String[] svcCd = new String[this.interfaceBucketList.size()];
for(int i = 0; it.hasNext(); i++){
svcCd[i] = (String)it.next();
}
Arrays.sort(svcCd);
return svcCd;
}
public void removeAdapter(String adapter) {
adapterBucketList.remove(adapter);
}
public void removeInterface(String inter) {
interfaceBucketList.remove(inter);
}
private CustomBucket makeBucketUsingInflowVO(InflowTargetVO inflowTarget) {
if (InflowControlManagerSBI.isInflowTarget(inflowTarget)) {
LocalBucketBuilder builder = Bucket4j.builder();
if (inflowTarget.getThresholdPerSecond() > 0) { // TPS
builder.addLimit(Bandwidth.simple(inflowTarget.getThresholdPerSecond(), Duration.ofSeconds(1)));
}
if (inflowTarget.getThreshold() > 0 && StringUtils.isNotBlank(inflowTarget.getThresholdTimeUnit())) {
builder.addLimit(Bandwidth.simple(inflowTarget.getThreshold(),
InflowControlManagerSBI.getPeriod(inflowTarget.getThresholdTimeUnit())));
}
return new CustomBucket(builder.build(), inflowTarget);
}
return null;
}
@Override
public boolean isAdapterPass(String adapter) {
CustomBucket b = adapterBucketList.get(adapter);
if ( b == null ) return true;
return b.getLocalBucket().tryConsume(1);
}
@Override
public boolean isInterfacePass(String inter) {
CustomBucket b = interfaceBucketList.get(inter);
if ( b == null ) return true;
return b.getLocalBucket().tryConsume(1);
}
@Override
public InflowTargetVO getAdapterInflowThreashold(String adapter) {
CustomBucket b = adapterBucketList.get(adapter);
if (b == null) return null;
return b.getInflowTargetVo();
}
@Override
public InflowTargetVO getInterfaceInflowThreashold(String inter) {
CustomBucket b = interfaceBucketList.get(inter);
if (b == null) return null;
return b.getInflowTargetVo();
}
@Override
public InflowTargetVO getInflowThreashold(String inter) {
return null;
}
public InflowTargetVO getAdapterInflow(String adapter) {
CustomBucket b = adapterBucketList.get(adapter);
if (b == null) return null;
return b.getInflowTargetVo();
}
public InflowTargetVO getInterfaceInflow(String inter) {
CustomBucket b = interfaceBucketList.get(inter);
if (b == null) return null;
return b.getInflowTargetVo();
}
public static boolean isInflowTarget(InflowTargetVO inflowTarget) {
if (inflowTarget == null || !inflowTarget.isActivate()) {
return false;
}
if (inflowTarget.getThresholdPerSecond() > 0) {
return true;
}
if (inflowTarget.getThreshold() > 0 && StringUtils.equalsAnyIgnoreCase(inflowTarget.getThresholdTimeUnit(),
InflowControlManager.QUOTA_TIMEUNIT_DAY, InflowControlManager.QUOTA_TIMEUNIT_SECOND,
InflowControlManager.QUOTA_TIMEUNIT_MINUTE, InflowControlManager.QUOTA_TIMEUNIT_HOUR,
InflowControlManager.QUOTA_TIMEUNIT_DAY, InflowControlManager.QUOTA_TIMEUNIT_MONTH)) {
return true;
}
return false;
}
public static Duration getPeriod(String timeUnit) {
if (StringUtils.equalsIgnoreCase(timeUnit, InflowControlManager.QUOTA_TIMEUNIT_SECOND)) {
return Duration.ofSeconds(1);
} else if (StringUtils.equalsIgnoreCase(timeUnit, InflowControlManager.QUOTA_TIMEUNIT_MINUTE)) {
return Duration.ofMinutes(1);
} else if (StringUtils.equalsIgnoreCase(timeUnit, InflowControlManager.QUOTA_TIMEUNIT_HOUR)) {
return Duration.ofHours(1);
} else if (StringUtils.equalsIgnoreCase(timeUnit, InflowControlManager.QUOTA_TIMEUNIT_DAY)) {
return Duration.ofDays(1);
} else if (StringUtils.equalsIgnoreCase(timeUnit, InflowControlManager.QUOTA_TIMEUNIT_MONTH)) {
Calendar calendar = Calendar.getInstance();
return Duration.ofDays(calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
} else {
return null;
}
}
}
@@ -0,0 +1,101 @@
package com.eactive.eai.manage.inflow;
import java.util.List;
public class GroupBucketStatusDTO {
private String groupId;
private String groupName;
private boolean activate;
private List<BucketInfo> buckets;
public static class BucketInfo {
private String type; // "perSecond" | "threshold"
private long capacity; // 최대 토큰 수
private long availableTokens; // 현재 사용 가능한 토큰 수
private String timeUnit; // threshold인 경우 시간 단위
private double usagePercent; // 사용률 (100 - availableTokens/capacity * 100)
public BucketInfo() {}
public BucketInfo(String type, long capacity, long availableTokens, String timeUnit) {
this.type = type;
this.capacity = capacity;
this.availableTokens = availableTokens;
this.timeUnit = timeUnit;
this.usagePercent = capacity > 0 ?
Math.round((1.0 - (double) availableTokens / capacity) * 10000) / 100.0 : 0;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public long getCapacity() {
return capacity;
}
public void setCapacity(long capacity) {
this.capacity = capacity;
}
public long getAvailableTokens() {
return availableTokens;
}
public void setAvailableTokens(long availableTokens) {
this.availableTokens = availableTokens;
}
public String getTimeUnit() {
return timeUnit;
}
public void setTimeUnit(String timeUnit) {
this.timeUnit = timeUnit;
}
public double getUsagePercent() {
return usagePercent;
}
public void setUsagePercent(double usagePercent) {
this.usagePercent = usagePercent;
}
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public boolean isActivate() {
return activate;
}
public void setActivate(boolean activate) {
this.activate = activate;
}
public List<BucketInfo> getBuckets() {
return buckets;
}
public void setBuckets(List<BucketInfo> buckets) {
this.buckets = buckets;
}
}
@@ -0,0 +1,56 @@
package com.eactive.eai.manage.inflow;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/manage/inflow/group")
public class InflowGroupBucketController {
@Autowired
private InflowGroupBucketService bucketService;
/**
* 특정 그룹의 버킷 상태 조회
* GET /manage/inflow/group/{groupId}/bucket-status
*/
@GetMapping("/{groupId}/bucket-status")
public ResponseEntity<?> getGroupBucketStatus(@PathVariable String groupId) {
GroupBucketStatusDTO status = bucketService.getGroupBucketStatus(groupId);
if (status == null) {
Map<String, Object> error = new HashMap<>();
error.put("success", false);
error.put("message", "그룹을 찾을 수 없습니다: " + groupId);
return ResponseEntity.ok(error);
}
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("data", status);
return ResponseEntity.ok(result);
}
/**
* 모든 그룹의 버킷 상태 조회
* GET /manage/inflow/group/bucket-status
*/
@GetMapping("/bucket-status")
public ResponseEntity<?> getAllGroupBucketStatus() {
List<GroupBucketStatusDTO> statusList = bucketService.getAllGroupBucketStatus();
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("data", statusList);
result.put("count", statusList.size());
return ResponseEntity.ok(result);
}
}
@@ -0,0 +1,105 @@
package com.eactive.eai.manage.inflow;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.eactive.eai.common.inflow.CustomGroupBucket;
import com.eactive.eai.common.inflow.InflowControlManager;
import com.eactive.eai.common.inflow.InflowGroupVO;
@Service
public class InflowGroupBucketService {
public GroupBucketStatusDTO getGroupBucketStatus(String groupId) {
InflowControlManager manager = InflowControlManager.getInstance();
InflowGroupVO groupVo = manager.getGroupInflowThreshold(groupId);
if (groupVo == null) {
return null;
}
GroupBucketStatusDTO dto = new GroupBucketStatusDTO();
dto.setGroupId(groupId);
dto.setGroupName(groupVo.getGroupName());
dto.setActivate(groupVo.isActivate());
List<GroupBucketStatusDTO.BucketInfo> buckets = new ArrayList<>();
// CustomGroupBucket에서 직접 토큰 조회
CustomGroupBucket customGroupBucket = getCustomGroupBucket(groupId);
// perSecond bucket
if (groupVo.getThresholdPerSecond() > 0) {
long capacity = groupVo.getThresholdPerSecond();
long available = capacity;
if (customGroupBucket != null) {
long tokens = customGroupBucket.getPerSecondAvailableTokens();
if (tokens >= 0) {
available = Math.min(tokens, capacity);
}
}
buckets.add(new GroupBucketStatusDTO.BucketInfo(
"perSecond",
capacity,
available,
"SEC"
));
}
// threshold bucket
if (groupVo.getThreshold() > 0) {
long capacity = groupVo.getThreshold();
long available = capacity;
if (customGroupBucket != null) {
long tokens = customGroupBucket.getThresholdAvailableTokens();
if (tokens >= 0) {
available = Math.min(tokens, capacity);
}
}
buckets.add(new GroupBucketStatusDTO.BucketInfo(
"threshold",
capacity,
available,
groupVo.getThresholdTimeUnit()
));
}
dto.setBuckets(buckets);
return dto;
}
/**
* 그룹 버킷 조회 (리플렉션 사용)
*/
public CustomGroupBucket getCustomGroupBucket(String groupId) {
try {
InflowControlManager manager = InflowControlManager.getInstance();
Field field = InflowControlManager.class.getDeclaredField("groupBucketList");
field.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String, CustomGroupBucket> groupBucketList =
(Map<String, CustomGroupBucket>) field.get(manager);
return groupBucketList.get(groupId);
} catch (Exception e) {
return null;
}
}
public List<GroupBucketStatusDTO> getAllGroupBucketStatus() {
InflowControlManager manager = InflowControlManager.getInstance();
String[] groupIds = manager.getGroupAllKeys();
List<GroupBucketStatusDTO> result = new ArrayList<>();
for (String groupId : groupIds) {
GroupBucketStatusDTO dto = getGroupBucketStatus(groupId);
if (dto != null) {
result.add(dto);
}
}
return result;
}
}