buckets; @Value("${common.service.sla.db}") private String SL"> buckets; @Value("${common.service.sla.db}") private String SL"> buckets; @Value("${common.service.sla.db}") private String SL">
public class ServiceFactory implements InitializingBean {
	public static Map<String, AdmSvcDply> jwtMap;
  private static Map<String, AdmSvcDply> basicMap;
	private static Map<String, AdmSvcDply> apiKeyMap;
	private static Map<String, AdmSvcDply> mtlsMap;
	private static Map<String, Set<String>> apiAutMap;
	private static Map<String, Sla> slaMap;
	private static Map<String, LocalBucket> bucketMap;
	private static LocalDateTime lastModifiedDate = null;
	private static Map<String, Map<String,String>> athnMap;
	private static Map<String, Pattern> ipAlwIpMap;
	private static Map<String, Pattern> ipBlkIpMap;

	@Autowired
	private PortalService portalService;

	@Autowired
	private AdmSvcService admSvcService;
	private final String BASIC = "Basic";
	private final String API_KEY = "ApiKey";
	private final String JWT = "JWT";
	private final String MTLS = "MTLS";

	@Autowired(required = false)
    private ProxyManager<String> buckets;

    @Value("${common.service.sla.db}")
    private String SLA_DB;

    private final String LOCAL = "LOCAL";
    private final String REDIS = "REDIS";
    private final String MONGODB = "MONGODB";

    @Scheduled(fixedDelayString = "${common.service.schedule.dbSync}", timeUnit = TimeUnit.SECONDS)
	public void synchronizeDB() {
		List<AdmSvcDply>  dbSvcList = null;

		// 마지막 동기화 시점 시간을 비교하여 데이터 동기화 처리
		LocalDateTime nowTime = LocalDateTime.now();
		if (lastModifiedDate == null) {
			dbSvcList = admSvcService.getAdmSvcList("DPLY");
		} else {
			dbSvcList = admSvcService.getAdmSvcList(lastModifiedDate);
		}

		if(dbSvcList != null && dbSvcList.size() > 0) {
			// System 정보를 ENTITY MAP에 현행화
			for (AdmSvcDply admSvc : dbSvcList) {
				if("DPLY".equals(admSvc.getDplyType())){
					if (BASIC.equals(admSvc.getAthnType())) insertBasicMap(admSvc);
					else if(JWT.equals(admSvc.getAthnType())) insertJwtMap(admSvc);
					else if(API_KEY.equals(admSvc.getAthnType())) insertApiKeyMap(admSvc);
					else if(MTLS.equals(admSvc.getAthnType())) insertMTLSMap(admSvc);

					insertApiAutMap(admSvc);
					insertBucketMap(admSvc);
					insertIpAcesAutMap(admSvc);
					
					log.info("ServiceFactory.synchronizeDB - Load : " + admSvc.toString());
				}else{
					String svcId = admSvc.getSvcId();
					if(athnMap.containsKey(svcId)){
						if (admSvc.getAthnType().equals(BASIC)) {
							basicMap.remove(athnMap.get(svcId).get(BASIC));
						}
						else if(admSvc.getAthnType().equals(JWT)){
							jwtMap.remove(athnMap.get(svcId).get(JWT));
						}
						else if(admSvc.getAthnType().equals(API_KEY)) {
							apiKeyMap.remove(athnMap.get(svcId).get(API_KEY));
						}else if(admSvc.getAthnType().equals(MTLS)) {
							mtlsMap.remove(athnMap.get(svcId).get(MTLS));
						}
					}

					athnMap.remove(svcId);
					apiAutMap.remove(svcId);
					if(slaMap.containsKey(svcId)){
						slaMap.remove(svcId);
						if(SLA_DB.equals(REDIS)){
							buckets.removeProxy(svcId);
						}
					}
					if(bucketMap.containsKey(svcId)){
						bucketMap.remove(svcId);
					}
					if(ipAlwIpMap.containsKey(svcId)){
						ipAlwIpMap.remove(svcId);
					}
					if(ipBlkIpMap.containsKey(svcId)){
						ipBlkIpMap.remove(svcId);
					}
					log.info("ServiceFactory.synchronizeDB - Remove : " + admSvc.toString());
				}
				
//				// 마지막 동기화 시간 현행화
//				if (lastModifiedDate == null || (admSvc.getDplyDt() != null && admSvc.getDplyDt().isAfter(lastModifiedDate))) {
//					lastModifiedDate = nowTime;
//				}
			}

			// 마지막 동기화 시간 현행화
			AdmSvcDply lastSvc = dbSvcList.stream().max((o1, o2) -> o1.getDplyDt().compareTo(o2.getDplyDt())).get();
			lastModifiedDate = lastSvc.getDplyDt();

		}
	}

@Override
	public void afterPropertiesSet() throws InternalException {
		log.info("ServiceFactory.afterPropertiesSet - Start");
		
		basicMap = new ConcurrentHashMap<String, AdmSvcDply>();
		jwtMap = new ConcurrentHashMap<String, AdmSvcDply>();
		apiKeyMap = new ConcurrentHashMap<String, AdmSvcDply>();
		mtlsMap = new ConcurrentHashMap<String, AdmSvcDply>();
		apiAutMap = new ConcurrentHashMap<String,  Set<String>>();
		athnMap = new ConcurrentHashMap<String, Map<String,String>>();
		slaMap = new ConcurrentHashMap<String, Sla>();
		bucketMap = new ConcurrentHashMap<String, LocalBucket>();
		ipAlwIpMap = new ConcurrentHashMap<String, Pattern>();
		ipBlkIpMap = new ConcurrentHashMap<String, Pattern>();

		List<AdmSvcDply> portalServiceList = portalService.getService();
		for(AdmSvcDply portalSvc:portalServiceList){
			if("DPLY".equals(portalSvc.getDplyType())){
				if (BASIC.equals(portalSvc.getAthnType())) insertBasicMap(portalSvc);
				else if(JWT.equals(portalSvc.getAthnType())) insertJwtMap(portalSvc);
				else if(API_KEY.equals(portalSvc.getAthnType())) insertApiKeyMap(portalSvc);
				else if(MTLS.equals(portalSvc.getAthnType())) insertMTLSMap(portalSvc);

				insertApiAutMap(portalSvc);
				insertBucketMap(portalSvc);
				insertIpAcesAutMap(portalSvc);
				if(portalSvc.getSvcStDt()==null){
					portalSvc.setSvcStDt(LocalDateTime.MIN);
				}
				if(portalSvc.getSvcEndDt()==null){
					portalSvc.setSvcEndDt(LocalDateTime.MAX);
				}
				
				log.info("Portal Service synchronization : " + portalSvc.toString());
			}
		}

		synchronizeDB();

		log.info("ServiceFactory.afterPropertiesSet - End");
	}

	
}
public static AdmSvcDply getBasic(String key) {	return basicMap.get(key); }

public static AdmSvcDply getJwt(String key) { return jwtMap.get(key); }

public static AdmSvcDply getApiKey(String key) { return apiKeyMap.get(key); }

public static AdmSvcDply getMTLS(String key) { return mtlsMap.get(key); }

public static Set<String> getApiAut(String key) { return apiAutMap.get(key); }

public static Sla getSla(String key) { return slaMap.get(key); }

public static Bucket getBucket(String key) { return bucketMap.get(key); }

public static Pattern getIpAlwRegEx(String key) { return ipAlwIpMap.get(key); }

public static Pattern getIpBlkRegEx(String key) { return ipBlkIpMap.get(key); }

	private void insertApiAutMap(AdmSvcDply admSvc) {
		String svcId = admSvc.getSvcId();
		Set<String> apiAutSet = new HashSet<>();
		for(String admApi : admSvc.getApiAut()){
			apiAutSet.add(admApi);
		}
		apiAutMap.put(svcId, apiAutSet);
	}

	private void insertJwtMap(AdmSvcDply admSvc) {
//		jwtMap = new ConcurrentHashMap<String, AdmSvcDply>();
		Jwt jwt = admSvc.getAthn().getJwt();
		String issAndAud = jwt.getIss().concat(".").concat(jwt.getAud());
		
		removeExistedAthnData(admSvc,issAndAud);
		jwtMap.put(issAndAud, admSvc);
		athnMap.put(admSvc.getSvcId(), new HashMap<String, String>() {{put(admSvc.getAthnType(), issAndAud);}});
	}
	
	private void insertBasicMap(AdmSvcDply admSvc) {
		String basicId = admSvc.getAthn().getBasic().getId();
		String basicPw = admSvc.getAthn().getBasic().getPw();
		String originalInput = basicId+":"+basicPw;
		String encodedString = Base64.getEncoder().encodeToString(originalInput.getBytes()).replace("=","");
		// admSvc.setLongSvcStDt(admSvc.getSvcStDt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
		// admSvc.setLongSvcEndDt(admSvc.getSvcEndDt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());

		removeExistedAthnData(admSvc,encodedString);
		basicMap.put(encodedString, admSvc);
		athnMap.put(admSvc.getSvcId(), new HashMap<String,String>(){{put(admSvc.getAthnType(),encodedString);}});
		
	}

	private void insertMTLSMap(AdmSvcDply admSvc) {
		String commNm = admSvc.getAthn().getMtls().getCn();
//		String[] splitCN = commNm.split("=");

//		String inputKey = (splitCN.length > 1)? splitCN[1] :  commNm;
		removeExistedAthnData(admSvc, commNm);

		mtlsMap.put(commNm, admSvc);
		athnMap.put(admSvc.getSvcId(), new HashMap<String, String>(){{put(admSvc.getAthnType(), commNm);}});
	}

	private void insertApiKeyMap(AdmSvcDply admSvc) {
		String apiKey = admSvc.getAthn().getApiKey().getKey();

		if(apiKey != null) {
			// admSvc.setLongSvcStDt(admSvc.getSvcStDt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
			// admSvc.setLongSvcEndDt(admSvc.getSvcEndDt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());

			removeExistedAthnData(admSvc,apiKey);
			apiKeyMap.put(apiKey, admSvc);
			athnMap.put(admSvc.getSvcId(), new HashMap<String,String>(){{put(admSvc.getAthnType(),apiKey);}});
		}
	}

	private void insertIpAcesAutMap(AdmSvcDply admSvc) {
		String svcId = admSvc.getSvcId();
		if(admSvc.getIpAcesAut()!=null){
			Pattern alwIpRegEx = convertRegExToIp(admSvc.getIpAcesAut().getAlwdIp());
			Pattern blckIpRegEx = convertRegExToIp(admSvc.getIpAcesAut().getBlckIp());

			ipAlwIpMap.put(svcId, alwIpRegEx);
			ipBlkIpMap.put(svcId, blckIpRegEx);
		}
	}

	private Pattern convertRegExToIp(List<String> ipList) {
		List<Pattern> regExList = new ArrayList<>();

		for(String ip : ipList) {
			String[] ipSplit = ip.split("\\.");
			StringBuilder regEx = new StringBuilder("^");
			for(int i = 0; i<ipSplit.length; i++) {
				String ipPart = ipSplit[i].trim().replace("[", "").replace("]", "");
				if("*".equals(ipPart)) {
					regEx.append("([1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])");
				} else if(ipSplit[i].contains("~")) {
					//범위 정규식 변환 처리
					String[] ipPartSplit = ipPart.split("~");
					int start = Integer.min(Integer.parseInt(ipPartSplit[0]), Integer.parseInt(ipPartSplit[1]));
					int end = Integer.max(Integer.parseInt(ipPartSplit[0]), Integer.parseInt(ipPartSplit[1]));

					int sQuot = Math.floorDiv(start,10);
					int sRemain = Math.floorMod(start,10);

					int eQuot = Math.floorDiv(end,10);
					int eRemain = Math.floorMod(end,10);
					regEx.append("(");
					if(sQuot == eQuot) {
						if(sQuot != 0) regEx.append(sQuot);
						regEx.append("[").append(sRemain).append("-").append(eRemain).append("]");
					} else {

						if(sQuot != 0) regEx.append(sQuot);
						regEx.append("[").append(sRemain).append("-9]|");
						for(int num = sQuot+1; num<eQuot; num++) {
							regEx.append(num).append("[0-9]|");
						}
						regEx.append(eQuot).append("[0-").append(eRemain).append("]");
					}
					regEx.append(")");
				} else if(ipSplit[i].matches("^\\d*$")) {
					regEx.append("(").append(Integer.parseInt(ipSplit[i])).append(")");
				}

				if(i < ipSplit.length-1) regEx.append("\\.");
			}
			regEx.append("$");

			try {
				Pattern pattern = Pattern.compile(regEx.toString());
				regExList.add(pattern);
			} catch(PatternSyntaxException e) {
				log.info("RegEx Syntax Error");
			}
		}

		Pattern totalRegEx = null;
		StringBuilder totalregexStr = new StringBuilder();

		if(!regExList.isEmpty()) {

			for (Pattern patt : regExList) {
				totalregexStr.append(patt).append("|");
			}

			totalregexStr.delete(totalregexStr.lastIndexOf("|"), totalregexStr.lastIndexOf("|") + 1);
			totalRegEx = Pattern.compile(totalregexStr.toString());
			return totalRegEx;
		}

		return Pattern.compile("");
	}

	private void removeExistedAthnData(AdmSvcDply admSvc,String key) {
		String svcId = admSvc.getSvcId();
		if(athnMap.containsKey(svcId)){
			String apiKey = athnMap.get(svcId).get(API_KEY);
			String jwt = athnMap.get(svcId).get(JWT);
			String basic = athnMap.get(svcId).get(BASIC);
			if(BASIC.equals(admSvc.getAthnType())){
				if(StringUtils.hasText(apiKey)){
					apiKeyMap.remove(apiKey);
				}else if(StringUtils.hasText(jwt)){
					jwtMap.remove(jwt);
				}
				if(StringUtils.hasText(basic)){
					if(!key.equals(basic)){
						basicMap.remove(basic);
					}
				}
			}
			else if(API_KEY.equals(admSvc.getAthnType())){
				if(StringUtils.hasText(basic)){
					basicMap.remove(basic);
				} else if(StringUtils.hasText(jwt)){
					jwtMap.remove(jwt);
				}
				if(StringUtils.hasText(apiKey)){
					if(!key.equals(apiKey)){
						apiKeyMap.remove(apiKey);
					}
				}
			}
			else if(JWT.equals(admSvc.getAthnType())) {
				if(StringUtils.hasText(apiKey)){
					apiKeyMap.remove(apiKey);
				} else if(StringUtils.hasText(basic)) {
					basicMap.remove(basic);
				}
				if(StringUtils.hasText(jwt)){
					if(!key.equals(jwt)){
						jwtMap.remove(jwt);
					}
				}
			}

			athnMap.remove(svcId);
		}
	}

	private void insertBucketMap(AdmSvcDply admSvc) {
		Sla sla = admSvc.getSla();
		String svcId = admSvc.getSvcId();
		Sla lastSla = slaMap.get(svcId);
		if(sla!=null && !sla.isEmpty()){
			// sla 정책 변동 여부 확인 : 변동이 있으면 변경해서 적용, 변동 x -> skip
			if(sla.equals(lastSla)){
				return;
			}
			if(SLA_DB.equals(LOCAL)){
				List<Bandwidth> bandwidths = sla.extractBandwidth(1);
				BucketConfiguration bucketConfiguration = new BucketConfiguration(bandwidths);
				LocalBucket bucket = Bucket.builder().addLimit(Bandwidth.simple(1000000, Duration.ofSeconds(1))).build();
				bucket.replaceConfiguration(bucketConfiguration, TokensInheritanceStrategy.RESET);
				bucketMap.put(svcId, bucket);
			}
			slaMap.put(svcId, sla);
			log.info("ServiceFactory.insertBucketMap - Load bucket : " + sla.toString());
		}else{
			// sla 정책이 없어질 시 map 에서 제거
			if(lastSla!=null){
				slaMap.remove(svcId);
				if(SLA_DB.equals(REDIS)){
					buckets.removeProxy(svcId);
				}
				if(SLA_DB.equals(LOCAL)){
					bucketMap.remove(svcId);
				}
				log.info("ServiceFactory.insertBucketMap - remove bucket : " + lastSla.toString());
			}
		}
	}

	@ReadOperation
    public Map<String, Object> serviceFeatures() {
		Map<String, Object> serviceInfoMap = new HashMap<>();
		serviceInfoMap.put("jwtMap", jwtMap);
		serviceInfoMap.put("basicMap", basicMap);
		serviceInfoMap.put("apiKeyMap", apiKeyMap);
		serviceInfoMap.put("apiAutMap", apiAutMap);
		serviceInfoMap.put("slaMap", slaMap);
		serviceInfoMap.put("ipAlwIpMap", ipAlwIpMap);
		serviceInfoMap.put("ipBlkIpMap", ipBlkIpMap);
        return serviceInfoMap;
    }