├── buycycle ├── logs │ └── .gitkeep ├── stopBuycycle.bat ├── startBuycycle.bat ├── lib │ └── com4j-x86.dll └── config │ ├── bootstrap.yml │ ├── application.yaml │ └── logback.xml ├── frontend ├── public │ ├── favicon.ico │ └── index.html ├── babel.config.js ├── src │ ├── assets │ │ ├── buycycle.png │ │ └── buycycle.svg │ ├── plugins │ │ └── vuetify.js │ ├── components │ │ ├── EBest.vue │ │ ├── TestBox.vue │ │ ├── EBestResTable.vue │ │ ├── EBestTab.vue │ │ ├── Hello.vue │ │ └── EBestTable.vue │ ├── main.js │ └── App.vue ├── .gitignore ├── vue.config.js ├── README.md └── package.json ├── src ├── main │ ├── java │ │ └── name │ │ │ └── buycycle │ │ │ ├── vendor │ │ │ └── ebest │ │ │ │ ├── event │ │ │ │ ├── IXAType.java │ │ │ │ ├── xaobject │ │ │ │ │ ├── XAObjectException.java │ │ │ │ │ ├── vo │ │ │ │ │ │ └── XAObject.java │ │ │ │ │ └── XAObjectHelper.java │ │ │ │ ├── XARealResponseEvent.java │ │ │ │ ├── vo │ │ │ │ │ ├── req │ │ │ │ │ │ ├── RequestHeader.java │ │ │ │ │ │ ├── RequestBody.java │ │ │ │ │ │ └── Request.java │ │ │ │ │ └── res │ │ │ │ │ │ └── Response.java │ │ │ │ ├── com4j │ │ │ │ │ ├── ClassFactory.java │ │ │ │ │ ├── _IXARealEvents.java │ │ │ │ │ ├── _IXAQueryEvents.java │ │ │ │ │ ├── IXAReal.java │ │ │ │ │ └── IXAQuery.java │ │ │ │ ├── handler │ │ │ │ │ ├── XASessionEventHandler.java │ │ │ │ │ ├── XARealEventHandler.java │ │ │ │ │ └── XAQueryEventHandler.java │ │ │ │ ├── XAQueryRequest.java │ │ │ │ └── XARealSubscribe.java │ │ │ │ ├── exception │ │ │ │ ├── ConnectFailException.java │ │ │ │ └── RequestTimeOutException.java │ │ │ │ ├── manage │ │ │ │ ├── Manager.java │ │ │ │ ├── XAQueryManager.java │ │ │ │ ├── command │ │ │ │ │ ├── XARealSubscribeCommand.java │ │ │ │ │ └── BlockingCommand.java │ │ │ │ ├── AbstractManager.java │ │ │ │ ├── XARealSubscribeManager.java │ │ │ │ └── XASessionManager.java │ │ │ │ ├── message │ │ │ │ ├── MessageException.java │ │ │ │ ├── ResDataRepository.java │ │ │ │ ├── MessageHelper.java │ │ │ │ ├── ResFileData.java │ │ │ │ └── ResFileReader.java │ │ │ │ ├── session │ │ │ │ ├── com4j │ │ │ │ │ ├── ClassFactory.java │ │ │ │ │ ├── XA_MESSAGE_ID.java │ │ │ │ │ ├── XA_SERVER_TYPE.java │ │ │ │ │ ├── _IXASessionEvents.java │ │ │ │ │ └── IXASession.java │ │ │ │ └── XASession.java │ │ │ │ └── config │ │ │ │ └── vo │ │ │ │ ├── User.java │ │ │ │ └── Connect.java │ │ │ ├── service │ │ │ └── ebest │ │ │ │ ├── vo │ │ │ │ ├── TableHeaderItem.java │ │ │ │ └── ResDesc.java │ │ │ │ └── EBestDescription.java │ │ │ ├── configuration │ │ │ └── ebest │ │ │ │ ├── XASessionConfigure.java │ │ │ │ ├── vo │ │ │ │ └── EBestConfig.java │ │ │ │ ├── XARealWebSocketConfigure.java │ │ │ │ └── EBestInitialization.java │ │ │ ├── control │ │ │ ├── rvo │ │ │ │ ├── ResTable.java │ │ │ │ └── TableHeader.java │ │ │ ├── XASessionChecker.java │ │ │ ├── XARealWebSocketHandler.java │ │ │ └── EBestController.java │ │ │ └── BuyCycleApplication.java │ └── resources │ │ ├── bootstrap.yml │ │ ├── banner.txt │ │ └── application.yaml └── test │ └── java │ └── name │ └── buycycle │ └── BuycycleApplicationTests.java ├── .gitignore ├── LICENSE ├── .github └── workflows │ └── maven-publish.yml ├── README.md └── pom.xml /buycycle/logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /buycycle/stopBuycycle.bat: -------------------------------------------------------------------------------- 1 | curl -X POST http://localhost:7771/actuator/shutdown -------------------------------------------------------------------------------- /buycycle/startBuycycle.bat: -------------------------------------------------------------------------------- 1 | java -Djava.library.path=./lib -jar ./lib/buycycle-1.0.8.jar -------------------------------------------------------------------------------- /buycycle/lib/com4j-x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malchooni/buycycle/HEAD/buycycle/lib/com4j-x86.dll -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malchooni/buycycle/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/assets/buycycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malchooni/buycycle/HEAD/frontend/src/assets/buycycle.png -------------------------------------------------------------------------------- /frontend/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuetify from 'vuetify/lib/framework'; 3 | 4 | Vue.use(Vuetify); 5 | 6 | export default new Vuetify({ 7 | }); 8 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/IXAType.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event; 2 | 3 | /** 4 | * ixa interface 5 | * 6 | * @author : ijyoon 7 | * @date : 2021/03/24 8 | */ 9 | public interface IXAType { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/exception/ConnectFailException.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.exception; 2 | 3 | public class ConnectFailException extends Exception { 4 | 5 | public ConnectFailException() { 6 | super("해당서버에 연결할 수 없습니다."); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/components/EBest.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 17 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import vuetify from './plugins/vuetify'; 4 | 5 | Vue.config.productionTip = false 6 | Vue.prototype.$website = 'http://buycycle.name' 7 | 8 | new Vue({ 9 | vuetify, 10 | render: h => h(App) 11 | }).$mount('#app') 12 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/manage/Manager.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.manage; 2 | 3 | import name.buycycle.configuration.ebest.vo.EBestConfig; 4 | 5 | public interface Manager { 6 | 7 | void setEBestConfig(EBestConfig eBestConfig); 8 | 9 | void initialize(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/exception/RequestTimeOutException.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.exception; 2 | 3 | public class RequestTimeOutException extends Exception { 4 | 5 | public RequestTimeOutException(long timeOut) { 6 | super("요청 경과시간이 초과 되었습니다. timeOut = " + timeOut); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /buycycle/config/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: buycycle 4 | profiles: 5 | active: dev 6 | cloud: 7 | config: 8 | enabled: false 9 | uri: 10 | 11 | management: 12 | endpoints: 13 | web: 14 | exposure: 15 | include: '*' 16 | endpoint: 17 | shutdown: 18 | enabled: true 19 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: buycycle 4 | profiles: 5 | active: dev 6 | cloud: 7 | config: 8 | enabled: false 9 | uri: 10 | 11 | management: 12 | endpoints: 13 | web: 14 | exposure: 15 | include: '*' 16 | endpoint: 17 | shutdown: 18 | enabled: true 19 | -------------------------------------------------------------------------------- /src/test/java/name/buycycle/BuycycleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package name.buycycle; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | /** 7 | * 기동 테스트 8 | */ 9 | @SpringBootTest 10 | class BuycycleApplicationTests { 11 | 12 | @Test 13 | void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/xaobject/XAObjectException.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.xaobject; 2 | 3 | /** 4 | * xa object exception 5 | * 6 | * @author : ijyoon 7 | * @date : 2022/08/30 8 | */ 9 | public class XAObjectException extends Exception { 10 | 11 | public XAObjectException(String message) { 12 | super(message); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/message/MessageException.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.message; 2 | 3 | 4 | /** 5 | * EBest Message process Exception 6 | * 7 | * @author : ijyoon 8 | * @date : 2022/08/30 9 | */ 10 | public class MessageException extends Exception { 11 | 12 | public MessageException(String message) { 13 | super(message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/XARealResponseEvent.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event; 2 | 3 | import name.buycycle.vendor.ebest.event.vo.req.Request; 4 | import name.buycycle.vendor.ebest.event.vo.res.Response; 5 | 6 | import java.io.IOException; 7 | 8 | public interface XARealResponseEvent { 9 | 10 | void responseEvent(Request receiveRequest, Response response) throws IOException; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | "transpileDependencies": [ 5 | "vuetify" 6 | ], 7 | outputDir: path.resolve( 8 | __dirname, 9 | "../src/main/resources/static" 10 | ), 11 | devServer: { 12 | proxy: { 13 | "/data": { 14 | target: "http://localhost:7771", 15 | ws: true, 16 | chageOrgin: true 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | ______ _ 3 | | ___ \ | | 4 | | |_/ / _ _ _ _ ___ _ _ ___ | | ___ 5 | | ___ \| | | || | | | / __|| | | | / __|| | / _ \ 6 | | |_/ /| |_| || |_| || (__ | |_| || (__ | || __/ 7 | \____/ \__,_| \__, | \___| \__, | \___||_| \___| 8 | __/ | __/ | 9 | |___/ |___/ 10 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/session/com4j/ClassFactory.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.session.com4j; 2 | 3 | import com4j.COM4J; 4 | 5 | /** 6 | * Defines methods to create COM objects 7 | */ 8 | public abstract class ClassFactory { 9 | 10 | private ClassFactory() { 11 | } // instanciation is not allowed 12 | 13 | 14 | /** 15 | * XASession Class 16 | */ 17 | public static IXASession createXASession() { 18 | return COM4J.createInstance(IXASession.class, "{7FEF321C-6BFD-413C-AA80-541A275434A1}"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /buycycle/config/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | address: localhost 3 | port: 7771 4 | 5 | logging: 6 | config: ./config/logback.xml 7 | 8 | ebest: 9 | resRootPath: 'C:\\eBEST\\xingAPI\\Res' 10 | connect: 11 | szServerIP: 'hts.ebestsec.co.kr' 12 | nServerPort: 20001 13 | connectTimeOut: 5000 14 | requestReadTimeOut: 10000 15 | user: 16 | id: '' 17 | pw: '' 18 | cpwd: '' 19 | 20 | eureka: 21 | client: 22 | enabled: false 23 | registerWithEureka: true 24 | fetchRegistry: true 25 | serviceUrl: 26 | defaultZone: -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/vo/req/RequestHeader.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.vo.req; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * 요청 헤더 7 | * 8 | * @author : ijyoon 9 | * @date : 2021/03/24 10 | */ 11 | public class RequestHeader { 12 | 13 | private String uuid; 14 | 15 | public String getUuid() { 16 | if (uuid == null || uuid.length() < 1) { 17 | uuid = UUID.randomUUID().toString(); 18 | } 19 | return uuid; 20 | } 21 | 22 | public void setUuid(String uuid) { 23 | this.uuid = uuid; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | address: localhost 3 | port: 7771 4 | 5 | logging: 6 | config: ./buycycle/config/logback.xml 7 | 8 | ebest: 9 | resRootPath: 'C:\\eBEST\\xingAPI\\Res' 10 | connect: 11 | szServerIP: 'hts.ebestsec.co.kr' 12 | nServerPort: 20001 13 | connectTimeOut: 5000 14 | requestReadTimeOut: 10000 15 | user: 16 | id: '' 17 | pw: '' 18 | cpwd: '' 19 | 20 | eureka: 21 | client: 22 | enabled: false 23 | registerWithEureka: true 24 | fetchRegistry: true 25 | serviceUrl: 26 | defaultZone: -------------------------------------------------------------------------------- /src/main/java/name/buycycle/service/ebest/vo/TableHeaderItem.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.service.ebest.vo; 2 | 3 | /** 4 | * 테이블 목록 vo 5 | * 6 | * @author : ijyoon 7 | * @date : 2021/03/24 8 | */ 9 | public class TableHeaderItem { 10 | 11 | private String name; 12 | private String desc; 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | public String getDesc() { 23 | return desc; 24 | } 25 | 26 | public void setDesc(String desc) { 27 | this.desc = desc; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/session/com4j/XA_MESSAGE_ID.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.session.com4j; 2 | 3 | import com4j.ComEnum; 4 | 5 | /** 6 | * 7 | */ 8 | public enum XA_MESSAGE_ID implements ComEnum { 9 | /** 10 | *

11 | * The value of this constant is -1 12 | *

13 | */ 14 | XA_FAILED(-1), 15 | /** 16 | *

17 | * The value of this constant is 0 18 | *

19 | */ 20 | XA_SUCCESS(0), 21 | ; 22 | 23 | private final int value; 24 | 25 | XA_MESSAGE_ID(int value) { 26 | this.value = value; 27 | } 28 | 29 | public int comEnumValue() { 30 | return value; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/service/ebest/vo/ResDesc.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.service.ebest.vo; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | /** 7 | * res 상세 8 | */ 9 | public class ResDesc { 10 | 11 | private Map>> resDescMap; 12 | 13 | public ResDesc(Map>> resDescMap) { 14 | this.resDescMap = resDescMap; 15 | } 16 | 17 | public Map>> getResDescMap() { 18 | return resDescMap; 19 | } 20 | 21 | public void setResDescMap(Map>> resDescMap) { 22 | this.resDescMap = resDescMap; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | 35 | /buycycle/lib/buycycle-*.jar 36 | logs/*.log 37 | **/buycycle.pid 38 | **/static/** 39 | **/resources/application.yaml 40 | **/resources/bootstrap.yaml -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/com4j/ClassFactory.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.com4j; 2 | 3 | import com4j.*; 4 | 5 | /** 6 | * Defines methods to create COM objects 7 | */ 8 | public abstract class ClassFactory { 9 | 10 | private ClassFactory() { 11 | } // instanciation is not allowed 12 | 13 | 14 | /** 15 | * XAQuery Class 16 | */ 17 | public static IXAQuery createXAQuery() { 18 | return COM4J.createInstance(IXAQuery.class, "{781520A9-4C8C-433B-AA6E-EE9E94108639}"); 19 | } 20 | 21 | /** 22 | * XAReal Class 23 | */ 24 | public static IXAReal createXAReal() { 25 | return COM4J.createInstance(IXAReal.class, "{4D654021-F9D9-49F7-B2F9-6529A19746F7}"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/config/vo/User.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.config.vo; 2 | 3 | /** 4 | * ebest user value object 5 | * 6 | * @author : ijyoon 7 | * @date : 2021/03/24 8 | */ 9 | public class User { 10 | 11 | private String id; 12 | private String pw; 13 | private String cpwd; 14 | 15 | public String getId() { 16 | return id; 17 | } 18 | 19 | public void setId(String id) { 20 | this.id = id; 21 | } 22 | 23 | public String getPw() { 24 | return pw; 25 | } 26 | 27 | public void setPw(String pw) { 28 | this.pw = pw; 29 | } 30 | 31 | public String getCpwd() { 32 | return cpwd; 33 | } 34 | 35 | public void setCpwd(String cpwd) { 36 | this.cpwd = cpwd; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/session/com4j/XA_SERVER_TYPE.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.session.com4j; 2 | 3 | import com4j.ComEnum; 4 | 5 | /** 6 | * 7 | */ 8 | public enum XA_SERVER_TYPE implements ComEnum { 9 | /** 10 | *

11 | * The value of this constant is -1 12 | *

13 | */ 14 | XA_NOSELECTED_SERVER(-1), 15 | /** 16 | *

17 | * The value of this constant is 0 18 | *

19 | */ 20 | XA_REAL_SERVER(0), 21 | /** 22 | *

23 | * The value of this constant is 1 24 | *

25 | */ 26 | XA_SIMUL_SERVER(1), 27 | ; 28 | 29 | private final int value; 30 | 31 | XA_SERVER_TYPE(int value) { 32 | this.value = value; 33 | } 34 | 35 | public int comEnumValue() { 36 | return value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/xaobject/vo/XAObject.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.xaobject.vo; 2 | 3 | import com4j.EventCookie; 4 | import name.buycycle.vendor.ebest.event.IXAType; 5 | 6 | /** 7 | * xing 인터페이스 객체 8 | * 9 | * @author : ijyoon 10 | * @date : 2021/03/24 11 | */ 12 | public class XAObject { 13 | 14 | private IXAType ixaType; 15 | private EventCookie eventCookie; 16 | 17 | public T getIxaType() { 18 | return (T) ixaType; 19 | } 20 | 21 | public void setIxaType(IXAType ixaType) { 22 | this.ixaType = ixaType; 23 | } 24 | 25 | public EventCookie getEventCookie() { 26 | return eventCookie; 27 | } 28 | 29 | public void setEventCookie(EventCookie eventCookie) { 30 | this.eventCookie = eventCookie; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/configuration/ebest/XASessionConfigure.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.configuration.ebest; 2 | 3 | 4 | import name.buycycle.control.XASessionChecker; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9 | 10 | /** 11 | * ebest 서버 연결 확인 12 | */ 13 | @Configuration 14 | public class XASessionConfigure implements WebMvcConfigurer { 15 | 16 | @Autowired 17 | private XASessionChecker xaSessionChecker; 18 | 19 | @Override 20 | public void addInterceptors(InterceptorRegistry registry) { 21 | registry.addInterceptor(xaSessionChecker) 22 | .addPathPatterns("/ebest/realtime", "/ebest/queries"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/components/TestBox.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/vo/req/RequestBody.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.vo.req; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 요청 바디 7 | * 8 | * @author : ijyoon 9 | * @date : 2021/03/24 10 | */ 11 | public class RequestBody { 12 | 13 | private String trName; 14 | private boolean bNext = false; 15 | private Map query; 16 | 17 | public String getTrName() { 18 | return trName; 19 | } 20 | 21 | public void setTrName(String trName) { 22 | this.trName = trName; 23 | } 24 | 25 | public boolean isbNext() { 26 | return bNext; 27 | } 28 | 29 | public void setbNext(boolean bNext) { 30 | this.bNext = bNext; 31 | } 32 | 33 | public Map getQuery() { 34 | return query; 35 | } 36 | 37 | public void setQuery(Map query) { 38 | this.query = query; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 12 | 13 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/control/rvo/ResTable.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.control.rvo; 2 | 3 | import name.buycycle.service.ebest.vo.TableHeaderItem; 4 | 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | 8 | /** 9 | * RES 목록 응답 value object 10 | */ 11 | public class ResTable { 12 | 13 | private List headers; 14 | private List items; 15 | 16 | public ResTable() { 17 | this.headers = new LinkedList<>(); 18 | this.items = new LinkedList<>(); 19 | } 20 | 21 | public List getHeaders() { 22 | return headers; 23 | } 24 | 25 | public void setHeaders(List headers) { 26 | this.headers = headers; 27 | } 28 | 29 | public void setHeaders(TableHeader tableHeader) { 30 | this.headers.add(tableHeader); 31 | } 32 | 33 | public List getItems() { 34 | return items; 35 | } 36 | 37 | public void setItems(List items) { 38 | this.items = items; 39 | } 40 | 41 | public void setItems(TableHeaderItem item) { 42 | this.items.add(item); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/control/rvo/TableHeader.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.control.rvo; 2 | 3 | /** 4 | * table header data by vuetify v-data-table 5 | */ 6 | public class TableHeader { 7 | 8 | private String text; 9 | private String align = "start"; 10 | private boolean sortable = false; 11 | private String value; 12 | 13 | public TableHeader(String text, String value) { 14 | this.text = text; 15 | this.value = value; 16 | } 17 | 18 | public String getText() { 19 | return text; 20 | } 21 | 22 | public void setText(String text) { 23 | this.text = text; 24 | } 25 | 26 | public String getAlign() { 27 | return align; 28 | } 29 | 30 | public void setAlign(String align) { 31 | this.align = align; 32 | } 33 | 34 | public boolean isSortable() { 35 | return sortable; 36 | } 37 | 38 | public void setSortable(boolean sortable) { 39 | this.sortable = sortable; 40 | } 41 | 42 | public String getValue() { 43 | return value; 44 | } 45 | 46 | public void setValue(String value) { 47 | this.value = value; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ijyoon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/session/com4j/_IXASessionEvents.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.session.com4j; 2 | 3 | import com4j.DISPID; 4 | import com4j.IID; 5 | 6 | /** 7 | * _IXASessionEvents Interface 8 | */ 9 | @IID("{6D45238D-A5EB-4413-907A-9EA14D046FE5}") 10 | public abstract class _IXASessionEvents { 11 | // Methods: 12 | 13 | /** 14 | *

15 | * method OnLogIn 16 | *

17 | * 18 | * @param szCode Mandatory java.lang.String parameter. 19 | * @param szMsg Mandatory java.lang.String parameter. 20 | */ 21 | 22 | @DISPID(1) 23 | public void login( 24 | String szCode, 25 | String szMsg) { 26 | throw new UnsupportedOperationException(); 27 | } 28 | 29 | 30 | /** 31 | *

32 | * method OnLogOut 33 | *

34 | */ 35 | 36 | @DISPID(2) 37 | public void logout() { 38 | throw new UnsupportedOperationException(); 39 | } 40 | 41 | 42 | /** 43 | *

44 | * method OnDisConnect 45 | *

46 | */ 47 | 48 | @DISPID(3) 49 | public void disconnect() { 50 | throw new UnsupportedOperationException(); 51 | } 52 | 53 | // Properties: 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/com4j/_IXARealEvents.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.com4j; 2 | 3 | import com4j.DISPID; 4 | import com4j.IID; 5 | 6 | /** 7 | * _IXARealEvents Interface 8 | */ 9 | @IID("{16602768-2C96-4D93-984B-E36E7E35BFBE}") 10 | public abstract class _IXARealEvents { 11 | // Methods: 12 | 13 | /** 14 | *

15 | * method ReceiveRealData 16 | *

17 | * 18 | * @param szTrCode Mandatory java.lang.String parameter. 19 | */ 20 | 21 | @DISPID(1) 22 | public void receiveRealData( 23 | String szTrCode) { 24 | throw new UnsupportedOperationException(); 25 | } 26 | 27 | 28 | /** 29 | *

30 | * method RecieveLinkData 31 | *

32 | * 33 | * @param szLinkName Mandatory java.lang.String parameter. 34 | * @param szData Mandatory java.lang.String parameter. 35 | * @param szFiller Mandatory java.lang.String parameter. 36 | */ 37 | 38 | @DISPID(2) 39 | public void recieveLinkData( 40 | String szLinkName, 41 | String szData, 42 | String szFiller) { 43 | throw new UnsupportedOperationException(); 44 | } 45 | 46 | // Properties: 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/config/vo/Connect.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.config.vo; 2 | 3 | /** 4 | * ebest connet value object 5 | * 6 | * @author : ijyoon 7 | * @date : 2021/03/24 8 | */ 9 | public class Connect { 10 | 11 | private String szServerIP; 12 | private int nServerPort; 13 | private int connectTimeOut; 14 | private int requestReadTimeOut; 15 | 16 | public String getSzServerIP() { 17 | return szServerIP; 18 | } 19 | 20 | public void setSzServerIP(String szServerIP) { 21 | this.szServerIP = szServerIP; 22 | } 23 | 24 | public int getnServerPort() { 25 | return nServerPort; 26 | } 27 | 28 | public void setnServerPort(int nServerPort) { 29 | this.nServerPort = nServerPort; 30 | } 31 | 32 | public int getConnectTimeOut() { 33 | return connectTimeOut; 34 | } 35 | 36 | public void setConnectTimeOut(int connectTimeOut) { 37 | this.connectTimeOut = connectTimeOut; 38 | } 39 | 40 | public int getRequestReadTimeOut() { 41 | return requestReadTimeOut; 42 | } 43 | 44 | public void setRequestReadTimeOut(int requestReadTimeOut) { 45 | this.requestReadTimeOut = requestReadTimeOut; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/configuration/ebest/vo/EBestConfig.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.configuration.ebest.vo; 2 | 3 | import name.buycycle.vendor.ebest.config.vo.Connect; 4 | import name.buycycle.vendor.ebest.config.vo.User; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.boot.context.properties.ConstructorBinding; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | /** 10 | * ebest config value object 11 | */ 12 | @Configuration 13 | @ConfigurationProperties(prefix = "ebest") 14 | @ConstructorBinding 15 | public class EBestConfig { 16 | 17 | private String resRootPath; 18 | private Connect connect; 19 | private User user; 20 | 21 | public String getResRootPath() { 22 | return resRootPath; 23 | } 24 | 25 | public void setResRootPath(String resRootPath) { 26 | this.resRootPath = resRootPath; 27 | } 28 | 29 | public Connect getConnect() { 30 | return connect; 31 | } 32 | 33 | public void setConnect(Connect connect) { 34 | this.connect = connect; 35 | } 36 | 37 | public User getUser() { 38 | return user; 39 | } 40 | 41 | public void setUser(User user) { 42 | this.user = user; 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/name/buycycle/BuyCycleApplication.java: -------------------------------------------------------------------------------- 1 | package name.buycycle; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | import org.springframework.boot.context.ApplicationPidFileWriter; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | 10 | /** 11 | * welcome to buycycle https://buycycle.name 12 | * 13 | * @author : ijyoon 14 | * @date : 2021/03/24 15 | */ 16 | @EnableEurekaClient 17 | @SpringBootApplication 18 | public class BuyCycleApplication { 19 | 20 | private static Logger logger = LoggerFactory.getLogger(BuyCycleApplication.class.getName()); 21 | 22 | public static void main(String[] args) { 23 | SpringApplicationBuilder app = new SpringApplicationBuilder( 24 | name.buycycle.BuyCycleApplication.class); 25 | app.build().addListeners(new ApplicationPidFileWriter("./buycycle.pid")); 26 | app.run(args); 27 | if (logger.isInfoEnabled()) { 28 | logger.info("======================"); 29 | logger.info(" Buycycle started... "); 30 | logger.info("======================"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/configuration/ebest/XARealWebSocketConfigure.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.configuration.ebest; 2 | 3 | import name.buycycle.control.XARealWebSocketHandler; 4 | import name.buycycle.control.XASessionChecker; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.socket.config.annotation.EnableWebSocket; 8 | import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 9 | import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 10 | 11 | /** 12 | * 실시간 요청 응답 웹소켓 환경설정 13 | */ 14 | @Configuration 15 | @EnableWebSocket 16 | public class XARealWebSocketConfigure implements WebSocketConfigurer { 17 | 18 | @Autowired 19 | private XASessionChecker xaSessionChecker; 20 | 21 | @Autowired 22 | private XARealWebSocketHandler xaRealWebSocketHandler; 23 | 24 | @Override 25 | public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { 26 | webSocketHandlerRegistry 27 | .addHandler(xaRealWebSocketHandler, "/ebest/realtime") 28 | .addInterceptors(xaSessionChecker) 29 | .setAllowedOrigins("*"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "buycycle.name", 3 | "version": "1.0.8", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.21.1", 12 | "core-js": "^3.6.5", 13 | "vue": "^2.6.11", 14 | "vuetify": "^2.2.11" 15 | }, 16 | "devDependencies": { 17 | "@vue/cli-plugin-babel": "~4.5.0", 18 | "@vue/cli-plugin-eslint": "~4.5.0", 19 | "@vue/cli-service": "~4.5.0", 20 | "babel-eslint": "^10.1.0", 21 | "eslint": "^6.7.2", 22 | "eslint-plugin-vue": "^6.2.2", 23 | "sass": "^1.19.0", 24 | "sass-loader": "^8.0.0", 25 | "vue-cli-plugin-vuetify": "~2.0.8", 26 | "vue-template-compiler": "^2.6.11", 27 | "vuetify-loader": "^1.3.0" 28 | }, 29 | "eslintConfig": { 30 | "root": true, 31 | "env": { 32 | "node": true 33 | }, 34 | "extends": [ 35 | "plugin:vue/essential", 36 | "eslint:recommended" 37 | ], 38 | "parserOptions": { 39 | "parser": "babel-eslint" 40 | }, 41 | "rules": {} 42 | }, 43 | "browserslist": [ 44 | "> 1%", 45 | "last 2 versions", 46 | "not dead" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/manage/XAQueryManager.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.manage; 2 | 3 | import name.buycycle.configuration.ebest.vo.EBestConfig; 4 | import name.buycycle.vendor.ebest.event.XAQueryRequest; 5 | import name.buycycle.vendor.ebest.event.vo.req.Request; 6 | import name.buycycle.vendor.ebest.event.vo.res.Response; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | public class XAQueryManager implements Manager { 11 | 12 | private static final XAQueryManager instance = new XAQueryManager(); 13 | 14 | public static XAQueryManager getInstance() { 15 | return instance; 16 | } 17 | 18 | private EBestConfig eBestConfig; 19 | private XAQueryRequest xaQueryRequest; 20 | 21 | private XAQueryManager() { 22 | } 23 | 24 | @Override 25 | public void setEBestConfig(EBestConfig eBestConfig) { 26 | this.eBestConfig = eBestConfig; 27 | } 28 | 29 | @Override 30 | public void initialize() { 31 | if (eBestConfig == null) { 32 | throw new NullPointerException("EBestConfig is null."); 33 | } 34 | this.xaQueryRequest = new XAQueryRequest(this.eBestConfig); 35 | } 36 | 37 | public Response requestQuery(Request request) { 38 | return this.xaQueryRequest.requestQuery(request); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/vo/res/Response.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.vo.res; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * json 응답 10 | * 11 | * @author : ijyoon 12 | * @date : 2021/03/24 13 | */ 14 | public class Response { 15 | 16 | private Map header; 17 | private Map>> body; 18 | 19 | public Response() { 20 | this(null); 21 | } 22 | 23 | public Response(String uuid) { 24 | this.header = new LinkedHashMap<>(); 25 | this.body = new LinkedHashMap<>(); 26 | putHeader("uuid", uuid); 27 | } 28 | 29 | public Map getHeader() { 30 | return header; 31 | } 32 | 33 | public String getHeader(String key) { 34 | return header.get(key); 35 | } 36 | 37 | public Map>> getBody() { 38 | return body; 39 | } 40 | 41 | public void putHeader(String key, String value) { 42 | this.header.put(key, value); 43 | } 44 | 45 | public void putBody(String blockName, Map row) { 46 | List> rows = this.body.computeIfAbsent(blockName, k -> new LinkedList<>()); 47 | rows.add(row); 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /frontend/src/components/EBestResTable.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 40 | 41 | -------------------------------------------------------------------------------- /buycycle/config/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 11 | 12 | 13 | 14 | 15 | 17 | ${LOGS}/buycycle.log 18 | 20 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 21 | 22 | 23 | 25 | ${LOGS}/buycycle-%d{yyyy-MM-dd}.log 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yml: -------------------------------------------------------------------------------- 1 | 2 | # This workflow will build a Java project with Maven 3 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 4 | 5 | name: Java CI with Maven 6 | 7 | on: 8 | push: 9 | branches: [ release ] 10 | 11 | jobs: 12 | build: 13 | runs-on: windows-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: actions/setup-node@v2 17 | with: 18 | node-version: '14' 19 | - working-directory: D:/a/buycycle/buycycle/frontend 20 | run: npm install 21 | - working-directory: D:/a/buycycle/buycycle/frontend 22 | run: npm run build 23 | - name: Set up JDK 1.8 for x86 24 | uses: actions/setup-java@v1 25 | with: 26 | java-version: 1.8 27 | java-package: jdk 28 | architecture: x86 29 | - name: Build with Maven 30 | run: mvn -B package --file pom.xml 31 | - name: delete exclude file 32 | run: powershell Remove-Item -Path D:/a/buycycle/buycycle/buycycle/logs/.gitkeep -Force 33 | - name: zip win artifact 34 | run: | 35 | powershell Compress-Archive -Path D:/a/buycycle/buycycle/buycycle -DestinationPath D:/a/buycycle/buycycle/buycycle.zip 36 | - name: release 37 | uses: ncipollo/release-action@v1 38 | with: 39 | artifacts: D:/a/buycycle/buycycle/buycycle.zip 40 | token: ${{ secrets.TOKEN }} 41 | tag: "1.0.8" 42 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/handler/XASessionEventHandler.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.handler; 2 | 3 | import name.buycycle.vendor.ebest.event.vo.res.Response; 4 | import name.buycycle.vendor.ebest.session.com4j._IXASessionEvents; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.UUID; 9 | 10 | /** 11 | * xa session 로그인 이벤트 핸들러 12 | * 13 | * @author : ijyoon 14 | * @date : 2021/03/24 15 | */ 16 | public class XASessionEventHandler extends _IXASessionEvents { 17 | 18 | private final Logger logger = LoggerFactory.getLogger(XASessionEventHandler.class); 19 | private final Response response; 20 | 21 | public XASessionEventHandler() { 22 | this.response = new Response(UUID.randomUUID().toString()); 23 | } 24 | 25 | public Response getResponse() { 26 | return response; 27 | } 28 | 29 | @Override 30 | public void login(String szCode, String szMsg) { 31 | if (logger.isInfoEnabled()) { 32 | logger.info("szCode : {} , szMsg : {}", szCode, szMsg); 33 | } 34 | 35 | response.putHeader("szCode", szCode); 36 | response.putHeader("szMsg", szMsg); 37 | 38 | synchronized (this) { 39 | this.notifyAll(); 40 | } 41 | } 42 | 43 | @Override 44 | public void logout() { 45 | if (logger.isInfoEnabled()) { 46 | logger.info("logout event receive"); 47 | } 48 | } 49 | 50 | @Override 51 | public void disconnect() { 52 | if (logger.isInfoEnabled()) { 53 | logger.info("disconnect event receive"); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 이베스트투자증권의 OPEN API 지원에 따라 해당 프로젝트는 종료 됩니다. 2 | 3 | https://openapi.ebestsec.co.kr/intro 4 | 5 | 6 |

7 | 8 | 9 | 10 |

11 | 12 |

13 | 증권사 API를 RESTful로 요청,응답 변환 모듈

14 | 15 | 16 | 17 | 18 | 19 |

20 | 21 | ------------- 22 | 23 | 'Buycycle'은 증권사 API를 HTTP JSON으로 요청 및 응답 받을 수 있습니다. 24 | 요청 받은 Json 메시지를 증권사 API 양식에 맞게 변환해 주는 자바 기반의 오픈 소스 입니다. 25 | HTTP RESTful을 제공함으로써 사용자는 개발 언어에 국한되지 않습니다. 26 | 27 | 28 |
29 | 30 | 구성 31 | ------------- 32 | 33 |

34 | 35 | * backend : Spring Boot, Com4j 36 | RESTful 방식으로 특정 증권사의 API를 연동합니다. 37 | 사용자는 http 특정 포트로 JSON으로 메시지를 주고 받습니다. 38 |

39 | * frontend : Vue.js Vuetifyjs 40 | API 명세 및 간단한 테스트를 위해 구현 되었습니다. 41 | 42 |
43 | 44 | 사이트 45 | ------------- 46 | 47 | 해당 사이트를 통해 바이사이클의 정보를 제공합니다. 48 | 실행 및 예제를 확인할 수 있습니다. 49 | https://opensource.buycycle.name 50 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/manage/command/XARealSubscribeCommand.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.manage.command; 2 | 3 | import name.buycycle.configuration.ebest.vo.EBestConfig; 4 | import name.buycycle.vendor.ebest.event.XARealResponseEvent; 5 | import name.buycycle.vendor.ebest.event.vo.req.Request; 6 | 7 | /** 8 | * XARealSubscribeManager 제어를 위한 명령어 오브젝트 9 | */ 10 | public class XARealSubscribeCommand { 11 | 12 | private String command; 13 | private EBestConfig eBestConfig; 14 | private Request request; 15 | private XARealResponseEvent xaRealResponseEvent; 16 | 17 | public XARealSubscribeCommand(String command) { 18 | this.command = command; 19 | } 20 | 21 | public Request getRequest() { 22 | return request; 23 | } 24 | 25 | public XARealSubscribeCommand setRequest(Request request) { 26 | this.request = request; 27 | return this; 28 | } 29 | 30 | public XARealResponseEvent getXaRealResponseEvent() { 31 | return xaRealResponseEvent; 32 | } 33 | 34 | public XARealSubscribeCommand setXaRealResponseEvent(XARealResponseEvent xaRealResponseEvent) { 35 | this.xaRealResponseEvent = xaRealResponseEvent; 36 | return this; 37 | } 38 | 39 | public String getCommand() { 40 | return command; 41 | } 42 | 43 | public void setCommand(String command) { 44 | this.command = command; 45 | } 46 | 47 | public EBestConfig getEBestConfig() { 48 | return eBestConfig; 49 | } 50 | 51 | public XARealSubscribeCommand setEBestConfig(EBestConfig eBestConfig) { 52 | this.eBestConfig = eBestConfig; 53 | return this; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return this.command; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/vo/req/Request.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.vo.req; 2 | 3 | import com.google.common.base.Objects; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * json 요청 9 | * 10 | * @author : ijyoon 11 | * @date : 2021/03/24 12 | */ 13 | public class Request { 14 | 15 | private RequestHeader requestHeader; 16 | private RequestBody body; 17 | 18 | public RequestHeader getHeader() { 19 | return requestHeader; 20 | } 21 | 22 | public void setHeader(RequestHeader requestHeader) { 23 | this.requestHeader = requestHeader; 24 | } 25 | 26 | public RequestBody getBody() { 27 | return body; 28 | } 29 | 30 | public void setBody(RequestBody body) { 31 | this.body = body; 32 | } 33 | 34 | public String getFirstValue() { 35 | return this.body.getQuery().entrySet().iterator().next().getValue(); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | 41 | if (obj == null) { 42 | return false; 43 | } 44 | 45 | if (this.getClass() != obj.getClass()) { 46 | return false; 47 | } 48 | 49 | Request target = (Request) obj; 50 | String targetTrName = target.getBody().getTrName(); 51 | 52 | Map.Entry targetEntry = target.getBody().getQuery().entrySet().iterator() 53 | .next(); 54 | 55 | if (target.getBody().getQuery().size() != 1 || this.body.getQuery().size() != 1) { 56 | return false; 57 | } 58 | 59 | if (this.body.getTrName().equals(targetTrName) && getFirstValue().equals( 60 | targetEntry.getValue())) { 61 | return true; 62 | } 63 | 64 | return false; 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hashCode(this.body.getTrName(), getFirstValue()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/com4j/_IXAQueryEvents.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.com4j; 2 | 3 | import com4j.DISPID; 4 | import com4j.IID; 5 | 6 | /** 7 | * _IXAQueryEvents Interface 8 | */ 9 | @IID("{AAF89E20-1F84-4B1F-B6EE-617B6F2C9CD4}") 10 | public abstract class _IXAQueryEvents { 11 | // Methods: 12 | 13 | /** 14 | *

15 | * method ReceiveData 16 | *

17 | * 18 | * @param szTrCode Mandatory java.lang.String parameter. 19 | */ 20 | 21 | @DISPID(1) 22 | public void receiveData( 23 | String szTrCode) { 24 | throw new UnsupportedOperationException(); 25 | } 26 | 27 | 28 | /** 29 | *

30 | * method ReceiveMessage 31 | *

32 | * 33 | * @param bIsSystemError Mandatory java.lang.String parameter. 34 | * @param nMessageCode Mandatory java.lang.String parameter. 35 | * @param szMessage Mandatory java.lang.String parameter. 36 | */ 37 | 38 | @DISPID(2) 39 | public void receiveMessage( 40 | String bIsSystemError, 41 | String nMessageCode, 42 | String szMessage) { 43 | throw new UnsupportedOperationException(); 44 | } 45 | 46 | 47 | /** 48 | *

49 | * method ReceiveChartRealData 50 | *

51 | * 52 | * @param szTrCode Mandatory java.lang.String parameter. 53 | */ 54 | 55 | @DISPID(3) 56 | public void receiveChartRealData( 57 | String szTrCode) { 58 | throw new UnsupportedOperationException(); 59 | } 60 | 61 | 62 | /** 63 | *

64 | * method ReceiveSearchRealData 65 | *

66 | * 67 | * @param szTrCode Mandatory java.lang.String parameter. 68 | */ 69 | 70 | @DISPID(4) 71 | public void receiveSearchRealData( 72 | String szTrCode) { 73 | throw new UnsupportedOperationException(); 74 | } 75 | 76 | // Properties: 77 | } 78 | -------------------------------------------------------------------------------- /frontend/src/components/EBestTab.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 66 | 67 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/manage/command/BlockingCommand.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.manage.command; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | public class BlockingCommand { 7 | 8 | private static final Logger logger = LoggerFactory.getLogger(BlockingCommand.class); 9 | 10 | private Object command; 11 | private boolean empty = true; 12 | private long timeOut = 0; 13 | private String timeOutCommand; 14 | 15 | public BlockingCommand() { 16 | } 17 | 18 | public BlockingCommand(long timeOut) { 19 | this.timeOut = timeOut; 20 | } 21 | 22 | public void setTimeOut(long timeOut) { 23 | this.timeOut = timeOut; 24 | } 25 | 26 | public BlockingCommand setTimeOutCommand(String timeOutCommand) { 27 | this.timeOutCommand = timeOutCommand; 28 | return this; 29 | } 30 | 31 | public synchronized T take() { 32 | while (this.empty) { 33 | try { 34 | wait(this.timeOut); 35 | if (this.empty && this.timeOutCommand != null) { 36 | this.command = this.timeOutCommand; 37 | this.empty = false; 38 | } 39 | } catch (InterruptedException e) { 40 | if (logger.isErrorEnabled()) { 41 | logger.error(e.getMessage(), e); 42 | } 43 | Thread.currentThread().interrupt(); 44 | } 45 | } 46 | this.empty = true; 47 | notifyAll(); 48 | return (T) command; 49 | } 50 | 51 | public synchronized void put(Object command) { 52 | while (!this.empty) { 53 | try { 54 | wait(); 55 | } catch (InterruptedException e) { 56 | if (logger.isErrorEnabled()) { 57 | logger.error(e.getMessage(), e); 58 | } 59 | Thread.currentThread().interrupt(); 60 | } 61 | } 62 | this.empty = false; 63 | this.command = command; 64 | notifyAll(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/message/ResDataRepository.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.message; 2 | 3 | import java.util.Map; 4 | import java.util.TreeMap; 5 | 6 | /** 7 | * res 파일 정보 레파지토리 8 | * 9 | * @author : ijyoon 10 | * @date : 2021/03/24 11 | */ 12 | public class ResDataRepository { 13 | 14 | private Map resReal; 15 | private Map resQuery; 16 | 17 | public ResDataRepository() { 18 | this.resReal = new TreeMap<>(); 19 | this.resQuery = new TreeMap<>(); 20 | } 21 | 22 | /** 23 | * res 파일 정보 반환 24 | * 25 | * @param resName res 파일명 26 | * @return res 정보 객체 27 | */ 28 | public ResFileData getResFileData(String resName) { 29 | if (this.resQuery.containsKey(resName)) { 30 | return this.resQuery.get(resName); 31 | } else { 32 | return this.resReal.get(resName); 33 | } 34 | } 35 | 36 | /** 37 | * res file 정보 등록 38 | * 39 | * @param resName res 파일명 40 | * @param resFIleData res 정보 객체 41 | * @throws Exception 42 | */ 43 | public void putResFileData(String resName, ResFileData resFIleData) throws MessageException { 44 | switch (resFIleData.getResType()) { 45 | case ResFileData.QUERY: 46 | this.resQuery.put(resName, resFIleData); 47 | break; 48 | case ResFileData.REAL: 49 | this.resReal.put(resName, resFIleData); 50 | break; 51 | default: 52 | throw new MessageException("invalid res type"); 53 | } 54 | } 55 | 56 | /** 57 | * res map 반환 58 | * 59 | * @param type real or query 60 | * @return res map 61 | */ 62 | public Map getResMap(String type) { 63 | switch (type) { 64 | case ResFileData.QUERY: 65 | return this.resQuery; 66 | case ResFileData.REAL: 67 | return this.resReal; 68 | default: 69 | return null; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/handler/XARealEventHandler.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.handler; 2 | 3 | import name.buycycle.vendor.ebest.event.com4j._IXARealEvents; 4 | import name.buycycle.vendor.ebest.event.vo.res.Response; 5 | import name.buycycle.vendor.ebest.manage.XASessionManager; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * xa real 이벤트 핸들러 11 | * @author : ijyoon 12 | * @date : 2021/03/24 13 | */ 14 | public class XARealEventHandler extends _IXARealEvents { 15 | 16 | private final Logger logger = LoggerFactory.getLogger(XARealEventHandler.class); 17 | private Response response; 18 | 19 | private final Object monitor; 20 | private final String requestUUID; 21 | 22 | public XARealEventHandler(Object monitor, String uuid) { 23 | this.monitor = monitor; 24 | this.requestUUID = uuid; 25 | } 26 | 27 | public Response getResponse() { 28 | return response; 29 | } 30 | 31 | @Override 32 | public void receiveRealData(String szTrCode) { 33 | 34 | if(logger.isDebugEnabled()) 35 | logger.debug("RequestUUID : {}, szTrCode : {}", this.requestUUID, szTrCode); 36 | 37 | this.response = new Response(this.requestUUID); 38 | this.response.putHeader("szTrCode", szTrCode); 39 | 40 | XASessionManager.getInstance().touch(); 41 | 42 | synchronized (this.monitor){ 43 | this.monitor.notifyAll(); 44 | } 45 | } 46 | 47 | @Override 48 | public void recieveLinkData(String szLinkName, String szData, String szFiller) { 49 | 50 | if(logger.isDebugEnabled()) 51 | logger.debug("RequestUUID : {}, szLinkName : {}, szData : {}, szFiller : {}", this.requestUUID, szLinkName, szData, szFiller); 52 | 53 | this.response = new Response(this.requestUUID); 54 | this.response.putHeader("szLinkName", szLinkName); 55 | this.response.putHeader("szData", szData); 56 | this.response.putHeader("szFiller", szFiller); 57 | synchronized (this.monitor){ 58 | this.monitor.notifyAll(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 71 | 72 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/control/XASessionChecker.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.control; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import name.buycycle.vendor.ebest.event.vo.res.Response; 5 | import name.buycycle.vendor.ebest.manage.XASessionManager; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.http.server.ServerHttpRequest; 9 | import org.springframework.http.server.ServerHttpResponse; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.servlet.HandlerInterceptor; 12 | import org.springframework.web.socket.WebSocketHandler; 13 | import org.springframework.web.socket.server.HandshakeInterceptor; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.util.Map; 18 | 19 | /** 20 | * 이베스트 세션 확인 21 | * 22 | * @author : ijyoon 23 | * @date : 2021/03/24 24 | */ 25 | @Component 26 | public class XASessionChecker implements HandlerInterceptor, HandshakeInterceptor { 27 | 28 | private XASessionManager xaSessionManager = XASessionManager.getInstance(); 29 | 30 | @Override 31 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 32 | throws Exception { 33 | 34 | if (xaSessionManager.isSucceedLogin()) { 35 | return true; 36 | } 37 | 38 | Response xaConResponse = xaSessionManager.login(); 39 | if (xaSessionManager.isSucceedLogin()) { 40 | return true; 41 | } else { 42 | if (xaConResponse == null) { 43 | xaConResponse = new Response(null); 44 | xaConResponse.putHeader("buyCycleErrMsg", "login response is null."); 45 | } 46 | ObjectMapper objectMapper = new ObjectMapper(); 47 | response.setContentType("application/json;charset=utf-8"); 48 | response.getWriter().write(objectMapper.writeValueAsString(xaConResponse)); 49 | return false; 50 | } 51 | } 52 | 53 | @Override 54 | public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, 55 | ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, 56 | Map map) throws Exception { 57 | 58 | if (xaSessionManager.isSucceedLogin()) { 59 | return true; 60 | } 61 | 62 | xaSessionManager.login(); 63 | return xaSessionManager.isSucceedLogin(); 64 | } 65 | 66 | @Override 67 | public void afterHandshake(ServerHttpRequest serverHttpRequest, 68 | ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) { 69 | // implementation ignored 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/manage/AbstractManager.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.manage; 2 | 3 | import name.buycycle.configuration.ebest.vo.EBestConfig; 4 | import name.buycycle.vendor.ebest.manage.command.BlockingCommand; 5 | import org.slf4j.Logger; 6 | 7 | abstract class AbstractManager extends Thread implements Manager { 8 | 9 | private Logger logger; 10 | private boolean running = true; 11 | 12 | private final BlockingCommand request; 13 | private final BlockingCommand response; 14 | 15 | protected EBestConfig eBestConfig; 16 | 17 | protected AbstractManager(String threadName, Logger logger) { 18 | super(threadName); 19 | this.logger = logger; 20 | this.request = new BlockingCommand(); 21 | this.response = new BlockingCommand(); 22 | } 23 | 24 | protected AbstractManager setRequestTimeOut(long timeout) { 25 | this.request.setTimeOut(timeout); 26 | return this; 27 | } 28 | 29 | protected AbstractManager setRequestTimeOutCommand(String command) { 30 | this.request.setTimeOutCommand(command); 31 | return this; 32 | } 33 | 34 | protected AbstractManager setResponseTimeOut(long timeout) { 35 | this.response.setTimeOut(timeout); 36 | return this; 37 | } 38 | 39 | protected AbstractManager setResponseTimeOutCommand(String command) { 40 | this.response.setTimeOutCommand(command); 41 | return this; 42 | } 43 | 44 | protected void requestCommand(T command) { 45 | this.request.put(command); 46 | } 47 | 48 | protected V responseTake() { 49 | return this.response.take(); 50 | } 51 | 52 | protected void responseCommand(Object command) { 53 | this.response.put(command); 54 | } 55 | 56 | protected void setRunning(boolean running) { 57 | this.running = running; 58 | } 59 | 60 | /** 61 | * 설정 주입 62 | * 63 | * @param eBestConfig EBest 환경 설정 64 | */ 65 | public void setEBestConfig(EBestConfig eBestConfig) { 66 | this.eBestConfig = eBestConfig; 67 | } 68 | 69 | @Override 70 | public void run() { 71 | if (logger.isInfoEnabled()) { 72 | logger.info("{} started..", this.getName()); 73 | } 74 | 75 | initialize(); 76 | while (running) { 77 | try { 78 | T command = this.request.take(); 79 | this.request(command); 80 | } catch (Exception e) { 81 | if (logger.isErrorEnabled()) { 82 | logger.error(e.getMessage(), e); 83 | } 84 | } 85 | } 86 | 87 | if (logger.isInfoEnabled()) { 88 | logger.info("{} shutdown done..", this.getName()); 89 | } 90 | } 91 | 92 | abstract void request(T command); 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/handler/XAQueryEventHandler.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.handler; 2 | 3 | import name.buycycle.vendor.ebest.event.com4j._IXAQueryEvents; 4 | import name.buycycle.vendor.ebest.event.vo.res.Response; 5 | import name.buycycle.vendor.ebest.manage.XASessionManager; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * xa query 이벤트 핸들러 11 | * 12 | * @author : ijyoon 13 | * @date : 2021/03/24 14 | */ 15 | public class XAQueryEventHandler extends _IXAQueryEvents { 16 | 17 | private Logger logger = LoggerFactory.getLogger(XAQueryEventHandler.class); 18 | private Response response; 19 | 20 | private static final String SZ_TR_CODE = "szTrCode"; 21 | 22 | public XAQueryEventHandler(String uuid) { 23 | this.response = new Response(uuid); 24 | } 25 | 26 | public Response getResponse() { 27 | return response; 28 | } 29 | 30 | /** 31 | * 수신 데이터 32 | * 33 | * @param szTrCode Mandatory java.lang.String parameter. 34 | */ 35 | @Override 36 | public void receiveData(String szTrCode) { 37 | if (logger.isInfoEnabled()) { 38 | logger.info("receiveData szTrCode : {}", szTrCode); 39 | } 40 | 41 | this.response.putHeader(SZ_TR_CODE, szTrCode); 42 | XASessionManager.getInstance().touch(); 43 | synchronized (this) { 44 | this.notifyAll(); 45 | } 46 | } 47 | 48 | /** 49 | * 수신 메시지 50 | * 51 | * @param bIsSystemError Mandatory java.lang.String parameter. 52 | * @param nMessageCode Mandatory java.lang.String parameter. 53 | * @param szMessage Mandatory java.lang.String parameter. 54 | */ 55 | @Override 56 | public void receiveMessage(String bIsSystemError, String nMessageCode, String szMessage) { 57 | if (logger.isInfoEnabled()) { 58 | logger.info("receiveMessage bIsSystemError : {}, nMessageCode : {}, szMessage: {}", 59 | bIsSystemError, nMessageCode, szMessage); 60 | } 61 | 62 | this.response.putHeader("bIsSystemError", bIsSystemError); 63 | this.response.putHeader("nMessageCode", nMessageCode); 64 | this.response.putHeader("szMessage", szMessage); 65 | 66 | if (!bIsSystemError.equals("0")) { 67 | synchronized (this) { 68 | this.notifyAll(); 69 | } 70 | } 71 | } 72 | 73 | @Override 74 | public void receiveChartRealData(String szTrCode) { 75 | if (logger.isInfoEnabled()) { 76 | logger.info("receiveChartRealData szTrCode : {}", szTrCode); 77 | } 78 | 79 | this.response.putHeader(SZ_TR_CODE, szTrCode); 80 | synchronized (this) { 81 | this.notifyAll(); 82 | } 83 | } 84 | 85 | @Override 86 | public void receiveSearchRealData(String szTrCode) { 87 | if (logger.isInfoEnabled()) { 88 | logger.info("receiveSearchRealData szTrCode : {}", szTrCode); 89 | } 90 | 91 | this.response.putHeader(SZ_TR_CODE, szTrCode); 92 | synchronized (this) { 93 | this.notifyAll(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/service/ebest/EBestDescription.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.service.ebest; 2 | 3 | import name.buycycle.control.rvo.TableHeader; 4 | import name.buycycle.control.rvo.ResTable; 5 | import name.buycycle.service.ebest.vo.ResDesc; 6 | import name.buycycle.service.ebest.vo.TableHeaderItem; 7 | import name.buycycle.vendor.ebest.event.vo.req.Request; 8 | import name.buycycle.vendor.ebest.event.vo.req.RequestBody; 9 | import name.buycycle.vendor.ebest.event.vo.req.RequestHeader; 10 | import name.buycycle.vendor.ebest.message.MessageHelper; 11 | import name.buycycle.vendor.ebest.message.ResDataRepository; 12 | import name.buycycle.vendor.ebest.message.ResFileData; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.util.LinkedHashMap; 16 | import java.util.Map; 17 | import java.util.Set; 18 | 19 | /** 20 | * res 파일에 대한 정보 21 | */ 22 | @Component 23 | public class EBestDescription { 24 | 25 | private ResDataRepository resDataRepository = MessageHelper.getInstance().getResDataRepository(); 26 | 27 | /** 28 | * res 목록 29 | * 30 | * @param resDataType 31 | * @return 32 | */ 33 | public ResTable resList(String resDataType) { 34 | ResTable resTable = new ResTable(); 35 | 36 | TableHeader interfaceHeader = new TableHeader("interface", "name"); 37 | interfaceHeader.setAlign("center"); 38 | resTable.setHeaders(interfaceHeader); 39 | resTable.setHeaders(new TableHeader("description", "desc")); 40 | 41 | Map resFileDataMap = resDataRepository.getResMap(resDataType); 42 | Set keySet = resFileDataMap.keySet(); 43 | 44 | ResFileData resFileData; 45 | TableHeaderItem tableHeaderItem; 46 | for (String key : keySet) { 47 | resFileData = resFileDataMap.get(key); 48 | tableHeaderItem = new TableHeaderItem(); 49 | tableHeaderItem.setName(resFileData.getName()); 50 | tableHeaderItem.setDesc(resFileData.getDescription()); 51 | resTable.setItems(tableHeaderItem); 52 | } 53 | return resTable; 54 | } 55 | 56 | /** 57 | * description trName 58 | * 59 | * @param trName 60 | * @return 61 | */ 62 | public ResDesc resDesc(String trName) { 63 | ResFileData resFileData = resDataRepository.getResFileData(trName); 64 | return new ResDesc(resFileData.getDataMap()); 65 | } 66 | 67 | /** 68 | * 메시지 생성 69 | * 70 | * @param trName 71 | * @return 72 | */ 73 | public Request requestMessage(String trName) { 74 | Request request = new Request(); 75 | RequestHeader header = new RequestHeader(); 76 | request.setHeader(header); 77 | Map bodyMap = new LinkedHashMap<>(); 78 | 79 | ResFileData resFileData = resDataRepository.getResFileData(trName); 80 | if (resFileData == null) { 81 | bodyMap.put("message", trName + " res file not found"); 82 | } else { 83 | RequestBody body = new RequestBody(); 84 | request.setBody(body); 85 | body.setTrName(trName); 86 | resFileData.getRequestColumnList().forEach(value -> bodyMap.put(value, "")); 87 | body.setQuery(bodyMap); 88 | } 89 | return request; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /frontend/src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 75 | 76 | 108 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/configuration/ebest/EBestInitialization.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.configuration.ebest; 2 | 3 | import name.buycycle.configuration.ebest.vo.EBestConfig; 4 | import name.buycycle.vendor.ebest.manage.XAQueryManager; 5 | import name.buycycle.vendor.ebest.manage.XARealSubscribeManager; 6 | import name.buycycle.vendor.ebest.message.MessageHelper; 7 | import name.buycycle.vendor.ebest.manage.XASessionManager; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.annotation.PostConstruct; 14 | import javax.annotation.PreDestroy; 15 | 16 | /** 17 | * ebest 초기화 res file 읽기, 세션 종료 18 | */ 19 | @Component 20 | public class EBestInitialization { 21 | 22 | private final Logger logger = LoggerFactory.getLogger(EBestInitialization.class); 23 | 24 | @Autowired 25 | private EBestConfig eBestConfig; 26 | 27 | /** 28 | * res 파일을 메시지 맵으로 읽는다. 29 | * 30 | * @throws Exception 31 | */ 32 | @PostConstruct 33 | public void resFileRead() throws Exception { 34 | MessageHelper messageHelper = MessageHelper.getInstance(); 35 | messageHelper.setResRootPath(eBestConfig.getResRootPath()); 36 | messageHelper.initialize(); 37 | } 38 | 39 | /** 40 | * 연결 관리자 초기화 41 | */ 42 | @PostConstruct 43 | public void xaSessionManager() { 44 | XASessionManager xaSessionManager = XASessionManager.getInstance(); 45 | xaSessionManager.setEBestConfig(eBestConfig); 46 | xaSessionManager.start(); 47 | } 48 | 49 | @PostConstruct 50 | public void xaRealSubscribeManager() { 51 | XARealSubscribeManager xaRealSubscribeManager = XARealSubscribeManager.getInstance(); 52 | xaRealSubscribeManager.setEBestConfig(eBestConfig); 53 | xaRealSubscribeManager.start(); 54 | } 55 | 56 | @PostConstruct 57 | public void xaQueryManager() { 58 | XAQueryManager xaQueryManager = XAQueryManager.getInstance(); 59 | xaQueryManager.setEBestConfig(eBestConfig); 60 | xaQueryManager.initialize(); 61 | } 62 | 63 | /** 64 | * xa session 종료. 65 | */ 66 | @PreDestroy 67 | public void shutdown() { 68 | XARealSubscribeManager xaRealSubscribeManager = XARealSubscribeManager.getInstance(); 69 | xaRealSubscribeManager.shutdown(); 70 | try { 71 | xaRealSubscribeManager.join(); 72 | } catch (InterruptedException e) { 73 | if (logger.isErrorEnabled()) { 74 | logger.error(e.getMessage(), e); 75 | } 76 | Thread.currentThread().interrupt(); 77 | } 78 | 79 | XASessionManager xaSessionManager = XASessionManager.getInstance(); 80 | xaSessionManager.shutdown(); 81 | try { 82 | xaSessionManager.join(); 83 | } catch (InterruptedException e) { 84 | if (logger.isErrorEnabled()) { 85 | logger.error(e.getMessage(), e); 86 | } 87 | Thread.currentThread().interrupt(); 88 | } 89 | 90 | if (logger.isInfoEnabled()) { 91 | logger.info("======================"); 92 | logger.info(" Buycycle stopped... "); 93 | logger.info("======================"); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.1 9 | 10 | 11 | name.buycycle 12 | buycycle 13 | 1.0.8 14 | buycycle 15 | jar 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-websocket 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-actuator 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-hateoas 40 | 41 | 42 | 43 | org.springframework.cloud 44 | spring-cloud-starter-bootstrap 45 | 3.0.3 46 | 47 | 48 | 49 | org.springframework.cloud 50 | spring-cloud-starter-config 51 | 3.0.3 52 | 53 | 54 | 55 | org.springframework.cloud 56 | spring-cloud-starter-netflix-eureka-client 57 | 3.0.3 58 | 59 | 60 | 61 | org.jvnet.com4j 62 | com4j 63 | 2.1 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-starter-test 69 | test 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-maven-plugin 78 | 79 | ${project.basedir}/buycycle/lib 80 | 81 | 82 | 83 | 84 | build-info 85 | 86 | 87 | 88 | UTF-8 89 | UTF-8 90 | 1.8 91 | 1.8 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/message/MessageHelper.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.message; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.File; 7 | import java.util.Map; 8 | import java.util.regex.Pattern; 9 | 10 | /** 11 | * RES file to data map, util. 12 | */ 13 | public class MessageHelper { 14 | 15 | private Logger logger = LoggerFactory.getLogger(MessageHelper.class); 16 | private static MessageHelper messageHelper; 17 | 18 | private String resRootPath; 19 | private ResDataRepository resDataRepository; 20 | 21 | private MessageHelper() { 22 | this.resDataRepository = new ResDataRepository(); 23 | } 24 | 25 | public static MessageHelper getInstance() { 26 | if (messageHelper == null) { 27 | messageHelper = new MessageHelper(); 28 | } 29 | return messageHelper; 30 | } 31 | 32 | public void setResRootPath(String resRootPath) { 33 | this.resRootPath = resRootPath; 34 | } 35 | 36 | /** 37 | * 초기화 38 | * 39 | * @throws Exception 40 | */ 41 | public void initialize() throws Exception { 42 | 43 | if (this.resRootPath == null) { 44 | throw new MessageException("res root path is null."); 45 | } 46 | 47 | File resRoot = new File(this.resRootPath); 48 | if (!resRoot.isDirectory()) { 49 | if (logger.isErrorEnabled()) { 50 | logger.error("this path is not directory. [{}]", this.resRootPath); 51 | } 52 | return; 53 | } 54 | 55 | File[] files = resRoot.listFiles(file -> file.isFile() && 56 | !Pattern.compile("^([\\S]+(_[1-2]\\.(?i)(res))$)").matcher(file.getName()).matches()); 57 | 58 | if (files.length < 1) { 59 | return; 60 | } 61 | 62 | ResFileReader resFileReader = new ResFileReader(); 63 | int successCount = 0; 64 | for (File resFile : files) { 65 | try { 66 | ResFileData resFileData = resFileReader.load(resFile); 67 | this.resDataRepository.putResFileData(resFileData.getName(), resFileData); 68 | successCount++; 69 | 70 | if (logger.isDebugEnabled()) { 71 | logger.debug("[{}][{}][{}] file loaded..", resFileData.getName(), 72 | resFileData.getResType(), resFileData.getDescription()); 73 | } 74 | } catch (Exception e) { 75 | if (logger.isErrorEnabled()) { 76 | logger.error(e.getMessage(), e); 77 | } 78 | } 79 | } 80 | if (logger.isInfoEnabled()) { 81 | logger.info("{} res file loaded..", successCount); 82 | logger.info("MessageHelper initialization completed.."); 83 | } 84 | } 85 | 86 | public ResFileData getResFileData(String trName) { 87 | return this.resDataRepository.getResFileData(trName); 88 | } 89 | 90 | /** 91 | * res 레파지토리 반환 92 | * 93 | * @return 94 | */ 95 | public ResDataRepository getResDataRepository() { 96 | return this.resDataRepository; 97 | } 98 | 99 | /** 100 | * res file data 반환 101 | * 102 | * @param type REAL or QUERY 103 | * @param trName 104 | * @return 105 | */ 106 | public ResFileData getResFileData(String type, String trName) { 107 | Map resMap = this.resDataRepository.getResMap(type); 108 | return resMap.get(trName); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/xaobject/XAObjectHelper.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.xaobject; 2 | 3 | import java.io.File; 4 | import name.buycycle.vendor.ebest.event.com4j.ClassFactory; 5 | import name.buycycle.vendor.ebest.event.com4j.IXAQuery; 6 | import name.buycycle.vendor.ebest.event.com4j.IXAReal; 7 | import name.buycycle.vendor.ebest.event.xaobject.vo.XAObject; 8 | import name.buycycle.vendor.ebest.message.ResFileData; 9 | 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * xing api 인터페이스 객체 제어 15 | * 16 | * @author : ijyoon 17 | * @date : 2021/03/24 18 | */ 19 | public class XAObjectHelper { 20 | 21 | private XAObjectHelper() { 22 | throw new IllegalStateException("XAObjectHelper is Utility class"); 23 | } 24 | 25 | /** 26 | * 인터페이스 객체 생성 27 | * 28 | * @param resRootPath res 파일 루트 경로 29 | * @param resFileData res 파일 객체 30 | * @param eventInterface 이벤트 핸들러 클래스 31 | * @param receiver 인터페이스 객체 32 | * @param IXAQuery or IXAReal 33 | * @return 34 | * @throws Exception 35 | */ 36 | public static XAObject createXAObject(String resRootPath, ResFileData resFileData, 37 | Class eventInterface, T receiver) throws XAObjectException { 38 | 39 | String filePath = resRootPath + File.separator + resFileData.getName() + ".res"; 40 | XAObject xaObject = new XAObject(); 41 | 42 | switch (resFileData.getResType()) { 43 | case ResFileData.REAL: 44 | IXAReal ixaReal = ClassFactory.createXAReal(); 45 | ixaReal.loadFromResFile(filePath); 46 | 47 | xaObject.setEventCookie(ixaReal.advise(eventInterface, receiver)); 48 | xaObject.setIxaType(ixaReal); 49 | 50 | break; 51 | case ResFileData.QUERY: 52 | IXAQuery ixaQuery = ClassFactory.createXAQuery(); 53 | ixaQuery.loadFromResFile(filePath); 54 | 55 | xaObject.setEventCookie(ixaQuery.advise(eventInterface, receiver)); 56 | xaObject.setIxaType(ixaQuery); 57 | break; 58 | default: 59 | throw new XAObjectException("invalid res type."); 60 | } 61 | 62 | return xaObject; 63 | } 64 | 65 | /** 66 | * ixaQuery 객체로 맵에 있는 요청값 셋팅 67 | * 68 | * @param ixaQuery 인터페이스 객체 69 | * @param resFileData res 파일 객체 70 | * @param query 요청 값 71 | */ 72 | public static void readyForRequest(IXAQuery ixaQuery, ResFileData resFileData, 73 | Map query) { 74 | String szBlockName = resFileData.getRequestBlockName(); 75 | List requestColumnList = resFileData.getRequestColumnList(); 76 | 77 | String value; 78 | for (String requestColumn : requestColumnList) { 79 | value = query.get(requestColumn); 80 | if (value != null) { 81 | ixaQuery.setFieldData(szBlockName, requestColumn, 0, value); 82 | } 83 | } 84 | } 85 | 86 | /** 87 | * ixaReal 객체로 맵에 있는 요청값 셋팅 88 | * 89 | * @param ixaReal 인터페이스 객체 90 | * @param resFileData res 파일 객체 91 | * @param query 요청 값 92 | */ 93 | public static void readyForRequest(IXAReal ixaReal, ResFileData resFileData, 94 | Map query) { 95 | 96 | String szBlockName = resFileData.getRequestBlockName(); 97 | List requestColumnList = resFileData.getRequestColumnList(); 98 | 99 | for (String requestColumn : requestColumnList) { 100 | ixaReal.setFieldData(szBlockName, requestColumn, query.get(requestColumn)); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/message/ResFileData.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.message; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * RES DESCRIPTION value object 7 | */ 8 | public class ResFileData { 9 | 10 | public static final int RES_TYPE_IDX = 0; 11 | public static final int RES_DESCRIPTION_IDX = 1; 12 | public static final String REAL = ".Feed"; 13 | public static final String QUERY = ".Func"; 14 | 15 | public static final int DESC_IDX = 0; 16 | public static final int COLUMN_IDX = 1; 17 | public static final int TYPE_IDX = 3; 18 | public static final int SIZE_IDX = 4; 19 | 20 | public static final String DESC = "DESC"; 21 | public static final String COLUMN = "COLUMN"; 22 | public static final String TYPE = "TYPE"; 23 | public static final String SIZE = "SIZE"; 24 | 25 | public static final String REQUEST = "InBlock"; 26 | public static final String RESPONSE = "OutBlock"; 27 | 28 | private Map>> dataMap; 29 | 30 | private String name; 31 | private String resType; 32 | private String description; 33 | 34 | public ResFileData(String name) { 35 | this.name = name; 36 | this.dataMap = new LinkedHashMap<>(); 37 | } 38 | 39 | public String getName() { 40 | return name; 41 | } 42 | 43 | public String getResType() { 44 | return resType; 45 | } 46 | 47 | public void setResType(String resType) { 48 | this.resType = resType; 49 | } 50 | 51 | public String getDescription() { 52 | return description; 53 | } 54 | 55 | public Map>> getDataMap() { 56 | return dataMap; 57 | } 58 | 59 | public void setDescription(String description) { 60 | this.description = description; 61 | } 62 | 63 | public void setDataBlock(String dataBlockName, List> dataBlock) { 64 | this.dataMap.put(dataBlockName, dataBlock); 65 | } 66 | 67 | public List> getDataBlock(String dataBlockName) { 68 | return this.dataMap.get(dataBlockName); 69 | } 70 | 71 | public List getRequestColumnList() { 72 | List result = new LinkedList<>(); 73 | List> inBlock = this.dataMap.get(getRequestBlockName()); 74 | 75 | for (Map row : inBlock) { 76 | result.add(row.get(COLUMN)); 77 | } 78 | return result; 79 | } 80 | 81 | public Map> getResponseColumnMap() { 82 | Map> result = new HashMap<>(); 83 | String[] responseBlocks = this.getResponseBlockName(); 84 | 85 | for (String blockName : responseBlocks) { 86 | List> outBlock = this.dataMap.get(blockName); 87 | 88 | List block = new LinkedList<>(); 89 | for (Map row : outBlock) { 90 | block.add(row.get(COLUMN)); 91 | } 92 | 93 | result.put(blockName, block); 94 | } 95 | 96 | return result; 97 | } 98 | 99 | /** 100 | * 요청 블럭 이름 반환 101 | * 102 | * @return 요청 블럭 이름 103 | */ 104 | public String getRequestBlockName() { 105 | List reqBlockName = findKey(REQUEST); 106 | return reqBlockName.get(0); 107 | } 108 | 109 | /** 110 | * 응답 블럭 이름 반환 111 | * 112 | * @return 응답 블럭 이름 113 | */ 114 | public String[] getResponseBlockName() { 115 | List resBlockName = findKey(RESPONSE); 116 | return resBlockName.toArray(new String[resBlockName.size()]); 117 | } 118 | 119 | private List findKey(String word) { 120 | List result = new ArrayList<>(); 121 | Set keys = this.dataMap.keySet(); 122 | for (String key : keys) { 123 | if (key.toLowerCase().indexOf(word.toLowerCase()) > -1) { 124 | result.add(key); 125 | } 126 | } 127 | return result; 128 | } 129 | } 130 | 131 | 132 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/session/XASession.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.session; 2 | 3 | import com4j.COM4J; 4 | import com4j.EventCookie; 5 | import name.buycycle.configuration.ebest.vo.EBestConfig; 6 | import name.buycycle.vendor.ebest.config.vo.Connect; 7 | import name.buycycle.vendor.ebest.config.vo.User; 8 | import name.buycycle.vendor.ebest.event.handler.XASessionEventHandler; 9 | import name.buycycle.vendor.ebest.event.vo.res.Response; 10 | import name.buycycle.vendor.ebest.exception.ConnectFailException; 11 | import name.buycycle.vendor.ebest.exception.RequestTimeOutException; 12 | import name.buycycle.vendor.ebest.session.com4j.ClassFactory; 13 | import name.buycycle.vendor.ebest.session.com4j.IXASession; 14 | import name.buycycle.vendor.ebest.session.com4j.XA_SERVER_TYPE; 15 | import name.buycycle.vendor.ebest.session.com4j._IXASessionEvents; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | /** 20 | * xing session 인터페이스 21 | * 22 | * @author : ijyoon date : 2021/03/24 23 | */ 24 | public class XASession { 25 | 26 | private Logger logger = LoggerFactory.getLogger(XASession.class); 27 | 28 | private final EBestConfig eBestConfig; 29 | 30 | private IXASession ixaSession; 31 | private EventCookie eventCookie; 32 | 33 | public XASession(EBestConfig eBestConfig) { 34 | this.eBestConfig = eBestConfig; 35 | } 36 | 37 | /** 38 | * 연결 확인 39 | * 40 | * @return 연결 여부 41 | */ 42 | public boolean isConnected() { 43 | if (ixaSession == null) { 44 | return false; 45 | } 46 | return ixaSession.isConnected(); 47 | } 48 | 49 | /** 50 | * 연결 51 | * 52 | * @param connectInfo 대상 서버 정보 53 | * @return 연결 여부 54 | */ 55 | private boolean connect(Connect connectInfo) { 56 | try { 57 | this.ixaSession.connectTimeOut(connectInfo.getConnectTimeOut()); 58 | return this.ixaSession.connectServer(connectInfo.getSzServerIP(), 59 | connectInfo.getnServerPort()); 60 | } catch (Exception e) { 61 | return false; 62 | } 63 | } 64 | 65 | /** 66 | * 로그인 요청 67 | * 68 | * @return 응답 69 | * @throws InterruptedException wait 70 | * @throws RequestTimeOutException 타임 아웃 71 | * @throws ConnectFailException 연결 실패 72 | */ 73 | public synchronized Response login() 74 | throws InterruptedException, RequestTimeOutException, ConnectFailException { 75 | 76 | final XASessionEventHandler xaSessionEventHandler = new XASessionEventHandler(); 77 | this.ixaSession = ClassFactory.createXASession(); 78 | this.eventCookie = this.ixaSession.advise(_IXASessionEvents.class, xaSessionEventHandler); 79 | 80 | if (connect(eBestConfig.getConnect())) { 81 | User user = eBestConfig.getUser(); 82 | this.ixaSession.login(user.getId(), user.getPw(), user.getCpwd(), 83 | XA_SERVER_TYPE.XA_REAL_SERVER.comEnumValue(), false); 84 | 85 | synchronized (xaSessionEventHandler) { 86 | long startTime = System.currentTimeMillis(); 87 | xaSessionEventHandler.wait(eBestConfig.getConnect().getRequestReadTimeOut()); 88 | long elapsedTime = System.currentTimeMillis() - startTime; 89 | 90 | if (elapsedTime >= eBestConfig.getConnect().getRequestReadTimeOut()) { 91 | throw new RequestTimeOutException(eBestConfig.getConnect().getRequestReadTimeOut()); 92 | } 93 | } 94 | return xaSessionEventHandler.getResponse(); 95 | } else { 96 | throw new ConnectFailException(); 97 | } 98 | } 99 | 100 | /** 101 | * session close 102 | */ 103 | public synchronized void close() { 104 | try { 105 | if (this.ixaSession != null) { 106 | this.ixaSession.disconnectServer(); 107 | } 108 | } catch (Exception e) { 109 | this.logger.error(e.getMessage(), e); 110 | } 111 | 112 | try { 113 | if (this.eventCookie != null) { 114 | this.eventCookie.close(); 115 | } 116 | } catch (Exception e) { 117 | this.logger.error(e.getMessage(), e); 118 | } 119 | 120 | COM4J.cleanUp(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/message/ResFileReader.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.message; 2 | 3 | import java.io.*; 4 | import java.util.LinkedHashMap; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * res file parser 11 | * 12 | * @author : ijyoon 13 | * @date : 2021/03/24 14 | */ 15 | public class ResFileReader { 16 | 17 | private static final String START_MARK = "BEGIN_DATA_MAP"; 18 | private static final String END_MARK = "END_DATA_MAP"; 19 | 20 | private static final String BEGIN = "begin"; 21 | private static final String END = "end"; 22 | 23 | private String resRootPath; 24 | 25 | public String getResRootPath() { 26 | return resRootPath; 27 | } 28 | 29 | public void setResRootPath(String resRootPath) { 30 | this.resRootPath = resRootPath; 31 | } 32 | 33 | public ResFileData load(String resFileName) throws Exception { 34 | if (this.resRootPath == null) { 35 | throw new MessageException("res root path is null."); 36 | } 37 | 38 | return this.load(new File(this.resRootPath + File.separator + resFileName + ".res")); 39 | } 40 | 41 | /** 42 | * res 파일을 읽어와 data map 으로 변환한다. 43 | * 44 | * @param resFile 대상 res 파일 45 | * @return ResFileData object 46 | * @throws Exception 47 | */ 48 | public ResFileData load(File resFile) throws Exception { 49 | 50 | boolean findDataMapStart = false; 51 | ResFileData resFileData = new ResFileData(resFile.getName().split("\\.")[0]); 52 | 53 | try ( BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(resFile), "MS949")) ){ 54 | String readLine; 55 | int lineNum = 0; 56 | while ((readLine = br.readLine()) != null) { 57 | lineNum++; 58 | if (readLine.endsWith(START_MARK)) { 59 | findDataMapStart = true; 60 | } else if (readLine.endsWith(END_MARK)) { 61 | break; 62 | } else { 63 | String[] s = readLine 64 | .replace("\t", "") 65 | .replace(" ", "") 66 | .split(","); 67 | if (findDataMapStart) { 68 | String[] subjects = s; 69 | if (subjects.length == 4 && subjects[3].startsWith("occurs")) { 70 | subjects[0] += "_repeat"; 71 | } 72 | 73 | resFileData.setDataBlock(subjects[0], extractionData(br)); 74 | } else if (lineNum == 2) { 75 | String[] data = s; 76 | resFileData.setResType(data[ResFileData.RES_TYPE_IDX]); 77 | resFileData.setDescription(data[ResFileData.RES_DESCRIPTION_IDX]); 78 | } 79 | } 80 | } 81 | return resFileData; 82 | } catch (Exception e) { 83 | throw e; 84 | } 85 | } 86 | 87 | /** 88 | * res file parser 89 | * 90 | * @param br res file 91 | * @return res data to map 92 | * @throws Exception invalid end of data 93 | */ 94 | private List> extractionData(BufferedReader br) throws Exception { 95 | 96 | boolean findBegin = false; 97 | List> dataList = new LinkedList<>(); 98 | 99 | String readLine; 100 | while ((readLine = br.readLine()) != null) { 101 | 102 | if (readLine.endsWith(BEGIN)) { 103 | findBegin = true; 104 | } else if (readLine.endsWith(END)) { 105 | return dataList; 106 | } else if (findBegin) { 107 | String[] data = readLine.replace("\t", "") 108 | .replace(" ", "") 109 | .split(","); 110 | if (data.length < 5) { 111 | continue; 112 | } 113 | 114 | Map dataSet = new LinkedHashMap<>(); 115 | dataSet.put(ResFileData.COLUMN, data[ResFileData.COLUMN_IDX]); 116 | dataSet.put(ResFileData.DESC, data[ResFileData.DESC_IDX]); 117 | dataSet.put(ResFileData.TYPE, data[ResFileData.TYPE_IDX]); 118 | dataSet.put(ResFileData.SIZE, data[ResFileData.SIZE_IDX].replace(";", "")); 119 | dataList.add(dataSet); 120 | } 121 | } 122 | throw new MessageException("not found END character : [" + END + "]"); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/manage/XARealSubscribeManager.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.manage; 2 | 3 | import name.buycycle.vendor.ebest.event.XARealResponseEvent; 4 | import name.buycycle.vendor.ebest.event.XARealSubscribe; 5 | import name.buycycle.vendor.ebest.event.vo.req.Request; 6 | import name.buycycle.vendor.ebest.manage.command.XARealSubscribeCommand; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class XARealSubscribeManager extends AbstractManager { 14 | 15 | private static final Logger logger = LoggerFactory.getLogger(XARealSubscribeManager.class); 16 | private static final XARealSubscribeManager instance = new XARealSubscribeManager(); 17 | 18 | public static XARealSubscribeManager getInstance() { 19 | return instance; 20 | } 21 | 22 | public static final String COMMAND_REQUEST = "REQUEST"; 23 | public static final String COMMAND_STOP = "STOP"; 24 | public static final String COMMAND_SHUTDOWN = "SHUTDOWN"; 25 | 26 | private Map threadMap; 27 | 28 | private XARealSubscribeManager() { 29 | super("XARealSubscribeManager", logger); 30 | this.threadMap = new HashMap<>(); 31 | } 32 | 33 | /** 34 | * 실시간 tr 요청 35 | * 36 | * @param request 37 | */ 38 | public void realTrRequest(XARealResponseEvent event, Request request) { 39 | requestCommand(new XARealSubscribeCommand(COMMAND_REQUEST) 40 | .setXaRealResponseEvent(event) 41 | .setRequest(request) 42 | ); 43 | } 44 | 45 | /** 46 | * 특정 스레드 중지 요청 47 | * 48 | * @param request 49 | */ 50 | public void realTrStop(Request request) { 51 | requestCommand(new XARealSubscribeCommand(COMMAND_STOP) 52 | .setRequest(request) 53 | ); 54 | } 55 | 56 | public void shutdown() { 57 | requestCommand(new XARealSubscribeCommand(COMMAND_SHUTDOWN)); 58 | } 59 | 60 | /** 61 | * 스레드 초기화 62 | */ 63 | @Override 64 | public void initialize() { 65 | // no initialize 66 | } 67 | 68 | @Override 69 | void request(XARealSubscribeCommand command) { 70 | switch (command.toString()) { 71 | case COMMAND_REQUEST: 72 | this.realTrRequestProcess(command); 73 | break; 74 | case COMMAND_STOP: 75 | this.realTrStopProcess(command); 76 | break; 77 | case COMMAND_SHUTDOWN: 78 | this.shutdownProcess(); 79 | break; 80 | default: 81 | if (logger.isErrorEnabled()) { 82 | logger.error("unsupported operation", 83 | new UnsupportedOperationException(command.toString())); 84 | } 85 | } 86 | } 87 | 88 | public void realTrRequestProcess(XARealSubscribeCommand command) { 89 | 90 | if (this.threadMap.containsKey(command.getRequest())) { 91 | return; 92 | } 93 | 94 | command.setEBestConfig(this.eBestConfig); 95 | XARealSubscribe xaRealSubscribe = new XARealSubscribe(command); 96 | xaRealSubscribe.start(); 97 | this.threadMap.put(command.getRequest(), xaRealSubscribe); 98 | } 99 | 100 | public void realTrStopProcess(XARealSubscribeCommand command) { 101 | 102 | XARealSubscribe xaRealSubscribe = this.threadMap.remove(command.getRequest()); 103 | 104 | if (xaRealSubscribe == null) { 105 | return; 106 | } 107 | 108 | xaRealSubscribe.shutdown(); 109 | try { 110 | xaRealSubscribe.join(); 111 | } catch (InterruptedException e) { 112 | if (logger.isErrorEnabled()) { 113 | logger.error(e.getMessage(), e); 114 | } 115 | Thread.currentThread().interrupt(); 116 | } 117 | } 118 | 119 | public void shutdownProcess() { 120 | 121 | threadMap.forEach((request, xaRealSubscribe) -> { 122 | xaRealSubscribe.shutdown(); 123 | try { 124 | xaRealSubscribe.join(); 125 | } catch (InterruptedException e) { 126 | if (logger.isErrorEnabled()) { 127 | logger.error(e.getMessage(), e); 128 | } 129 | Thread.currentThread().interrupt(); 130 | } 131 | }); 132 | setRunning(false); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/com4j/IXAReal.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.com4j; 2 | 3 | import com4j.*; 4 | import name.buycycle.vendor.ebest.event.IXAType; 5 | 6 | /** 7 | * IXAReal Interface 8 | */ 9 | @IID("{ED0FC93A-7879-4C0D-BA8F-71A7E2B5A737}") 10 | public interface IXAReal extends Com4jObject, IXAType { 11 | // Methods: 12 | 13 | /** 14 | *

15 | * property FileName 16 | *

17 | *

18 | * Getter method for the COM property "ResFileName" 19 | *

20 | * 21 | * @return Returns a value of type java.lang.String 22 | */ 23 | 24 | @DISPID(1) //= 0x1. The runtime will prefer the VTID if present 25 | @VTID(7) 26 | String resFileName(); 27 | 28 | 29 | /** 30 | *

31 | * property FileName 32 | *

33 | *

34 | * Setter method for the COM property "ResFileName" 35 | *

36 | * 37 | * @param pVal Mandatory java.lang.String parameter. 38 | */ 39 | 40 | @DISPID(1) //= 0x1. The runtime will prefer the VTID if present 41 | @VTID(8) 42 | void resFileName( 43 | String pVal); 44 | 45 | 46 | /** 47 | *

48 | * property GetTrCode 49 | *

50 | * 51 | * @return Returns a value of type java.lang.String 52 | */ 53 | 54 | @DISPID(6) //= 0x6. The runtime will prefer the VTID if present 55 | @VTID(9) 56 | String getTrCode(); 57 | 58 | 59 | /** 60 | *

61 | * method LoadFromResFile 62 | *

63 | * 64 | * @param szFileName Mandatory java.lang.String parameter. 65 | * @return Returns a value of type boolean 66 | */ 67 | 68 | @DISPID(7) //= 0x7. The runtime will prefer the VTID if present 69 | @VTID(10) 70 | boolean loadFromResFile( 71 | String szFileName); 72 | 73 | 74 | /** 75 | *

76 | * Input Record�� Setting. 77 | *

78 | * 79 | * @param szBlockName Mandatory java.lang.String parameter. 80 | * @param szFieldName Mandatory java.lang.String parameter. 81 | * @param szData Mandatory java.lang.String parameter. 82 | */ 83 | 84 | @DISPID(8) //= 0x8. The runtime will prefer the VTID if present 85 | @VTID(11) 86 | void setFieldData( 87 | String szBlockName, 88 | String szFieldName, 89 | String szData); 90 | 91 | 92 | /** 93 | *

94 | * method GetFieldData 95 | *

96 | * 97 | * @param szBlockName Mandatory java.lang.String parameter. 98 | * @param szFieldName Mandatory java.lang.String parameter. 99 | * @return Returns a value of type java.lang.String 100 | */ 101 | 102 | @DISPID(11) //= 0xb. The runtime will prefer the VTID if present 103 | @VTID(12) 104 | String getFieldData( 105 | String szBlockName, 106 | String szFieldName); 107 | 108 | 109 | /** 110 | *

111 | * method AdviseRealData 112 | *

113 | */ 114 | 115 | @DISPID(12) //= 0xc. The runtime will prefer the VTID if present 116 | @VTID(13) 117 | void adviseRealData(); 118 | 119 | 120 | /** 121 | *

122 | * method UnadviseRealData 123 | *

124 | */ 125 | 126 | @DISPID(13) //= 0xd. The runtime will prefer the VTID if present 127 | @VTID(14) 128 | void unadviseRealData(); 129 | 130 | 131 | /** 132 | *

133 | * method UnadviseRealDataWithKey 134 | *

135 | * 136 | * @param szCode Mandatory java.lang.String parameter. 137 | */ 138 | 139 | @DISPID(14) //= 0xe. The runtime will prefer the VTID if present 140 | @VTID(15) 141 | void unadviseRealDataWithKey( 142 | String szCode); 143 | 144 | 145 | /** 146 | *

147 | * method AdviseLinkFromHTS 148 | *

149 | */ 150 | 151 | @DISPID(15) //= 0xf. The runtime will prefer the VTID if present 152 | @VTID(16) 153 | void adviseLinkFromHTS(); 154 | 155 | 156 | /** 157 | *

158 | * method UnAdviseLinkFromHTS 159 | *

160 | */ 161 | 162 | @DISPID(16) //= 0x10. The runtime will prefer the VTID if present 163 | @VTID(17) 164 | void unAdviseLinkFromHTS(); 165 | 166 | 167 | /** 168 | *

169 | * method GetBlockData 170 | *

171 | * 172 | * @param szBlockName Mandatory java.lang.String parameter. 173 | * @return Returns a value of type java.lang.String 174 | */ 175 | 176 | @DISPID(17) //= 0x11. The runtime will prefer the VTID if present 177 | @VTID(18) 178 | String getBlockData( 179 | String szBlockName); 180 | 181 | // Properties: 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/XAQueryRequest.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event; 2 | 3 | import com4j.COM4J; 4 | import name.buycycle.configuration.ebest.vo.EBestConfig; 5 | import name.buycycle.vendor.ebest.event.com4j.IXAQuery; 6 | import name.buycycle.vendor.ebest.event.com4j._IXAQueryEvents; 7 | import name.buycycle.vendor.ebest.event.handler.XAQueryEventHandler; 8 | import name.buycycle.vendor.ebest.event.vo.req.Request; 9 | import name.buycycle.vendor.ebest.event.vo.req.RequestBody; 10 | import name.buycycle.vendor.ebest.event.vo.res.Response; 11 | import name.buycycle.vendor.ebest.event.xaobject.XAObjectHelper; 12 | import name.buycycle.vendor.ebest.event.xaobject.vo.XAObject; 13 | import name.buycycle.vendor.ebest.message.MessageHelper; 14 | import name.buycycle.vendor.ebest.message.ResFileData; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.Set; 22 | 23 | /** 24 | * xa query 요청 / 응답 25 | * 26 | * @author : ijyoon 27 | * @date : 2021/03/24 28 | */ 29 | public class XAQueryRequest { 30 | 31 | private Logger logger = LoggerFactory.getLogger(getClass()); 32 | private final MessageHelper messageHelper = MessageHelper.getInstance(); 33 | 34 | private EBestConfig eBestConfig; 35 | 36 | public XAQueryRequest(EBestConfig eBestConfig) { 37 | this.eBestConfig = eBestConfig; 38 | } 39 | 40 | /** 41 | * xa query 요청, 응답 42 | * 43 | * @param request 요청 값 44 | * @return 응답 45 | */ 46 | public Response requestQuery(Request request) { 47 | 48 | RequestBody requestBody = request.getBody(); 49 | XAObject xaObject = null; 50 | Response response = null; 51 | 52 | try { 53 | ResFileData resFileData = this.messageHelper.getResFileData(ResFileData.QUERY, 54 | requestBody.getTrName()); 55 | XAQueryEventHandler xaQueryEventHandler = new XAQueryEventHandler( 56 | request.getHeader().getUuid()); 57 | xaObject = XAObjectHelper.createXAObject(this.eBestConfig.getResRootPath(), resFileData, 58 | _IXAQueryEvents.class, xaQueryEventHandler); 59 | IXAQuery ixaQuery = xaObject.getIxaType(); 60 | 61 | XAObjectHelper.readyForRequest(ixaQuery, resFileData, requestBody.getQuery()); 62 | ixaQuery.request(requestBody.isbNext()); 63 | 64 | synchronized (xaQueryEventHandler) { 65 | xaQueryEventHandler.wait(eBestConfig.getConnect().getRequestReadTimeOut()); 66 | } 67 | 68 | response = xaQueryEventHandler.getResponse(); 69 | setResponseData(ixaQuery, resFileData.getResponseColumnMap(), response); 70 | } catch (InterruptedException e) { 71 | if (logger.isErrorEnabled()) { 72 | logger.error(e.getMessage(), e); 73 | } 74 | Thread.currentThread().interrupt(); 75 | 76 | } catch (Exception e) { 77 | if (logger.isErrorEnabled()) { 78 | logger.error(e.getMessage(), e); 79 | } 80 | exceptionResponseMsg(request, response, e); 81 | } finally { 82 | if (xaObject != null && xaObject.getEventCookie() != null) { 83 | xaObject.getEventCookie().close(); 84 | COM4J.cleanUp(); 85 | } 86 | } 87 | 88 | return response; 89 | } 90 | 91 | /** 92 | * ixaQuery 응답값을 vo로 변환 93 | * 94 | * @param ixaQuery ixaQuery 응답 값 95 | * @param resSchemaMap res file data 96 | * @param response 응답 vo 97 | */ 98 | private void setResponseData(IXAQuery ixaQuery, Map> resSchemaMap, 99 | Response response) { 100 | Set blocks = resSchemaMap.keySet(); 101 | 102 | int count; 103 | String originBlockName; 104 | for (String blockName : blocks) { 105 | if (blockName.endsWith("_repeat")) { 106 | originBlockName = blockName.replace("_repeat", ""); 107 | count = ixaQuery.getBlockCount(originBlockName); 108 | } else { 109 | originBlockName = blockName; 110 | count = 1; 111 | } 112 | 113 | List columns = resSchemaMap.get(blockName); 114 | Map row; 115 | for (int i = 0; i < count; i++) { 116 | row = new HashMap<>(); 117 | for (String columnName : columns) { 118 | row.put(columnName, ixaQuery.getFieldData(originBlockName, columnName, i)); 119 | } 120 | response.putBody(originBlockName, row); 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * 예외 발생 시 해당 메시지를 응답 값으로 반환 127 | * 128 | * @param request 요청 vo 129 | * @param response 응답 vo 130 | * @param e 예외 131 | */ 132 | private void exceptionResponseMsg(Request request, Response response, Exception e) { 133 | if (response == null) { 134 | response = new Response(request.getHeader().getUuid()); 135 | } 136 | response.putHeader("buyCycleErrMsg", e.getMessage()); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/XARealSubscribe.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event; 2 | 3 | import com4j.COM4J; 4 | import com4j.EventCookie; 5 | import name.buycycle.configuration.ebest.vo.EBestConfig; 6 | import name.buycycle.vendor.ebest.event.com4j.IXAReal; 7 | import name.buycycle.vendor.ebest.event.com4j._IXARealEvents; 8 | import name.buycycle.vendor.ebest.event.handler.XARealEventHandler; 9 | import name.buycycle.vendor.ebest.event.vo.req.Request; 10 | import name.buycycle.vendor.ebest.event.vo.req.RequestBody; 11 | import name.buycycle.vendor.ebest.event.vo.res.Response; 12 | import name.buycycle.vendor.ebest.event.xaobject.XAObjectHelper; 13 | import name.buycycle.vendor.ebest.event.xaobject.vo.XAObject; 14 | import name.buycycle.vendor.ebest.manage.command.XARealSubscribeCommand; 15 | import name.buycycle.vendor.ebest.message.MessageHelper; 16 | import name.buycycle.vendor.ebest.message.ResFileData; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.Set; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | /** 27 | * xa real 이벤트 수신 스레드 28 | * 29 | * @author : ijyoon 30 | * @date : 2021/03/24 31 | */ 32 | public class XARealSubscribe extends Thread { 33 | 34 | private Logger logger = LoggerFactory.getLogger(getClass()); 35 | private MessageHelper messageHelper = MessageHelper.getInstance(); 36 | 37 | private boolean running = true; 38 | private Object monitor; 39 | 40 | private EBestConfig eBestConfig; 41 | private Request request; 42 | private XARealResponseEvent xaRealResponseEvent; 43 | 44 | private static final AtomicInteger atomicInteger = new AtomicInteger(); 45 | 46 | public XARealSubscribe(XARealSubscribeCommand command) { 47 | super("XARealSubscribe-" + atomicInteger.incrementAndGet()); 48 | this.xaRealResponseEvent = command.getXaRealResponseEvent(); 49 | this.eBestConfig = command.getEBestConfig(); 50 | this.request = command.getRequest(); 51 | this.monitor = new Object(); 52 | this.setDaemon(true); 53 | } 54 | 55 | @Override 56 | public void run() { 57 | 58 | RequestBody requestBody = request.getBody(); 59 | XAObject xaObject = null; 60 | IXAReal ixaReal = null; 61 | Response response; 62 | 63 | try { 64 | ResFileData resFileData = this.messageHelper.getResFileData(ResFileData.REAL, 65 | requestBody.getTrName()); 66 | XARealEventHandler xaRealEventHandler = new XARealEventHandler(this.monitor, 67 | request.getHeader().getUuid()); 68 | xaObject = XAObjectHelper.createXAObject(eBestConfig.getResRootPath(), resFileData, 69 | _IXARealEvents.class, xaRealEventHandler); 70 | ixaReal = xaObject.getIxaType(); 71 | 72 | XAObjectHelper.readyForRequest(ixaReal, resFileData, requestBody.getQuery()); 73 | ixaReal.adviseRealData(); 74 | 75 | while (isRunning()) { 76 | synchronized (this.monitor) { 77 | this.monitor.wait(); 78 | } 79 | if (!isRunning()) { 80 | break; 81 | } 82 | 83 | response = xaRealEventHandler.getResponse(); 84 | setResponseData(ixaReal, resFileData.getResponseColumnMap(), response); 85 | this.xaRealResponseEvent.responseEvent(request, response); 86 | } 87 | } catch (InterruptedException ie) { 88 | if (logger.isInfoEnabled()) { 89 | logger.info("XARealSubscribe shutdown event received."); 90 | } 91 | Thread.currentThread().interrupt(); 92 | } catch (Exception e) { 93 | if (logger.isErrorEnabled()) { 94 | logger.error(e.getMessage(), e); 95 | } 96 | } finally { 97 | if (ixaReal != null) { 98 | ixaReal.unadviseRealData(); 99 | } 100 | 101 | if (xaObject != null) { 102 | EventCookie eventCookie = xaObject.getEventCookie(); 103 | if (eventCookie != null) { 104 | eventCookie.close(); 105 | } 106 | 107 | COM4J.cleanUp(); 108 | } 109 | logger.info("XARealSubscribe process end."); 110 | } 111 | } 112 | 113 | public boolean isRunning() { 114 | return running; 115 | } 116 | 117 | public void shutdown() { 118 | this.running = false; 119 | synchronized (this.monitor) { 120 | this.monitor.notifyAll(); 121 | } 122 | } 123 | 124 | public Request getRequest() { 125 | return request; 126 | } 127 | 128 | /** 129 | * 수신 ixaReal -> value object 130 | * 131 | * @param ixaReal 132 | * @param resSchemaMap 133 | * @param response 134 | */ 135 | private void setResponseData(IXAReal ixaReal, Map> resSchemaMap, 136 | Response response) { 137 | Set blocks = resSchemaMap.keySet(); 138 | 139 | for (String blockName : blocks) { 140 | List columns = resSchemaMap.get(blockName); 141 | Map row = new HashMap<>(); 142 | 143 | for (String columnName : columns) { 144 | row.put(columnName, ixaReal.getFieldData(blockName, columnName)); 145 | } 146 | response.putBody(blockName, row); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/control/XARealWebSocketHandler.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.control; 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import name.buycycle.vendor.ebest.event.vo.req.Request; 6 | import name.buycycle.vendor.ebest.manage.XARealSubscribeManager; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.socket.CloseStatus; 11 | import org.springframework.web.socket.TextMessage; 12 | import org.springframework.web.socket.WebSocketSession; 13 | import org.springframework.web.socket.handler.TextWebSocketHandler; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Iterator; 17 | import java.util.List; 18 | import java.util.Map; 19 | import java.util.concurrent.ConcurrentHashMap; 20 | 21 | /** 22 | * 웹소켓 json 메시지 요청, 응답 23 | */ 24 | @Component 25 | public class XARealWebSocketHandler extends TextWebSocketHandler { 26 | 27 | private Logger logger = LoggerFactory.getLogger(XARealWebSocketHandler.class); 28 | private XARealSubscribeManager xaRealSubscribeManager = XARealSubscribeManager.getInstance(); 29 | 30 | private Map> requestSessionMap; 31 | 32 | private ObjectMapper objectMapper; 33 | 34 | public XARealWebSocketHandler() { 35 | objectMapper = new ObjectMapper(); 36 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 37 | requestSessionMap = new ConcurrentHashMap<>(); 38 | } 39 | 40 | @Override 41 | public void afterConnectionEstablished(WebSocketSession session) throws Exception { 42 | if (logger.isInfoEnabled()) { 43 | logger.info("ConnectionEstablished : {}", session.getId()); 44 | } 45 | } 46 | 47 | @Override 48 | public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { 49 | 50 | String targetSessionId = session.getId(); 51 | Iterator requestIterator = requestSessionMap.keySet().iterator(); 52 | while (requestIterator.hasNext()) { 53 | Request key = requestIterator.next(); 54 | 55 | List sessionList = requestSessionMap.get(key); 56 | for (int i = 0; i < sessionList.size(); i++) { 57 | WebSocketSession getSession = sessionList.get(i); 58 | if (targetSessionId.equals(getSession.getId())) { 59 | sessionList.remove(i); 60 | break; 61 | } 62 | } 63 | 64 | if (sessionList.isEmpty()) { 65 | xaRealSubscribeManager.realTrStop(key); 66 | requestIterator.remove(); 67 | } 68 | } 69 | 70 | if (logger.isInfoEnabled()) { 71 | logger.info("ConnectionClosed : {}", session.getId()); 72 | } 73 | } 74 | 75 | /** 76 | * 요청 받은 후 수신 이벤트 응답 스레드 생성 77 | * 78 | * @param session 79 | * @param message 80 | * @throws Exception 81 | */ 82 | @Override 83 | protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { 84 | String requestJsonMessage = message.getPayload(); 85 | 86 | if (logger.isDebugEnabled()) { 87 | logger.debug(" => request message \n---\n{}\n---", requestJsonMessage); 88 | } 89 | 90 | Request request = objectMapper.readValue(requestJsonMessage, Request.class); 91 | 92 | if (this.checkAlreadyRequest(session, request)) { 93 | if (logger.isInfoEnabled()) { 94 | logger.info( 95 | "already requested : [{}] [{}] [{}]", 96 | session.getId(), 97 | request.getBody().getTrName(), 98 | request.getFirstValue() 99 | ); 100 | } 101 | return; 102 | } else { 103 | List sessionList = requestSessionMap.get(request); 104 | if (sessionList == null) { 105 | sessionList = new ArrayList<>(); 106 | requestSessionMap.put(request, sessionList); 107 | } 108 | sessionList.add(session); 109 | } 110 | 111 | xaRealSubscribeManager.realTrRequest((receiveRequest, response) -> { 112 | List sessionList = requestSessionMap.get(receiveRequest); 113 | if (sessionList != null && sessionList.size() > 0) { 114 | String responseStr = objectMapper.writeValueAsString(response); 115 | for (WebSocketSession responseSession : sessionList) { 116 | if (logger.isDebugEnabled()) { 117 | logger.debug(" <= response message \n---\n{}\n---", responseStr); 118 | } 119 | 120 | if (responseSession.isOpen()) { 121 | synchronized (responseSession) { 122 | responseSession.sendMessage(new TextMessage(responseStr)); 123 | } 124 | } else { 125 | responseSession.close(); 126 | } 127 | } 128 | } 129 | }, request); 130 | } 131 | 132 | /** 133 | * 이미 요청된 tr 인지 확인 134 | * 135 | * @param searchSession 136 | * @param request 137 | * @return 138 | */ 139 | private boolean checkAlreadyRequest(WebSocketSession searchSession, Request request) { 140 | String searchSessionId = searchSession.getId(); 141 | List sessionIdList = requestSessionMap.get(request); 142 | 143 | if (sessionIdList == null) { 144 | return false; 145 | } 146 | 147 | for (WebSocketSession session : sessionIdList) { 148 | if (searchSessionId.equals(session.getId())) { 149 | return true; 150 | } 151 | } 152 | return false; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/manage/XASessionManager.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.manage; 2 | 3 | import name.buycycle.vendor.ebest.event.vo.res.Response; 4 | import name.buycycle.vendor.ebest.exception.ConnectFailException; 5 | import name.buycycle.vendor.ebest.exception.RequestTimeOutException; 6 | import name.buycycle.vendor.ebest.session.XASession; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * xa session 연결 관리자 12 | */ 13 | public class XASessionManager extends AbstractManager { 14 | 15 | private static final Logger logger = LoggerFactory.getLogger(XASessionManager.class); 16 | private static final XASessionManager instance = new XASessionManager(); 17 | 18 | public static XASessionManager getInstance() { 19 | return instance; 20 | } 21 | 22 | public static final String COMMAND_LOGIN = "LOGIN"; 23 | public static final String COMMAND_CLOSE = "CLOSE"; 24 | public static final String COMMAND_SHUTDOWN = "SHUTDOWN"; 25 | public static final String COMMAND_TOUCH = "TOUCH"; 26 | public static final String COMMAND_CHECK = "CHECK"; 27 | 28 | private boolean succeedLogin = false; 29 | private long touchTime; 30 | private XASession xaSession; 31 | 32 | private XASessionManager() { 33 | super("XASessionManager", logger); 34 | this.setRequestTimeOut(10000).setRequestTimeOutCommand(COMMAND_CHECK); 35 | } 36 | 37 | /** 38 | * 로그인 확인 39 | * 40 | * @return 로그인 여부 41 | */ 42 | public boolean isSucceedLogin() { 43 | return succeedLogin; 44 | } 45 | 46 | /** 47 | * 로그인 요청 48 | * 49 | * @return 응답 값 50 | */ 51 | public Response login() { 52 | requestCommand(COMMAND_LOGIN); 53 | return responseTake(); 54 | } 55 | 56 | /** 57 | * 세션 종료 요청 58 | */ 59 | public void close() { 60 | if (this.succeedLogin) { 61 | requestCommand(COMMAND_CLOSE); 62 | } 63 | } 64 | 65 | /** 66 | * 스레드 종료 요청 67 | */ 68 | public void shutdown() { 69 | requestCommand(COMMAND_SHUTDOWN); 70 | try { 71 | this.join(); 72 | } catch (InterruptedException ignored) { 73 | if (logger.isErrorEnabled()) { 74 | logger.error(ignored.getMessage(), ignored); 75 | } 76 | Thread.currentThread().interrupt(); 77 | } 78 | } 79 | 80 | /** 81 | * idle time 갱신 82 | */ 83 | public void touch() { 84 | requestCommand(COMMAND_TOUCH); 85 | } 86 | 87 | /** 88 | * 스레드 초기화 89 | */ 90 | @Override 91 | public void initialize() { 92 | if (eBestConfig == null) { 93 | throw new NullPointerException("EBestConfig is null."); 94 | } 95 | this.xaSession = new XASession(this.eBestConfig); 96 | this.touchRequest(); 97 | } 98 | 99 | @Override 100 | void request(String command) { 101 | switch (command) { 102 | case COMMAND_LOGIN: 103 | this.loginRequest(this.xaSession); 104 | break; 105 | case COMMAND_CLOSE: 106 | this.closeRequest(this.xaSession); 107 | break; 108 | case COMMAND_SHUTDOWN: 109 | this.shutdownRequest(this.xaSession); 110 | break; 111 | case COMMAND_TOUCH: 112 | this.touchRequest(); 113 | break; 114 | case COMMAND_CHECK: 115 | this.checkRequest(this.xaSession); 116 | break; 117 | default: 118 | if (logger.isErrorEnabled()) { 119 | logger.error("unsupported operation", new UnsupportedOperationException(command)); 120 | } 121 | } 122 | } 123 | 124 | /** 125 | * 로그인 요청 126 | */ 127 | private void loginRequest(XASession xaSession) { 128 | 129 | if (!this.succeedLogin) { 130 | Response response; 131 | try { 132 | response = xaSession.login(); 133 | } catch (InterruptedException | RequestTimeOutException | ConnectFailException e) { 134 | if (logger.isErrorEnabled()) { 135 | logger.error(e.getMessage(), e); 136 | } 137 | Thread.currentThread().interrupt(); 138 | response = errorResponse(e); 139 | } 140 | 141 | if (response != null && response.getHeader("szCode").equals("0000")) { 142 | this.succeedLogin = true; 143 | } 144 | responseCommand(response); 145 | } else { 146 | responseCommand(null); 147 | } 148 | 149 | } 150 | 151 | private Response errorResponse(Throwable e) { 152 | Response response = new Response(); 153 | response.putHeader("buyCycleErrMsg", e.getMessage()); 154 | return response; 155 | } 156 | 157 | /** 158 | * 세션 종료 요청 159 | * 160 | * @param xaSession XASession 161 | */ 162 | private void closeRequest(XASession xaSession) { 163 | xaSession.close(); 164 | this.succeedLogin = false; 165 | } 166 | 167 | /** 168 | * 스레드 종료 169 | * 170 | * @param xaSession XASession 171 | */ 172 | private void shutdownRequest(XASession xaSession) { 173 | if (isSucceedLogin()) { 174 | this.closeRequest(xaSession); 175 | } 176 | setRunning(false); 177 | } 178 | 179 | /** 180 | * idle time 갱신 181 | */ 182 | private void touchRequest() { 183 | this.touchTime = System.currentTimeMillis(); 184 | } 185 | 186 | /** 187 | * idle time out session close 188 | */ 189 | private void checkRequest(XASession xaSession) { 190 | long now = System.currentTimeMillis(); 191 | if ((now - this.touchTime) > (5 * 60 * 1000) && isSucceedLogin()) { 192 | this.closeRequest(xaSession); 193 | if (logger.isInfoEnabled()) { 194 | logger.info("xasession idle time out. connection closed."); 195 | } 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /frontend/src/components/EBestTable.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | -------------------------------------------------------------------------------- /frontend/src/assets/buycycle.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 24 | 28 | 32 | 33 | 40 | 48 | 53 | 54 | 62 | 67 | 68 | 69 | 96 | 98 | 99 | 101 | image/svg+xml 102 | 104 | 105 | 106 | 107 | 108 | 113 | 119 | 125 | 126 | 131 | B 142 | uycycle 153 | 154 | 155 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/control/EBestController.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.control; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.databind.SerializationFeature; 5 | import name.buycycle.control.rvo.ResTable; 6 | import name.buycycle.service.ebest.EBestDescription; 7 | import name.buycycle.service.ebest.vo.ResDesc; 8 | import name.buycycle.vendor.ebest.event.vo.req.Request; 9 | import name.buycycle.vendor.ebest.event.vo.res.Response; 10 | import name.buycycle.vendor.ebest.manage.XAQueryManager; 11 | import name.buycycle.vendor.ebest.message.ResFileData; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.hateoas.EntityModel; 16 | import org.springframework.http.ResponseEntity; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; 20 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; 21 | 22 | /** 23 | * 이베스트 컨트롤러 24 | * 25 | * @author : ijyoon 26 | */ 27 | @RestController 28 | @RequestMapping("/ebest") 29 | public class EBestController { 30 | 31 | private static final String REAL_TR_LIST = "real_tr_list"; // real tr 목록 32 | private static final String REAL_TR_DESC = "real_tr_desc"; // real tr 상세 33 | private static final String QUERY_TR_LIST = "query_tr_list"; // query tr 목록 34 | private static final String QUERY_TR_DESC = "query_tr_desc"; // query tr 상세 35 | private static final String REQUEST_MESSAGE = "request_message"; // 요청메시지 36 | private static final String REQUEST = "request"; // 요청 37 | 38 | private final Logger logger = LoggerFactory.getLogger(getClass()); 39 | private final ObjectMapper objectMapper = new ObjectMapper().enable( 40 | SerializationFeature.INDENT_OUTPUT); 41 | 42 | private final XAQueryManager xaQueryManager = XAQueryManager.getInstance(); 43 | 44 | @Autowired 45 | private EBestDescription eBestDescription; 46 | 47 | /** 48 | * xing api 호출 49 | * 50 | * @param request 요청 값 51 | * @return api 요청 응답값 52 | * @throws Exception exception 53 | */ 54 | @PostMapping(value = "/queries", produces = "application/json;charset=utf-8") 55 | public ResponseEntity> queryRequest(@RequestBody Request request) 56 | throws Exception { 57 | 58 | if (logger.isDebugEnabled()) { 59 | logger.debug(" => request message \n---\n{}\n---", 60 | objectMapper.writeValueAsString(request)); 61 | } 62 | 63 | Response response = this.xaQueryManager.requestQuery(request); 64 | 65 | if (logger.isDebugEnabled()) { 66 | logger.debug(" <= response message \n---\n{}\n---", 67 | objectMapper.writeValueAsString(response)); 68 | } 69 | 70 | return ResponseEntity.ok( 71 | EntityModel.of(response) 72 | .add(linkTo(methodOn(EBestController.class).queryRequest(null)).withSelfRel()) 73 | ); 74 | } 75 | 76 | /** 77 | * real 목록 78 | * 79 | * @return XAReal 요청 목록 80 | */ 81 | @GetMapping("/description/realtime") 82 | public ResponseEntity> listReal() throws Exception { 83 | if (logger.isInfoEnabled()) { 84 | logger.info("Real 목록 요청"); 85 | } 86 | 87 | ResTable result = eBestDescription.resList(ResFileData.REAL); 88 | return ResponseEntity.ok( 89 | EntityModel.of(result) 90 | .add(linkTo(methodOn(EBestController.class).listReal()).withSelfRel()) 91 | .add(linkTo(methodOn(EBestController.class).listReal(null)).withRel(REAL_TR_DESC)) 92 | .add(linkTo(methodOn(EBestController.class).requestMessage(null)).withRel( 93 | REQUEST_MESSAGE)) 94 | ); 95 | } 96 | 97 | /** 98 | * query 목록 99 | * 100 | * @return XAQuery 요청 목록 101 | */ 102 | @GetMapping("/description/queries") 103 | public ResponseEntity> listQuery() throws Exception { 104 | if (logger.isInfoEnabled()) { 105 | logger.info("Query 목록 요청"); 106 | } 107 | 108 | ResTable result = eBestDescription.resList(ResFileData.QUERY); 109 | 110 | return ResponseEntity.ok( 111 | EntityModel.of(result) 112 | .add(linkTo(methodOn(EBestController.class).listQuery()).withSelfRel()) 113 | .add(linkTo(methodOn(EBestController.class).listQuery(null)).withRel(QUERY_TR_DESC)) 114 | .add(linkTo(methodOn(EBestController.class).requestMessage(null)).withRel( 115 | REQUEST_MESSAGE)) 116 | ); 117 | } 118 | 119 | /** 120 | * real tr 명세 121 | * 122 | * @param trName TR 이름 123 | * @return 대상 TR 명세서 124 | */ 125 | @GetMapping("/description/realtime/{trName}") 126 | public ResponseEntity> listReal(@PathVariable String trName) 127 | throws Exception { 128 | if (logger.isInfoEnabled()) { 129 | logger.info("[{}] Real 명세 요청", trName); 130 | } 131 | 132 | ResDesc result = eBestDescription.resDesc(trName); 133 | 134 | return ResponseEntity.ok( 135 | EntityModel.of(result) 136 | .add(linkTo(methodOn(EBestController.class).listReal(trName)).withSelfRel()) 137 | .add(linkTo(methodOn(EBestController.class).listReal()).withRel(REAL_TR_LIST)) 138 | .add(linkTo(methodOn(EBestController.class).requestMessage(trName)).withRel( 139 | REQUEST_MESSAGE)) 140 | ); 141 | } 142 | 143 | /** 144 | * query tr 명세 145 | * 146 | * @param trName TR 이름 147 | * @return 대상 TR 명세서 148 | */ 149 | @GetMapping("/description/queries/{trName}") 150 | public ResponseEntity> listQuery(@PathVariable String trName) 151 | throws Exception { 152 | if (logger.isInfoEnabled()) { 153 | logger.info("[{}] Query 명세 요청", trName); 154 | } 155 | ResDesc result = eBestDescription.resDesc(trName); 156 | 157 | return ResponseEntity.ok( 158 | EntityModel.of(result) 159 | .add(linkTo(methodOn(EBestController.class).listQuery(trName)).withSelfRel()) 160 | .add(linkTo(methodOn(EBestController.class).listQuery()).withRel(QUERY_TR_LIST)) 161 | .add(linkTo(methodOn(EBestController.class).requestMessage(trName)).withRel( 162 | REQUEST_MESSAGE)) 163 | .add(linkTo(methodOn(EBestController.class).queryRequest(null)).withRel(REQUEST)) 164 | ); 165 | } 166 | 167 | /** 168 | * 샘플 요청 메시지 반환 169 | * 170 | * @param trName 대상 TR 171 | * @return 대상 TR 요청 메시지 172 | */ 173 | @GetMapping(value = "/request-messages/{trName}") 174 | public ResponseEntity> requestMessage(@PathVariable String trName) 175 | throws Exception { 176 | if (logger.isInfoEnabled()) { 177 | logger.info("[{}] 요청 메시지 샘플", trName); 178 | } 179 | Request result = eBestDescription.requestMessage(trName); 180 | 181 | return ResponseEntity.ok( 182 | EntityModel.of(result) 183 | .add(linkTo(methodOn(EBestController.class).requestMessage(trName)).withSelfRel()) 184 | .add(linkTo(methodOn(EBestController.class).queryRequest(null)).withRel(REQUEST)) 185 | ); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/session/com4j/IXASession.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.session.com4j; 2 | 3 | import com4j.Com4jObject; 4 | import com4j.DISPID; 5 | import com4j.IID; 6 | import com4j.VTID; 7 | 8 | /** 9 | * IXASession Interface 10 | */ 11 | @IID("{8C0F4618-3BAB-4F19-A59B-A32E08EA711F}") 12 | public interface IXASession extends Com4jObject { 13 | // Methods: 14 | 15 | /** 16 | *

17 | * method IsLoadAPI 18 | *

19 | * 20 | * @return Returns a value of type boolean 21 | */ 22 | 23 | @DISPID(1) //= 0x1. The runtime will prefer the VTID if present 24 | @VTID(7) 25 | boolean isLoadAPI(); 26 | 27 | 28 | /** 29 | *

30 | * method ConnectServer 31 | *

32 | * 33 | * @param szServerIP Mandatory java.lang.String parameter. 34 | * @param nServerPort Mandatory int parameter. 35 | * @return Returns a value of type boolean 36 | */ 37 | 38 | @DISPID(2) //= 0x2. The runtime will prefer the VTID if present 39 | @VTID(8) 40 | boolean connectServer( 41 | String szServerIP, 42 | int nServerPort); 43 | 44 | 45 | /** 46 | *

47 | * method DisConnectServer 48 | *

49 | */ 50 | 51 | @DISPID(3) //= 0x3. The runtime will prefer the VTID if present 52 | @VTID(9) 53 | void disconnectServer(); 54 | 55 | 56 | /** 57 | *

58 | * method IsConnected 59 | *

60 | * 61 | * @return Returns a value of type boolean 62 | */ 63 | 64 | @DISPID(4) //= 0x4. The runtime will prefer the VTID if present 65 | @VTID(10) 66 | boolean isConnected(); 67 | 68 | 69 | /** 70 | *

71 | * method Login 72 | *

73 | * 74 | * @param szID Mandatory java.lang.String parameter. 75 | * @param szPwd Mandatory java.lang.String parameter. 76 | * @param szCertPwd Mandatory java.lang.String parameter. 77 | * @param nServerType Mandatory int parameter. 78 | * @param bShowCertErrDlg Mandatory boolean parameter. 79 | * @return Returns a value of type boolean 80 | */ 81 | 82 | @DISPID(5) //= 0x5. The runtime will prefer the VTID if present 83 | @VTID(11) 84 | boolean login( 85 | String szID, 86 | String szPwd, 87 | String szCertPwd, 88 | int nServerType, 89 | boolean bShowCertErrDlg); 90 | 91 | 92 | /** 93 | *

94 | * method Logout 95 | *

96 | * 97 | * @return Returns a value of type boolean 98 | */ 99 | 100 | @DISPID(7) //= 0x7. The runtime will prefer the VTID if present 101 | @VTID(12) 102 | boolean logout(); 103 | 104 | 105 | /** 106 | *

107 | * property ConnectTimeOut 108 | *

109 | *

110 | * Getter method for the COM property "ConnectTimeOut" 111 | *

112 | * 113 | * @return Returns a value of type int 114 | */ 115 | 116 | @DISPID(8) //= 0x8. The runtime will prefer the VTID if present 117 | @VTID(13) 118 | int connectTimeOut(); 119 | 120 | 121 | /** 122 | *

123 | * property ConnectTimeOut 124 | *

125 | *

126 | * Setter method for the COM property "ConnectTimeOut" 127 | *

128 | * 129 | * @param pVal Mandatory int parameter. 130 | */ 131 | 132 | @DISPID(8) //= 0x8. The runtime will prefer the VTID if present 133 | @VTID(14) 134 | void connectTimeOut( 135 | int pVal); 136 | 137 | 138 | /** 139 | *

140 | * property SendPacketSize 141 | *

142 | *

143 | * Getter method for the COM property "SendPacketSize" 144 | *

145 | * 146 | * @return Returns a value of type int 147 | */ 148 | 149 | @DISPID(9) //= 0x9. The runtime will prefer the VTID if present 150 | @VTID(15) 151 | int sendPacketSize(); 152 | 153 | 154 | /** 155 | *

156 | * property SendPacketSize 157 | *

158 | *

159 | * Setter method for the COM property "SendPacketSize" 160 | *

161 | * 162 | * @param pVal Mandatory int parameter. 163 | */ 164 | 165 | @DISPID(9) //= 0x9. The runtime will prefer the VTID if present 166 | @VTID(16) 167 | void sendPacketSize( 168 | int pVal); 169 | 170 | 171 | /** 172 | *

173 | * method GetLastError 174 | *

175 | * 176 | * @return Returns a value of type int 177 | */ 178 | 179 | @DISPID(10) //= 0xa. The runtime will prefer the VTID if present 180 | @VTID(17) 181 | int getLastError(); 182 | 183 | 184 | /** 185 | *

186 | * method GetErrorMessage 187 | *

188 | * 189 | * @param nErrorCode Mandatory int parameter. 190 | * @return Returns a value of type java.lang.String 191 | */ 192 | 193 | @DISPID(11) //= 0xb. The runtime will prefer the VTID if present 194 | @VTID(18) 195 | String getErrorMessage( 196 | int nErrorCode); 197 | 198 | 199 | /** 200 | *

201 | * method GetCommMedia 202 | *

203 | * 204 | * @return Returns a value of type java.lang.String 205 | */ 206 | 207 | @DISPID(12) //= 0xc. The runtime will prefer the VTID if present 208 | @VTID(19) 209 | String getCommMedia(); 210 | 211 | 212 | /** 213 | *

214 | * method GetETKMedia 215 | *

216 | * 217 | * @return Returns a value of type java.lang.String 218 | */ 219 | 220 | @DISPID(13) //= 0xd. The runtime will prefer the VTID if present 221 | @VTID(20) 222 | String getETKMedia(); 223 | 224 | 225 | /** 226 | *

227 | * method GetClientIP 228 | *

229 | * 230 | * @return Returns a value of type java.lang.String 231 | */ 232 | 233 | @DISPID(14) //= 0xe. The runtime will prefer the VTID if present 234 | @VTID(21) 235 | String getClientIP(); 236 | 237 | 238 | /** 239 | *

240 | * method GetServerName 241 | *

242 | * 243 | * @return Returns a value of type java.lang.String 244 | */ 245 | 246 | @DISPID(15) //= 0xf. The runtime will prefer the VTID if present 247 | @VTID(22) 248 | String getServerName(); 249 | 250 | 251 | /** 252 | *

253 | * method GetAccountList 254 | *

255 | * 256 | * @param nIndex Mandatory int parameter. 257 | * @return Returns a value of type java.lang.String 258 | */ 259 | 260 | @DISPID(16) //= 0x10. The runtime will prefer the VTID if present 261 | @VTID(23) 262 | String getAccountList( 263 | int nIndex); 264 | 265 | 266 | /** 267 | *

268 | * method GetAccountListCount 269 | *

270 | * 271 | * @return Returns a value of type int 272 | */ 273 | 274 | @DISPID(17) //= 0x11. The runtime will prefer the VTID if present 275 | @VTID(24) 276 | int getAccountListCount(); 277 | 278 | 279 | /** 280 | *

281 | * method GetAccountName 282 | *

283 | * 284 | * @param szAcc Mandatory java.lang.String parameter. 285 | * @return Returns a value of type java.lang.String 286 | */ 287 | 288 | @DISPID(18) //= 0x12. The runtime will prefer the VTID if present 289 | @VTID(25) 290 | String getAccountName( 291 | String szAcc); 292 | 293 | 294 | /** 295 | *

296 | * method GetAcctDetailName 297 | *

298 | * 299 | * @param szAcc Mandatory java.lang.String parameter. 300 | * @return Returns a value of type java.lang.String 301 | */ 302 | 303 | @DISPID(19) //= 0x13. The runtime will prefer the VTID if present 304 | @VTID(26) 305 | String getAcctDetailName( 306 | String szAcc); 307 | 308 | 309 | /** 310 | *

311 | * method GetAcctNickname 312 | *

313 | * 314 | * @param szAcc Mandatory java.lang.String parameter. 315 | * @return Returns a value of type java.lang.String 316 | */ 317 | 318 | @DISPID(20) //= 0x14. The runtime will prefer the VTID if present 319 | @VTID(27) 320 | String getAcctNickname( 321 | String szAcc); 322 | 323 | 324 | /** 325 | *

326 | * method GetPath 327 | *

328 | * 329 | * @return Returns a value of type java.lang.String 330 | */ 331 | 332 | @DISPID(21) //= 0x15. The runtime will prefer the VTID if present 333 | @VTID(28) 334 | String getPath(); 335 | 336 | 337 | /** 338 | *

339 | * method SetPath 340 | *

341 | * 342 | * @param szPath Mandatory java.lang.String parameter. 343 | */ 344 | 345 | @DISPID(22) //= 0x16. The runtime will prefer the VTID if present 346 | @VTID(29) 347 | void setPath( 348 | String szPath); 349 | 350 | 351 | /** 352 | *

353 | * method SetMode 354 | *

355 | * 356 | * @param szMode Mandatory java.lang.String parameter. 357 | * @param szValue Mandatory java.lang.String parameter. 358 | * @return Returns a value of type boolean 359 | */ 360 | 361 | @DISPID(23) //= 0x17. The runtime will prefer the VTID if present 362 | @VTID(30) 363 | boolean setMode( 364 | String szMode, 365 | String szValue); 366 | 367 | // Properties: 368 | } 369 | -------------------------------------------------------------------------------- /src/main/java/name/buycycle/vendor/ebest/event/com4j/IXAQuery.java: -------------------------------------------------------------------------------- 1 | package name.buycycle.vendor.ebest.event.com4j; 2 | 3 | import com4j.*; 4 | import name.buycycle.vendor.ebest.event.IXAType; 5 | 6 | /** 7 | * IXAQuery Interface 8 | */ 9 | @IID("{255B43AE-B290-4435-9BA7-37FCAAD04D77}") 10 | public interface IXAQuery extends Com4jObject, IXAType { 11 | // Methods: 12 | 13 | /** 14 | *

15 | * method GetFieldData 16 | *

17 | * 18 | * @param szBlockName Mandatory java.lang.String parameter. 19 | * @param szFieldName Mandatory java.lang.String parameter. 20 | * @param nRecordIndex Mandatory int parameter. 21 | * @return Returns a value of type java.lang.String 22 | */ 23 | 24 | @DISPID(2) //= 0x2. The runtime will prefer the VTID if present 25 | @VTID(7) 26 | String getFieldData( 27 | String szBlockName, 28 | String szFieldName, 29 | int nRecordIndex); 30 | 31 | 32 | /** 33 | *

34 | * method Request 35 | *

36 | * 37 | * @param bNext Mandatory boolean parameter. 38 | * @return Returns a value of type int 39 | */ 40 | 41 | @DISPID(3) //= 0x3. The runtime will prefer the VTID if present 42 | @VTID(8) 43 | int request( 44 | boolean bNext); 45 | 46 | 47 | /** 48 | *

49 | * property ResFileName 50 | *

51 | *

52 | * Getter method for the COM property "ResFileName" 53 | *

54 | * 55 | * @return Returns a value of type java.lang.String 56 | */ 57 | 58 | @DISPID(5) //= 0x5. The runtime will prefer the VTID if present 59 | @VTID(9) 60 | String resFileName(); 61 | 62 | 63 | /** 64 | *

65 | * property ResFileName 66 | *

67 | *

68 | * Setter method for the COM property "ResFileName" 69 | *

70 | * 71 | * @param pVal Mandatory java.lang.String parameter. 72 | */ 73 | 74 | @DISPID(5) //= 0x5. The runtime will prefer the VTID if present 75 | @VTID(10) 76 | void resFileName( 77 | String pVal); 78 | 79 | 80 | /** 81 | *

82 | * method LoadFromResFile 83 | *

84 | * 85 | * @param szFileName Mandatory java.lang.String parameter. 86 | * @return Returns a value of type boolean 87 | */ 88 | 89 | @DISPID(6) //= 0x6. The runtime will prefer the VTID if present 90 | @VTID(11) 91 | boolean loadFromResFile( 92 | String szFileName); 93 | 94 | 95 | /** 96 | *

97 | * property GetTrCode 98 | *

99 | * 100 | * @return Returns a value of type java.lang.String 101 | */ 102 | 103 | @DISPID(7) //= 0x7. The runtime will prefer the VTID if present 104 | @VTID(12) 105 | String getTrCode(); 106 | 107 | 108 | /** 109 | *

110 | * property GetTrDesc 111 | *

112 | * 113 | * @return Returns a value of type java.lang.String 114 | */ 115 | 116 | @DISPID(8) //= 0x8. The runtime will prefer the VTID if present 117 | @VTID(13) 118 | String getTrDesc(); 119 | 120 | 121 | /** 122 | *

123 | * method GetBlockInfo 124 | *

125 | * 126 | * @param szFieldName Mandatory java.lang.String parameter. 127 | * @param szNameK Mandatory Holder parameter. 128 | * @param szNameE Mandatory Holder parameter. 129 | * @param nRecordType Mandatory Holder parameter. 130 | */ 131 | 132 | @DISPID(14) //= 0xe. The runtime will prefer the VTID if present 133 | @VTID(14) 134 | void getBlockInfo( 135 | String szFieldName, 136 | Holder szNameK, 137 | Holder szNameE, 138 | Holder nRecordType); 139 | 140 | 141 | /** 142 | *

143 | * Input Record�� Setting. 144 | *

145 | * 146 | * @param szBlockName Mandatory java.lang.String parameter. 147 | * @param szFieldName Mandatory java.lang.String parameter. 148 | * @param nOccursIndex Mandatory int parameter. 149 | * @param szData Mandatory java.lang.String parameter. 150 | */ 151 | 152 | @DISPID(15) //= 0xf. The runtime will prefer the VTID if present 153 | @VTID(15) 154 | void setFieldData( 155 | String szBlockName, 156 | String szFieldName, 157 | int nOccursIndex, 158 | String szData); 159 | 160 | 161 | /** 162 | *

163 | * method GetFieldInfo 164 | *

165 | * 166 | * @param szFieldName Mandatory java.lang.String parameter. 167 | * @param szItemName Mandatory java.lang.String parameter. 168 | * @param nItemType Mandatory Holder parameter. 169 | * @param nDataSize Mandatory Holder parameter. 170 | * @param nDotPoint Mandatory Holder parameter. 171 | * @param nOffSet Mandatory Holder parameter. 172 | */ 173 | 174 | @DISPID(17) //= 0x11. The runtime will prefer the VTID if present 175 | @VTID(16) 176 | void getFieldInfo( 177 | String szFieldName, 178 | String szItemName, 179 | Holder nItemType, 180 | Holder nDataSize, 181 | Holder nDotPoint, 182 | Holder nOffSet); 183 | 184 | 185 | /** 186 | *

187 | * property GetBlockType 188 | *

189 | * 190 | * @param szBlockName Mandatory java.lang.String parameter. 191 | * @return Returns a value of type int 192 | */ 193 | 194 | @DISPID(18) //= 0x12. The runtime will prefer the VTID if present 195 | @VTID(17) 196 | int getBlockType( 197 | String szBlockName); 198 | 199 | 200 | /** 201 | *

202 | * method GetResData 203 | *

204 | * 205 | * @return Returns a value of type java.lang.String 206 | */ 207 | 208 | @DISPID(19) //= 0x13. The runtime will prefer the VTID if present 209 | @VTID(18) 210 | String getResData(); 211 | 212 | 213 | /** 214 | *

215 | * method GetBlockSize 216 | *

217 | * 218 | * @param szBlockName Mandatory java.lang.String parameter. 219 | * @return Returns a value of type int 220 | */ 221 | 222 | @DISPID(23) //= 0x17. The runtime will prefer the VTID if present 223 | @VTID(19) 224 | int getBlockSize( 225 | String szBlockName); 226 | 227 | 228 | /** 229 | *

230 | * method GetFieldDescList 231 | *

232 | * 233 | * @param szBlockName Mandatory java.lang.String parameter. 234 | * @return Returns a value of type java.lang.String 235 | */ 236 | 237 | @DISPID(24) //= 0x18. The runtime will prefer the VTID if present 238 | @VTID(20) 239 | String getFieldDescList( 240 | String szBlockName); 241 | 242 | 243 | /** 244 | *

245 | * property IsNext 246 | *

247 | *

248 | * Getter method for the COM property "IsNext" 249 | *

250 | * 251 | * @return Returns a value of type boolean 252 | */ 253 | 254 | @DISPID(29) //= 0x1d. The runtime will prefer the VTID if present 255 | @VTID(21) 256 | boolean isNext(); 257 | 258 | 259 | /** 260 | *

261 | * property ContinueKey 262 | *

263 | *

264 | * Getter method for the COM property "ContinueKey" 265 | *

266 | * 267 | * @return Returns a value of type java.lang.String 268 | */ 269 | 270 | @DISPID(30) //= 0x1e. The runtime will prefer the VTID if present 271 | @VTID(22) 272 | String continueKey(); 273 | 274 | 275 | /** 276 | *

277 | * method GetBlockCount 278 | *

279 | * 280 | * @param szBlockName Mandatory java.lang.String parameter. 281 | * @return Returns a value of type int 282 | */ 283 | 284 | @DISPID(31) //= 0x1f. The runtime will prefer the VTID if present 285 | @VTID(23) 286 | int getBlockCount( 287 | String szBlockName); 288 | 289 | 290 | /** 291 | *

292 | * method SetBlockCount 293 | *

294 | * 295 | * @param szBlockName Mandatory java.lang.String parameter. 296 | * @param nCount Mandatory int parameter. 297 | */ 298 | 299 | @DISPID(32) //= 0x20. The runtime will prefer the VTID if present 300 | @VTID(24) 301 | void setBlockCount( 302 | String szBlockName, 303 | int nCount); 304 | 305 | 306 | /** 307 | *

308 | * method ClearBlockdata 309 | *

310 | * 311 | * @param szFieldName Mandatory java.lang.String parameter. 312 | */ 313 | 314 | @DISPID(33) //= 0x21. The runtime will prefer the VTID if present 315 | @VTID(25) 316 | void clearBlockdata( 317 | String szFieldName); 318 | 319 | 320 | /** 321 | *

322 | * method GetLastError 323 | *

324 | * 325 | * @return Returns a value of type int 326 | */ 327 | 328 | @DISPID(34) //= 0x22. The runtime will prefer the VTID if present 329 | @VTID(26) 330 | int getLastError(); 331 | 332 | 333 | /** 334 | *

335 | * method GetErrorMessage 336 | *

337 | * 338 | * @param nErrorCode Mandatory int parameter. 339 | * @return Returns a value of type java.lang.String 340 | */ 341 | 342 | @DISPID(35) //= 0x23. The runtime will prefer the VTID if present 343 | @VTID(27) 344 | String getErrorMessage( 345 | int nErrorCode); 346 | 347 | 348 | /** 349 | *

350 | * method GetAccountList 351 | *

352 | * 353 | * @param nIndex Mandatory int parameter. 354 | * @return Returns a value of type java.lang.String 355 | */ 356 | 357 | @DISPID(36) //= 0x24. The runtime will prefer the VTID if present 358 | @VTID(28) 359 | String getAccountList( 360 | int nIndex); 361 | 362 | 363 | /** 364 | *

365 | * method GetAccountListCount 366 | *

367 | * 368 | * @return Returns a value of type int 369 | */ 370 | 371 | @DISPID(37) //= 0x25. The runtime will prefer the VTID if present 372 | @VTID(29) 373 | int getAccountListCount(); 374 | 375 | 376 | /** 377 | *

378 | * method GetBlockData 379 | *

380 | * 381 | * @param szBlockName Mandatory java.lang.String parameter. 382 | * @return Returns a value of type java.lang.String 383 | */ 384 | 385 | @DISPID(38) //= 0x26. The runtime will prefer the VTID if present 386 | @VTID(30) 387 | String getBlockData( 388 | String szBlockName); 389 | 390 | 391 | /** 392 | *

393 | * method RequestService 394 | *

395 | * 396 | * @param szCode Mandatory java.lang.String parameter. 397 | * @param szData Mandatory java.lang.String parameter. 398 | * @return Returns a value of type int 399 | */ 400 | 401 | @DISPID(39) //= 0x27. The runtime will prefer the VTID if present 402 | @VTID(31) 403 | int requestService( 404 | String szCode, 405 | String szData); 406 | 407 | 408 | /** 409 | *

410 | * method RemoveService 411 | *

412 | * 413 | * @param szCode Mandatory java.lang.String parameter. 414 | * @param szData Mandatory java.lang.String parameter. 415 | * @return Returns a value of type int 416 | */ 417 | 418 | @DISPID(40) //= 0x28. The runtime will prefer the VTID if present 419 | @VTID(32) 420 | int removeService( 421 | String szCode, 422 | String szData); 423 | 424 | 425 | /** 426 | *

427 | * method RequestLinkToHTS 428 | *

429 | * 430 | * @param szLinkName Mandatory java.lang.String parameter. 431 | * @param szData Mandatory java.lang.String parameter. 432 | * @param szFiller Mandatory java.lang.String parameter. 433 | * @return Returns a value of type boolean 434 | */ 435 | 436 | @DISPID(41) //= 0x29. The runtime will prefer the VTID if present 437 | @VTID(33) 438 | boolean requestLinkToHTS( 439 | String szLinkName, 440 | String szData, 441 | String szFiller); 442 | 443 | 444 | /** 445 | *

446 | * method Decompress 447 | *

448 | * 449 | * @param szBlockName Mandatory java.lang.String parameter. 450 | * @return Returns a value of type int 451 | */ 452 | 453 | @DISPID(42) //= 0x2a. The runtime will prefer the VTID if present 454 | @VTID(34) 455 | int decompress( 456 | String szBlockName); 457 | 458 | 459 | /** 460 | *

461 | * method GetTRCountPerSec 462 | *

463 | * 464 | * @param szCode Mandatory java.lang.String parameter. 465 | * @return Returns a value of type int 466 | */ 467 | 468 | @DISPID(43) //= 0x2b. The runtime will prefer the VTID if present 469 | @VTID(35) 470 | int getTRCountPerSec( 471 | String szCode); 472 | 473 | 474 | /** 475 | *

476 | * method GetAccountName 477 | *

478 | * 479 | * @param szAcc Mandatory java.lang.String parameter. 480 | * @return Returns a value of type java.lang.String 481 | */ 482 | 483 | @DISPID(44) //= 0x2c. The runtime will prefer the VTID if present 484 | @VTID(36) 485 | String getAccountName( 486 | String szAcc); 487 | 488 | 489 | /** 490 | *

491 | * method GetAcctDetailName 492 | *

493 | * 494 | * @param szAcc Mandatory java.lang.String parameter. 495 | * @return Returns a value of type java.lang.String 496 | */ 497 | 498 | @DISPID(45) //= 0x2d. The runtime will prefer the VTID if present 499 | @VTID(37) 500 | String getAcctDetailName( 501 | String szAcc); 502 | 503 | 504 | /** 505 | *

506 | * method GetAcctNickname 507 | *

508 | * 509 | * @param szAcc Mandatory java.lang.String parameter. 510 | * @return Returns a value of type java.lang.String 511 | */ 512 | 513 | @DISPID(46) //= 0x2e. The runtime will prefer the VTID if present 514 | @VTID(38) 515 | String getAcctNickname( 516 | String szAcc); 517 | 518 | 519 | /** 520 | *

521 | * method GetFieldChartRealData 522 | *

523 | * 524 | * @param szBlockName Mandatory java.lang.String parameter. 525 | * @param szFieldName Mandatory java.lang.String parameter. 526 | * @return Returns a value of type java.lang.String 527 | */ 528 | 529 | @DISPID(47) //= 0x2f. The runtime will prefer the VTID if present 530 | @VTID(39) 531 | String getFieldChartRealData( 532 | String szBlockName, 533 | String szFieldName); 534 | 535 | 536 | /** 537 | *

538 | * method GetAttribute 539 | *

540 | * 541 | * @param szBlockName Mandatory java.lang.String parameter. 542 | * @param szFieldName Mandatory java.lang.String parameter. 543 | * @param szAttribute Mandatory java.lang.String parameter. 544 | * @param nRecordIndex Mandatory int parameter. 545 | * @return Returns a value of type java.lang.String 546 | */ 547 | 548 | @DISPID(48) //= 0x30. The runtime will prefer the VTID if present 549 | @VTID(40) 550 | String getAttribute( 551 | String szBlockName, 552 | String szFieldName, 553 | String szAttribute, 554 | int nRecordIndex); 555 | 556 | 557 | /** 558 | *

559 | * method GetTRCountBaseSec 560 | *

561 | * 562 | * @param szCode Mandatory java.lang.String parameter. 563 | * @return Returns a value of type int 564 | */ 565 | 566 | @DISPID(49) //= 0x31. The runtime will prefer the VTID if present 567 | @VTID(41) 568 | int getTRCountBaseSec( 569 | String szCode); 570 | 571 | 572 | /** 573 | *

574 | * method GetTRCountRequest 575 | *

576 | * 577 | * @param szCode Mandatory java.lang.String parameter. 578 | * @return Returns a value of type int 579 | */ 580 | 581 | @DISPID(50) //= 0x32. The runtime will prefer the VTID if present 582 | @VTID(42) 583 | int getTRCountRequest( 584 | String szCode); 585 | 586 | 587 | /** 588 | *

589 | * method GetTRCountLimit 590 | *

591 | * 592 | * @param szCode Mandatory java.lang.String parameter. 593 | * @return Returns a value of type int 594 | */ 595 | 596 | @DISPID(51) //= 0x33. The runtime will prefer the VTID if present 597 | @VTID(43) 598 | int getTRCountLimit( 599 | String szCode); 600 | 601 | 602 | /** 603 | *

604 | * method GetFieldSearchRealData 605 | *

606 | * 607 | * @param szBlockName Mandatory java.lang.String parameter. 608 | * @param szFieldName Mandatory java.lang.String parameter. 609 | * @return Returns a value of type java.lang.String 610 | */ 611 | 612 | @DISPID(52) //= 0x34. The runtime will prefer the VTID if present 613 | @VTID(44) 614 | String getFieldSearchRealData( 615 | String szBlockName, 616 | String szFieldName); 617 | 618 | // Properties: 619 | } 620 | --------------------------------------------------------------------------------