diff --git a/.env.example b/.env.example index 6288c88..07ddf89 100644 --- a/.env.example +++ b/.env.example @@ -28,6 +28,11 @@ export BACKOFFICE_ADMIN_USER="admin" export BACKOFFICE_ADMIN_PASSWORD="admin" export BACKOFFICE_ORDS_BASE_URL="https://yh0olybn5pqce4n-d8aukro81636mon0.adb.ap-seoul-1.oraclecloudapps.com/ords" export BACKOFFICE_ORDS_TIMEOUT_SECONDS="10" +# ORDS metadata 생성/수정 전용 계정. 비워두면 BACKOFFICE_DB_* 연결을 사용하므로 +# ADMIN으로 실행 중이면 Handler 생성은 막히고 소스 보기만 사용합니다. +export BACKOFFICE_ORDS_DB_URL="${BACKOFFICE_DB_URL}" +export BACKOFFICE_ORDS_DB_USERNAME="CB_ORDS" +export BACKOFFICE_ORDS_DB_PASSWORD="" # --- (2c) OpenAI 호환 AI 호출 (MCP-style Reasoning 탭) --- export BACKOFFICE_AI_ENABLED="false" diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java b/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java index 903b61b..9c05799 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java @@ -6,8 +6,13 @@ import com.cloudhandson.vpdbackoffice.domain.ords.OrdsObjectHandlerResult; import com.cloudhandson.vpdbackoffice.domain.protectedobject.ProtectedColumn; import com.cloudhandson.vpdbackoffice.domain.protectedobject.ProtectedObject; import com.cloudhandson.vpdbackoffice.mapper.OrdsMetadataMapper; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import jakarta.annotation.PreDestroy; import java.util.List; import java.util.Locale; +import javax.sql.DataSource; +import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,16 +22,38 @@ public class OrdsMetadataService { private final OrdsMetadataMapper mapper; private final JdbcTemplate jdbcTemplate; + private final JdbcTemplate ordsMetadataJdbcTemplate; + private final HikariDataSource ordsMetadataDataSource; private final ProtectedObjectService protectedObjectService; public OrdsMetadataService( OrdsMetadataMapper mapper, JdbcTemplate jdbcTemplate, - ProtectedObjectService protectedObjectService + ProtectedObjectService protectedObjectService, + DataSource dataSource, + @Value("${backoffice.ords.metadata-db.url:}") String ordsMetadataUrl, + @Value("${backoffice.ords.metadata-db.username:}") String ordsMetadataUsername, + @Value("${backoffice.ords.metadata-db.password:}") String ordsMetadataPassword ) { this.mapper = mapper; this.jdbcTemplate = jdbcTemplate; this.protectedObjectService = protectedObjectService; + if (hasText(ordsMetadataUrl) && hasText(ordsMetadataUsername)) { + HikariConfig config = new HikariConfig(); + config.setPoolName("vpd-ords-metadata-pool"); + config.setJdbcUrl(ordsMetadataUrl.trim()); + config.setUsername(ordsMetadataUsername.trim()); + config.setPassword(ordsMetadataPassword == null ? "" : ordsMetadataPassword); + config.setDriverClassName("oracle.jdbc.OracleDriver"); + config.setMaximumPoolSize(2); + config.setMinimumIdle(0); + config.setConnectionTimeout(10000); + this.ordsMetadataDataSource = new HikariDataSource(config); + this.ordsMetadataJdbcTemplate = new JdbcTemplate(this.ordsMetadataDataSource); + } else { + this.ordsMetadataDataSource = null; + this.ordsMetadataJdbcTemplate = new JdbcTemplate(dataSource); + } } public List findHandlers() { @@ -108,7 +135,7 @@ public class OrdsMetadataService { requireIdentifier(object.objectName(), "objectName"); columns.forEach(column -> requireIdentifier(column, "column")); - String currentUser = jdbcTemplate.queryForObject("SELECT USER FROM dual", String.class); + String currentUser = ordsMetadataJdbcTemplate.queryForObject("SELECT USER FROM dual", String.class); if (currentUser == null || !currentUser.equalsIgnoreCase("CB_ORDS")) { throw new AppException("ORDS 조회 Handler 생성은 ORDS parsing schema(CB_ORDS)로 DB에 연결했을 때만 가능합니다. 현재 연결 사용자: " + currentUser + ". 현재 연결에서는 소스 보기를 눌러 기본 PL/SQL을 확인한 뒤 ORDS Handler에 적용하세요."); @@ -120,7 +147,7 @@ public class OrdsMetadataService { String ordsPath = "cb-ords/" + basePath + template; String source = objectQueryHandlerSource(objectId); - jdbcTemplate.update(""" + ordsMetadataJdbcTemplate.update(""" BEGIN ORDS.DEFINE_MODULE( p_module_name => ?, @@ -156,7 +183,7 @@ public class OrdsMetadataService { p_method => 'POST', p_name => 'limit', p_bind_variable_name => 'row_limit', - p_source_type => 'QUERY', + p_source_type => 'URI', p_param_type => 'INT', p_access_method => 'IN' ); @@ -228,4 +255,15 @@ public class OrdsMetadataService { throw new AppException("ORDS Handler 생성에 사용할 수 없는 " + label + " 식별자입니다: " + value); } } + + private boolean hasText(String value) { + return value != null && !value.isBlank(); + } + + @PreDestroy + public void closeOrdsMetadataDataSource() { + if (ordsMetadataDataSource != null) { + ordsMetadataDataSource.close(); + } + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ca94781..45462e0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -33,6 +33,10 @@ backoffice: ords: base-url: ${BACKOFFICE_ORDS_BASE_URL:https://yh0olybn5pqce4n-d8aukro81636mon0.adb.ap-seoul-1.oraclecloudapps.com/ords} timeout: ${BACKOFFICE_ORDS_TIMEOUT_SECONDS:10}s + metadata-db: + url: ${BACKOFFICE_ORDS_DB_URL:} + username: ${BACKOFFICE_ORDS_DB_USERNAME:} + password: ${BACKOFFICE_ORDS_DB_PASSWORD:} ai: enabled: ${BACKOFFICE_AI_ENABLED:false} base-url: ${BACKOFFICE_AI_BASE_URL:}