Merge branch '알람기능_및_UMS_연동' into jenkins_with_weblogic
This commit is contained in:
@@ -6,6 +6,11 @@ import com.eactive.eai.common.lifecycle.LifecycleListener;
|
|||||||
import com.eactive.eai.common.lifecycle.LifecycleSupport;
|
import com.eactive.eai.common.lifecycle.LifecycleSupport;
|
||||||
import com.eactive.eai.common.property.PropManager;
|
import com.eactive.eai.common.property.PropManager;
|
||||||
import com.eactive.eai.common.util.Logger;
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
import com.eactive.eai.custom.alarm.AlarmStateManager;
|
||||||
|
import com.eactive.eai.custom.alarm.condition.AlarmCondition;
|
||||||
|
import com.eactive.eai.custom.alarm.event.AlarmEvent;
|
||||||
|
import com.eactive.eai.custom.alarm.key.CoreAlarmKey;
|
||||||
|
|
||||||
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
|
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
|
||||||
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
|
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
|
||||||
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
|
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
|
||||||
@@ -71,6 +76,28 @@ public class CircuitBreakerManager implements Lifecycle {
|
|||||||
circuitBreakerRegistry = CircuitBreakerRegistry.of(config);
|
circuitBreakerRegistry = CircuitBreakerRegistry.of(config);
|
||||||
|
|
||||||
TaggedCircuitBreakerMetrics.ofCircuitBreakerRegistry(circuitBreakerRegistry).bindTo(meterRegistry);
|
TaggedCircuitBreakerMetrics.ofCircuitBreakerRegistry(circuitBreakerRegistry).bindTo(meterRegistry);
|
||||||
|
|
||||||
|
circuitBreakerRegistry.getEventPublisher().onEntryAdded(event -> {
|
||||||
|
CircuitBreaker cb = event.getAddedEntry();
|
||||||
|
String apiId = cb.getName();
|
||||||
|
|
||||||
|
// 여기서 상태 변경 리스너를 한 번만 등록
|
||||||
|
cb.getEventPublisher().onStateTransition(stateEvent -> {
|
||||||
|
CircuitBreaker.State from = stateEvent.getStateTransition().getFromState();
|
||||||
|
CircuitBreaker.State to = stateEvent.getStateTransition().getToState();
|
||||||
|
|
||||||
|
AlarmEvent alarmEvent = AlarmEvent.builder().key(CoreAlarmKey.CircuitBreaker)
|
||||||
|
.condition(AlarmCondition.builder().build())
|
||||||
|
.message(String.format("CircuitBreaker state changed. apiId=%s, %s -> %s", apiId, from, to))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
AlarmStateManager.getAlarmStateManager().onEvnet(alarmEvent);
|
||||||
|
|
||||||
|
logger.warn("CircuitBreaker state changed. apiId={}, {} -> {}", apiId, from, to);
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info("Registered StateTransition listener for: {}", apiId);
|
||||||
|
});
|
||||||
|
|
||||||
logger.info("init CircuitBreaker - "+config);
|
logger.info("init CircuitBreaker - "+config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.eactive.eai.common.util;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public final class Jsons {
|
||||||
|
|
||||||
|
private Jsons() {}
|
||||||
|
|
||||||
|
public static final Gson GSON = new Gson();
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.eactive.eai.custom.alarm;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.property.PropManager;
|
||||||
|
import com.eactive.eai.common.util.Jsons;
|
||||||
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
import com.eactive.eai.custom.alarm.key.AlarmKey;
|
||||||
|
import com.eactive.eai.custom.alarm.key.DynamicAlarmKey;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.AlarmPolicy;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.CounterPolicy;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.SendPolicy;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.TimerPolicy;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AlarmService {
|
||||||
|
|
||||||
|
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
|
|
||||||
|
final static String ALARM_GROUP = "Alarm";
|
||||||
|
final static String ALARM_KEY = "{ALARM}";
|
||||||
|
final static String ALARM_RECIVER = "{RECIVER}";
|
||||||
|
final static String ALARM_EABLE = "enable.alarm";
|
||||||
|
|
||||||
|
public Map<AlarmKey, AlarmPolicy> getAlarmPolicy() {
|
||||||
|
|
||||||
|
Map<AlarmKey, AlarmPolicy> policyMap = new HashMap<AlarmKey, AlarmPolicy>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
Properties props = PropManager.getInstance().getProperties(ALARM_GROUP);
|
||||||
|
|
||||||
|
props.forEach((key, value) -> {
|
||||||
|
|
||||||
|
String keyName = (String) key;
|
||||||
|
String configStr = (String) value;
|
||||||
|
|
||||||
|
if (keyName.contains(ALARM_KEY)) {
|
||||||
|
|
||||||
|
AlarmPolicy newPolicy = buildAlarmPolicy(keyName, configStr);
|
||||||
|
policyMap.put(newPolicy.getAlarmKey(), newPolicy);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("getAlarmPolicy fail.", e);
|
||||||
|
return Collections.EMPTY_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return policyMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAlarmEnabled() {
|
||||||
|
return Optional.ofNullable(PropManager.getInstance().getProperty(ALARM_GROUP, ALARM_EABLE))
|
||||||
|
.map(Boolean::valueOf).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlarmPolicy buildAlarmPolicy(String key, String configJsonStr) {
|
||||||
|
|
||||||
|
JsonObject alarmConfig = Jsons.GSON.fromJson(configJsonStr, JsonObject.class);
|
||||||
|
|
||||||
|
String policyType = alarmConfig.get("type").getAsString();
|
||||||
|
int thresholdCount = Optional.ofNullable(alarmConfig.get("thresholdCount")).map(i -> i.getAsInt()).orElse(5);
|
||||||
|
int timeWindowSec = Optional.ofNullable(alarmConfig.get("timeWindowSec")).map(i -> i.getAsInt()).orElse(60);
|
||||||
|
|
||||||
|
AlarmPolicy alarmPolicy;
|
||||||
|
|
||||||
|
if ("count".equals(policyType)) {
|
||||||
|
alarmPolicy = CounterPolicy.builder().alarmKey(new DynamicAlarmKey(key)).thresholdCount(thresholdCount)
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
alarmPolicy = TimerPolicy.builder().alarmKey(new DynamicAlarmKey(key)).timeWindowMs(timeWindowSec * 1000)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return alarmPolicy;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<AlarmKey, SendPolicy> getSendPolicy() {
|
||||||
|
|
||||||
|
Map<AlarmKey, SendPolicy> policyMap = new HashMap<AlarmKey, SendPolicy>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
Properties props = PropManager.getInstance().getProperties(ALARM_GROUP);
|
||||||
|
|
||||||
|
props.forEach((key, value) -> {
|
||||||
|
String keyName = (String) key;
|
||||||
|
String configStr = (String) value;
|
||||||
|
|
||||||
|
if (!keyName.contains(ALARM_RECIVER))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SendPolicy newPolicy = buildSendPolicy(keyName, configStr);
|
||||||
|
|
||||||
|
policyMap.put(newPolicy.getAlarmKey(), newPolicy);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("getSendPolicy fail.", e);
|
||||||
|
return Collections.EMPTY_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return policyMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SendPolicy buildSendPolicy(String key, String configStr) {
|
||||||
|
|
||||||
|
List<String> reciverList = Optional.ofNullable(configStr).map(t -> Arrays.asList(t.split(",")))
|
||||||
|
.orElse(Collections.EMPTY_LIST);
|
||||||
|
|
||||||
|
key = key.replace(ALARM_RECIVER, "").trim() + "{ALARM}";
|
||||||
|
|
||||||
|
SendPolicy sendPolicy = new SendPolicy(key, reciverList);
|
||||||
|
|
||||||
|
return sendPolicy;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
package com.eactive.eai.custom.alarm;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.util.ApplicationContextProvider;
|
||||||
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
import com.eactive.eai.custom.alarm.event.AlarmEvent;
|
||||||
|
import com.eactive.eai.custom.alarm.key.AlarmKey;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.AlarmPolicy;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.SendPolicy;
|
||||||
|
import com.eactive.eai.custom.alarm.ums.UmsService;
|
||||||
|
import com.eactive.eai.custom.alarm.ums.payload.ObpMonitoringUmsTemplate;
|
||||||
|
import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AlarmStateManager {
|
||||||
|
|
||||||
|
List<AlarmEvent> registerAlarmList = new ArrayList<AlarmEvent>();
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
|
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
|
|
||||||
|
private static AlarmStateManager alarmStateManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
AlarmService alarmService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
UmsService usmService;
|
||||||
|
|
||||||
|
public static AlarmStateManager getAlarmStateManager() {
|
||||||
|
if (alarmStateManager == null) {
|
||||||
|
alarmStateManager = ApplicationContextProvider.getContext().getBean(AlarmStateManager.class);
|
||||||
|
}
|
||||||
|
return alarmStateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlarmStateManager() {
|
||||||
|
|
||||||
|
this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
|
||||||
|
Thread t = new Thread(r);
|
||||||
|
t.setName("AlarmStateManager-worker");
|
||||||
|
t.setDaemon(false);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
|
scheduler.scheduleWithFixedDelay(() -> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// === 여기에 지속 실행할 로직 ===
|
||||||
|
fireAlarm();
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// 반드시 예외 잡기 (안 잡으면 스케줄 자체가 죽음)
|
||||||
|
logger.error("fireAlarm fail", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 0, 5, TimeUnit.SECONDS); // 최초 0초, 이후 5초 간격
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEvnet(AlarmEvent alaramEvent) {
|
||||||
|
|
||||||
|
Optional<AlarmEvent> existEvent = registerAlarmList.stream().filter(e -> e.equals(alaramEvent)).findFirst();
|
||||||
|
|
||||||
|
if (existEvent.isPresent()) {
|
||||||
|
AlarmEvent event = existEvent.get();
|
||||||
|
event.onOcurr();
|
||||||
|
} else {
|
||||||
|
registerAlarmList.add(alaramEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fireAlarm() {
|
||||||
|
|
||||||
|
Map<AlarmKey, AlarmPolicy> alarmPolicyMap = alarmService.getAlarmPolicy();
|
||||||
|
|
||||||
|
Map<AlarmKey, SendPolicy> sendPolicyMap = alarmService.getSendPolicy();
|
||||||
|
|
||||||
|
Iterator<AlarmEvent> iterator = registerAlarmList.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
AlarmEvent event = iterator.next();
|
||||||
|
AlarmPolicy alarmPolicy = alarmPolicyMap.get(event.getKey());
|
||||||
|
|
||||||
|
if (alarmPolicy != null && alarmPolicy.isAlarmTriggered(event)) {
|
||||||
|
// 알람 발송 로직
|
||||||
|
SendPolicy sendPolicy = sendPolicyMap.get(event.getKey());
|
||||||
|
if (alarmService.isAlarmEnabled()) {
|
||||||
|
send(sendPolicy, event);
|
||||||
|
} else {
|
||||||
|
logger.info("Alarm is disabled, event = {}, policy = {}", event, sendPolicy);
|
||||||
|
}
|
||||||
|
// 리스트에서 안전하게 제거
|
||||||
|
iterator.remove();
|
||||||
|
}else { //트리거 조건이 안되더라도, 이벤트발생한지 오래 되었으면 제거하여 OOM 예방.
|
||||||
|
|
||||||
|
|
||||||
|
long firstOcurredAt = event.getCondition().getOcurredAt();
|
||||||
|
|
||||||
|
long diffInMs = System.currentTimeMillis() - firstOcurredAt;
|
||||||
|
|
||||||
|
if ( diffInMs >= TimeUnit.MINUTES.toMillis(60) ) { //1시간 지난거면 삭제
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void send(SendPolicy sendPolicy, AlarmEvent event) {
|
||||||
|
|
||||||
|
UmsRequestPayload payload = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
List<String> cellPhoneList = sendPolicy.getCellPhoneList();
|
||||||
|
|
||||||
|
for (String cellPhone : cellPhoneList) {
|
||||||
|
|
||||||
|
payload = UmsRequestPayload.builder()
|
||||||
|
.content(ObpMonitoringUmsTemplate.builder().message(event.getMessage()).build())
|
||||||
|
.cellphone(cellPhone).build();
|
||||||
|
|
||||||
|
usmService.send(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(String.format("Alarm message delivery failed (UMS), payload=%s", payload), e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.condition;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class AlarmCondition {
|
||||||
|
final long ocurredAt = System.currentTimeMillis();
|
||||||
|
long lastOcurredAt; // 일단, 미사용
|
||||||
|
@Builder.Default
|
||||||
|
long count = 1;
|
||||||
|
|
||||||
|
public void onOcurr() {
|
||||||
|
this.lastOcurredAt = System.currentTimeMillis();
|
||||||
|
this.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.condition;
|
||||||
|
|
||||||
|
public enum AlarmLevel {
|
||||||
|
ERROR, WARN, FATAL
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.event;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import com.eactive.eai.custom.alarm.condition.AlarmCondition;
|
||||||
|
import com.eactive.eai.custom.alarm.key.AlarmKey;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.AlarmPolicy;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.CounterPolicy;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@ToString
|
||||||
|
public class AlarmEvent {
|
||||||
|
AlarmKey key;
|
||||||
|
AlarmCondition condition;
|
||||||
|
String message;
|
||||||
|
|
||||||
|
public void onOcurr() {
|
||||||
|
condition.onOcurr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof AlarmEvent)) return false;
|
||||||
|
|
||||||
|
AlarmEvent that = (AlarmEvent) o;
|
||||||
|
return Objects.equals(this.key, that.key)
|
||||||
|
&& Objects.equals(this.message, that.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(key, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.key;
|
||||||
|
|
||||||
|
|
||||||
|
public interface AlarmKey {
|
||||||
|
String code();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.key;
|
||||||
|
|
||||||
|
public final class CoreAlarmKey {
|
||||||
|
|
||||||
|
private CoreAlarmKey() { }
|
||||||
|
|
||||||
|
public static final AlarmKey CircuitBreaker = new DynamicAlarmKey("CircuitBreaker{ALARM}");
|
||||||
|
|
||||||
|
public static final AlarmKey Timeout = new DynamicAlarmKey("Timeout{ALARM}");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.key;
|
||||||
|
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
public final class DynamicAlarmKey implements AlarmKey {
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
public DynamicAlarmKey(String code) {
|
||||||
|
if (code == null || code.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("AlarmKey code must not be empty");
|
||||||
|
}
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String code() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof AlarmKey)) return false;
|
||||||
|
return code.equals(((AlarmKey) o).code());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return code.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.policy;
|
||||||
|
|
||||||
|
import com.eactive.eai.custom.alarm.event.AlarmEvent;
|
||||||
|
import com.eactive.eai.custom.alarm.key.AlarmKey;
|
||||||
|
|
||||||
|
public abstract class AlarmPolicy {
|
||||||
|
|
||||||
|
private AlarmKey alarmKey;
|
||||||
|
|
||||||
|
private int thresholdCount;
|
||||||
|
|
||||||
|
private long timeWindowMs;
|
||||||
|
|
||||||
|
protected AlarmPolicy(Builder<?> builder) {
|
||||||
|
this.alarmKey = builder.alarmKey;
|
||||||
|
this.thresholdCount = builder.thresholdCount;
|
||||||
|
this.timeWindowMs = builder.timeWindowMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlarmKey getAlarmKey() {
|
||||||
|
return alarmKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getThresholdCount() {
|
||||||
|
return thresholdCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimeWindowMs() {
|
||||||
|
return timeWindowMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isAlarmTriggered(AlarmEvent event);
|
||||||
|
|
||||||
|
|
||||||
|
public boolean hasElapsed(long baseTimeMs) {
|
||||||
|
|
||||||
|
return System.currentTimeMillis() - baseTimeMs >= timeWindowMs;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasExceededLimit(long count) {
|
||||||
|
return count >= thresholdCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class Builder<T extends Builder<T>> {
|
||||||
|
|
||||||
|
private AlarmKey alarmKey;
|
||||||
|
private int thresholdCount;
|
||||||
|
private long timeWindowMs;
|
||||||
|
|
||||||
|
public T alarmKey(AlarmKey alarmKey) {
|
||||||
|
this.alarmKey = alarmKey;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T thresholdCount(int thresholdCount) {
|
||||||
|
this.thresholdCount = thresholdCount;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T timeWindowMs(long timeWindowMs) {
|
||||||
|
this.timeWindowMs = timeWindowMs;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T self();
|
||||||
|
|
||||||
|
abstract AlarmPolicy build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.policy;
|
||||||
|
|
||||||
|
public enum AlarmType {
|
||||||
|
COUNT, TIMER
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.policy;
|
||||||
|
|
||||||
|
import com.eactive.eai.custom.alarm.event.AlarmEvent;
|
||||||
|
|
||||||
|
public class CounterPolicy extends AlarmPolicy {
|
||||||
|
|
||||||
|
private CounterPolicy(Builder builder) {
|
||||||
|
super(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlarmTriggered(AlarmEvent event) {
|
||||||
|
|
||||||
|
if (!event.getKey().equals(getAlarmKey())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long count = event.getCondition().getCount();
|
||||||
|
return hasExceededLimit(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AlarmPolicy.Builder<Builder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Builder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CounterPolicy build() {
|
||||||
|
return new CounterPolicy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.policy;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.eactive.eai.custom.alarm.key.AlarmKey;
|
||||||
|
import com.eactive.eai.custom.alarm.key.DynamicAlarmKey;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
@ToString
|
||||||
|
@Getter
|
||||||
|
public class SendPolicy {
|
||||||
|
|
||||||
|
final AlarmKey alarmKey;
|
||||||
|
|
||||||
|
final List<String> cellPhoneList;
|
||||||
|
|
||||||
|
public SendPolicy(String alarmKey, List<String> cellPhoneList) {
|
||||||
|
this.alarmKey = new DynamicAlarmKey(alarmKey);
|
||||||
|
this.cellPhoneList = cellPhoneList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.policy;
|
||||||
|
|
||||||
|
import com.eactive.eai.custom.alarm.condition.AlarmCondition;
|
||||||
|
import com.eactive.eai.custom.alarm.event.AlarmEvent;
|
||||||
|
import com.eactive.eai.custom.alarm.policy.CounterPolicy.Builder;
|
||||||
|
|
||||||
|
public class TimerPolicy extends AlarmPolicy {
|
||||||
|
|
||||||
|
private TimerPolicy(Builder builder) {
|
||||||
|
super(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlarmTriggered(AlarmEvent event) {
|
||||||
|
|
||||||
|
if (event.getKey().equals(getAlarmKey())) {
|
||||||
|
|
||||||
|
AlarmCondition condition = event.getCondition();
|
||||||
|
|
||||||
|
long baseTimeMs = condition.getOcurredAt();
|
||||||
|
|
||||||
|
if (hasElapsed(baseTimeMs)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AlarmPolicy.Builder<Builder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Builder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimerPolicy build() {
|
||||||
|
return new TimerPolicy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class UmsCallResult {
|
||||||
|
private String umsMessageId;
|
||||||
|
private boolean isSuccess;
|
||||||
|
|
||||||
|
private String returnCode;
|
||||||
|
private String returnMessage;
|
||||||
|
private String returnPayload;
|
||||||
|
|
||||||
|
private Throwable throwable;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums;
|
||||||
|
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UmsSendManager {
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
|
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
|
|
||||||
|
Queue<UmsRequestPayload> queue = new ConcurrentLinkedQueue<UmsRequestPayload>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
UmsService umsService;
|
||||||
|
|
||||||
|
public UmsSendManager() {
|
||||||
|
this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
|
||||||
|
Thread t = new Thread(r);
|
||||||
|
t.setName("AlarmStateManager-worker");
|
||||||
|
t.setDaemon(false);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
|
scheduler.scheduleWithFixedDelay(() -> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// === 여기에 지속 실행할 로직 ===
|
||||||
|
sendMessage();
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// 반드시 예외 잡기 (안 잡으면 스케줄 자체가 죽음)
|
||||||
|
logger.error("fireAlarm fail", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 0, 5, TimeUnit.SECONDS); // 최초 0초, 이후 5초 간격
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendMessage() throws Exception {
|
||||||
|
UmsRequestPayload payload;
|
||||||
|
while ((payload = queue.poll()) != null) {
|
||||||
|
umsService.send(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enqueue(UmsRequestPayload payload) {
|
||||||
|
queue.offer(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||||
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
|
import org.apache.hc.client5.http.entity.EntityBuilder;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||||
|
import org.apache.hc.core5.http.ContentType;
|
||||||
|
import org.apache.hc.core5.http.ProtocolException;
|
||||||
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
|
import org.apache.hc.core5.util.Timeout;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.property.PropManager;
|
||||||
|
import com.eactive.eai.common.util.Jsons;
|
||||||
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;
|
||||||
|
import com.eactive.eai.custom.alarm.ums.payload.ValidationUtil;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UmsService {
|
||||||
|
|
||||||
|
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
|
|
||||||
|
private final static String UMS_GROUP_PROP_NAME = "UMS";
|
||||||
|
private final static String UMS_PROP_HOST = "host";
|
||||||
|
private final static String UMS_PROP_URL = "url";
|
||||||
|
private final static String UMS_PROP_API_KEY = "apiKey";
|
||||||
|
private final static String UMS_URL = "http://172.31.35.144:9021";
|
||||||
|
private final static String API_KEY = "7cca6d58-e4f7-474d-9edd-525806bc99ff";
|
||||||
|
private final static String SEND_URL = "/ums/openapi/send";
|
||||||
|
private final static String CONTENT_TYPE = "application/json; charset=utf-8";
|
||||||
|
private final static String AUTHORIZATION_FMT = "Bearer %s";
|
||||||
|
|
||||||
|
public Future<UmsCallResult> send(UmsRequestPayload payload) throws Exception {
|
||||||
|
|
||||||
|
if (payload.getContent() == null) {
|
||||||
|
throw new IllegalArgumentException("content is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ValidationUtil.validateOrThrow(payload);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.debug(String.format("UMS Request payload validation failed - %s", payload));
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return call(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CloseableHttpClient createHttpClient() {
|
||||||
|
return HttpClients.createDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Future<UmsCallResult> call(UmsRequestPayload requestPayload) throws Exception {
|
||||||
|
|
||||||
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
|
String json = Jsons.GSON.toJson(requestPayload);
|
||||||
|
|
||||||
|
String host = PropManager.getInstance().getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_HOST, UMS_URL);
|
||||||
|
String url = PropManager.getInstance().getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_URL, SEND_URL);
|
||||||
|
String apiKey = PropManager.getInstance().getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_API_KEY, API_KEY);
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost(host + url);
|
||||||
|
httpPost.setHeader("Content-Type", CONTENT_TYPE);
|
||||||
|
httpPost.setHeader("Authorization", String.format(AUTHORIZATION_FMT, apiKey));
|
||||||
|
httpPost.setEntity(EntityBuilder.create().setText(json).setContentType(ContentType.APPLICATION_JSON).build());
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
try {
|
||||||
|
logger.debug("Header - {}", httpPost.getHeader("Content-Type"));
|
||||||
|
logger.debug("Header - {}", httpPost.getHeader("Authorization"));
|
||||||
|
logger.debug("Request Body : {}",
|
||||||
|
StreamUtils.copyToString(httpPost.getEntity().getContent(), Charset.defaultCharset()));
|
||||||
|
} catch (ProtocolException | IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
httpPost.setConfig(RequestConfig.custom().setConnectTimeout(Timeout.ofSeconds(3))
|
||||||
|
.setResponseTimeout(Timeout.ofSeconds(3)).build());
|
||||||
|
Future<UmsCallResult> future;
|
||||||
|
try (CloseableHttpClient httpClient = createHttpClient()) {
|
||||||
|
future = executor.submit(() -> {
|
||||||
|
return httpClient.execute(httpPost, res -> {
|
||||||
|
try {
|
||||||
|
UmsCallResult result;
|
||||||
|
String body = EntityUtils.toString(res.getEntity());
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Response - {}", body);
|
||||||
|
}
|
||||||
|
result = Jsons.GSON.fromJson(body, UmsCallResult.class);
|
||||||
|
result.setUmsMessageId(requestPayload.getMessageIdentityNo());
|
||||||
|
result.setSuccess(true);
|
||||||
|
return result;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
logger.error("UMS Call error(JSON Syntax)", e);
|
||||||
|
return UmsCallResult.builder().umsMessageId(requestPayload.getMessageIdentityNo())
|
||||||
|
.isSuccess(false).throwable(e).build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("UMS Call error", e);
|
||||||
|
return UmsCallResult.builder().umsMessageId(requestPayload.getMessageIdentityNo())
|
||||||
|
.isSuccess(false).throwable(e).build();
|
||||||
|
} finally {
|
||||||
|
logger.debug("Response status - {}", res.getCode());
|
||||||
|
|
||||||
|
if (res.getCode() != 200) {
|
||||||
|
Arrays.asList(res.getHeaders()).forEach(o -> {
|
||||||
|
logger.warn("[Header] {}: {}", o.getName(), o.getValue());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return future;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("UMS call exception", e);
|
||||||
|
throw new Exception("UMS call failed", e);
|
||||||
|
} finally {
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums.payload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GSON Serialize 용 Object
|
||||||
|
*/
|
||||||
|
public interface IUmsGsonObject {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums.payload;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class ObpMonitoringUmsTemplate implements IUmsGsonObject {
|
||||||
|
@SerializedName("MOTR_EVAL_CNTN")
|
||||||
|
private String message;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public enum UmsBizWorkCode {
|
||||||
|
MONITORING("B_ELFN_09510", "OBP 모니터링"),
|
||||||
|
VERIFY_PHONE("S55_ICT_0006", "API Portal 인증번호"),
|
||||||
|
;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String code;
|
||||||
|
@Getter
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
UmsBizWorkCode(String code, String displayName) {
|
||||||
|
this.code = code;
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums.payload;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
import org.hibernate.validator.constraints.NotEmpty;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
public class UmsRequestPayload {
|
||||||
|
// MSG_IDNT_NO string 메시지식별번호 50 O "발송 구분을 위한 거래 번호 (GUID 권고)
|
||||||
|
//GUID로 입력이 어려울시
|
||||||
|
//어플리케이션코드(3자리)+난수 로 유니크한 ID로 채번 권고"
|
||||||
|
@Length(min = 1, max = 50)
|
||||||
|
@NotEmpty
|
||||||
|
@SerializedName("MSG_IDNT_NO")
|
||||||
|
@Builder.Default
|
||||||
|
private String messageIdentityNo = String.format("APM-%s",DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()));
|
||||||
|
|
||||||
|
// MSG_BZWK_CD string 메시지업무코드 30 O UMS에 등록된 메시지업무코드(AS-IS 템플릿ID)
|
||||||
|
@NotEmpty
|
||||||
|
@Length(min = 1, max = 30)
|
||||||
|
@SerializedName("MSG_BZWK_CD")
|
||||||
|
@Builder.Default
|
||||||
|
private String msgBizWorkCode = UmsBizWorkCode.MONITORING.getCode();
|
||||||
|
|
||||||
|
// 메시지업무파라미터내용 / 4000 / JSONObject
|
||||||
|
// MSG_BZWK_PARAM_CTNT object 메시지업무파라미터내용 4000 메시지업무코드의 템플릿에서 사용하는 변수와 변수값
|
||||||
|
@NotNull
|
||||||
|
@SerializedName("MSG_BZWK_PARAM_CTNT")
|
||||||
|
private IUmsGsonObject content;
|
||||||
|
|
||||||
|
// 발송예약일시 / 14 / 실 발송 일자(yyyyMMddHHmmss)
|
||||||
|
// SND_RESR_DTTM string 발송예약일시 14 20240418111500 O 실 발송 일자(현재시간)
|
||||||
|
@Pattern(regexp = "^[0-9]{14}$")
|
||||||
|
@NotEmpty
|
||||||
|
@SerializedName("SND_RESR_DTTM")
|
||||||
|
@Builder.Default
|
||||||
|
private String sendReservationDatetime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
|
||||||
|
|
||||||
|
// 휴대전화번호 / 44 / 휴대폰번호(평문, 암호화 둘다가능)
|
||||||
|
// CPNO string 휴대전화번호 44 "암호화 또는 평문 (safedb not rrno)
|
||||||
|
//문자일 시 암호문
|
||||||
|
//숫자일 시 전화번호
|
||||||
|
//고객번호 또는 휴대전화번호 필수"
|
||||||
|
@NotEmpty
|
||||||
|
@Pattern(regexp = "^[0-9]{10,11}$")
|
||||||
|
@SerializedName("CPNO")
|
||||||
|
private String cellphone;
|
||||||
|
|
||||||
|
// 발송부점코드 / 4 /
|
||||||
|
// SND_BRCD string 발송부점코드 4 O 0333
|
||||||
|
@NotEmpty
|
||||||
|
@SerializedName("SND_BRCD")
|
||||||
|
@Builder.Default
|
||||||
|
private String sendBranchCode = "0990";
|
||||||
|
|
||||||
|
// 발송직원번호 / 7 / ECEB057(텔러번호?)
|
||||||
|
// SND_EMPNO string 발송직원번호 7 O ? 넣긴해야함
|
||||||
|
@NotEmpty
|
||||||
|
@SerializedName("SND_EMPNO")
|
||||||
|
@Builder.Default
|
||||||
|
private String sendEmployeeNo = "ECEB057";
|
||||||
|
|
||||||
|
// SRVC_ID string 서비스ID 11 요청단 측 서비스ID
|
||||||
|
@NotEmpty
|
||||||
|
@SerializedName("SRVC_ID")
|
||||||
|
@Builder.Default
|
||||||
|
private String serviceId = "eAPIM";
|
||||||
|
|
||||||
|
// MSG_SND_CHNL_CD string 메시지발송채널코드 2
|
||||||
|
@SerializedName("MSG_SND_CHNL_CD")
|
||||||
|
@NotNull
|
||||||
|
@Builder.Default
|
||||||
|
private ChannelCode msgSndChnlCd = ChannelCode.KM;
|
||||||
|
|
||||||
|
// VALDTN_RSLT_CD string 검증결과코드 2 00으로 고정
|
||||||
|
@SerializedName("VALDTN_RSLT_CD")
|
||||||
|
@NotEmpty
|
||||||
|
@Builder.Default
|
||||||
|
private String validationResultCode = "00";
|
||||||
|
|
||||||
|
public enum ChannelCode {
|
||||||
|
SM, // SMS
|
||||||
|
LM, // LMS
|
||||||
|
MM, // MMS
|
||||||
|
KM, // 카카오-알림톡
|
||||||
|
FM, // 카카오-친구톡
|
||||||
|
SR, // RCS-SMS
|
||||||
|
LR, // RCS-LMS
|
||||||
|
MR, // RCS-MMS
|
||||||
|
TR, // RCS-TEMPLATE
|
||||||
|
IR, // RCS-IMAGE Template
|
||||||
|
PM // Push
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums.payload;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.validation.ConstraintViolation;
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
|
import javax.validation.Validation;
|
||||||
|
import javax.validation.Validator;
|
||||||
|
import javax.validation.ValidatorFactory;
|
||||||
|
|
||||||
|
import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;
|
||||||
|
|
||||||
|
public class ValidationUtil {
|
||||||
|
private static final ValidatorFactory factory;
|
||||||
|
private static final Validator validator;
|
||||||
|
|
||||||
|
static {
|
||||||
|
factory = Validation.byDefaultProvider()
|
||||||
|
.configure()
|
||||||
|
.messageInterpolator(new ParameterMessageInterpolator())
|
||||||
|
.buildValidatorFactory();
|
||||||
|
|
||||||
|
validator = factory.getValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ValidationUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> Set<ConstraintViolation<T>> validate(T target) {
|
||||||
|
return validator.validate(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void validateOrThrow(T target) {
|
||||||
|
Set<ConstraintViolation<T>> violations = validate(target);
|
||||||
|
if (!violations.isEmpty()) {
|
||||||
|
String message = violations.stream()
|
||||||
|
.map(v -> v.getPropertyPath() + " : " + v.getMessage())
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
throw new ConstraintViolationException("Validation failed: " + message, violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> String getViolationMessage(T target) {
|
||||||
|
Set<ConstraintViolation<T>> violations = validate(target);
|
||||||
|
if (violations.isEmpty()) return null;
|
||||||
|
return violations.stream()
|
||||||
|
.map(v -> v.getPropertyPath() + " : " + v.getMessage())
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.eactive.eai.custom.alarm.ums.payload;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class VerifyPhoneUmsTemplate implements IUmsGsonObject {
|
||||||
|
@SerializedName("ATHN_NO")
|
||||||
|
private String authNumber;
|
||||||
|
}
|
||||||
@@ -42,6 +42,11 @@ import com.eactive.eai.common.worker.ResponseMap;
|
|||||||
import com.eactive.eai.control.HttpSender;
|
import com.eactive.eai.control.HttpSender;
|
||||||
import com.eactive.eai.control.LogSender;
|
import com.eactive.eai.control.LogSender;
|
||||||
import com.eactive.eai.control.Transform;
|
import com.eactive.eai.control.Transform;
|
||||||
|
import com.eactive.eai.custom.alarm.AlarmStateManager;
|
||||||
|
import com.eactive.eai.custom.alarm.condition.AlarmCondition;
|
||||||
|
import com.eactive.eai.custom.alarm.event.AlarmEvent;
|
||||||
|
import com.eactive.eai.custom.alarm.key.AlarmKey;
|
||||||
|
import com.eactive.eai.custom.alarm.key.CoreAlarmKey;
|
||||||
import com.eactive.eai.env.ElinkConfig;
|
import com.eactive.eai.env.ElinkConfig;
|
||||||
import com.eactive.eai.inbound.processor.Processor;
|
import com.eactive.eai.inbound.processor.Processor;
|
||||||
import com.ext.eai.common.stdmessage.STDMessageKeys;
|
import com.ext.eai.common.stdmessage.STDMessageKeys;
|
||||||
@@ -96,20 +101,24 @@ public class RESTProcess extends HTTPProcess {
|
|||||||
String circuitBreakerUseYn = PropManager.getInstance().getProperty("CircuitBreaker", "useYn");
|
String circuitBreakerUseYn = PropManager.getInstance().getProperty("CircuitBreaker", "useYn");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if("Y".equals(circuitBreakerUseYn)){
|
if (true) {
|
||||||
String apiId = reqEaiMsg.getEAISvcCd();
|
String apiId = reqEaiMsg.getEAISvcCd();
|
||||||
CircuitBreaker circuitBreaker = CircuitBreakerManager.getInstance().getCircuitBreaker(apiId);
|
CircuitBreaker circuitBreaker = CircuitBreakerManager.getInstance().getCircuitBreaker(apiId);
|
||||||
|
|
||||||
// ObjectMapper 인스턴스 생성
|
// ObjectMapper 인스턴스 생성
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
// 서킷 브레이커의 메트릭 정보와 상태 정보를 직접 Node로 변환
|
// 서킷 브레이커의 메트릭 정보와 상태 정보를 직접 Node로 변환
|
||||||
ObjectNode combinedNode = objectMapper.createObjectNode();
|
ObjectNode combinedNode = objectMapper.createObjectNode();
|
||||||
combinedNode.put("state", circuitBreaker.getState().toString());
|
combinedNode.put("state", circuitBreaker.getState().toString());
|
||||||
combinedNode.set("metrics", objectMapper.valueToTree(circuitBreaker.getMetrics()));
|
combinedNode.set("metrics", objectMapper.valueToTree(circuitBreaker.getMetrics()));
|
||||||
|
|
||||||
|
logger.info("CircuitBreaker state " + combinedNode.toString());
|
||||||
|
this.resObject = circuitBreaker.executeCallable(() -> HttpSender
|
||||||
|
.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger.info("CircuitBreaker state "+combinedNode.toString());
|
|
||||||
this.resObject = circuitBreaker.executeCallable(() -> HttpSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp));
|
|
||||||
}else{
|
}else{
|
||||||
this.resObject = HttpSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp);
|
this.resObject = HttpSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user