착각은 자유...그리고 오판의 쓴맛

emptynote의 이미지

코다 서버 만들때

서버 비지니스 로직을 나름 이것이 콤포넌트라고 생각하는 방향으로 설계를 이렇게 했습니다.

그래서 사람들이 콤포넌트를 작성하여 공개를 하면

오픈소스 진영에 서비스가 확장되겠구나 했습니다.

하지만 이건 이건 저의 착각 저만의 생각일뿐 ㅠ.ㅠ

정말로 이게 콤포넌트일까요?

재사용 가능한 코드라는 관점에서 막히네요.

문서를 작성하여 문서를 웹 서비스에 추가및 적용을 해주는 서비스가 필요하게 되었습니다.

이 문서 서비스는 기존 개발했던 게시판에 문서 관련 정보 { (1) 게시판 PK, (2) 문서 URL } 테이블 게시판 내용만 추가하면 되었습니다.

그런데 막상 구현을 할려다 보니 이런 트랜잭션을 묶은 상태로 게시판 서버 모듈 재사용이 안되네요.

콤포넌트라 재 사용 가능할것이다 라는것은 저만의 착각이였습니다.

DB 트랙잭션을 묶을려리 난감하네요.

현재에는 공통 부분을 공통 로직으로 분리하여 재 사용하는 방법을 생각하고 있습니다.

그런데 이것이 진정 콤포넌트인지 모르겠습니다.

공학도 이지만 늘상 어제 보다 오늘 더 진보하기를 희망합니다.

package kr.pe.codda.impl.task.server;
 
import static kr.pe.codda.jooq.tables.SbBoardHistoryTb.SB_BOARD_HISTORY_TB;
import static kr.pe.codda.jooq.tables.SbBoardInfoTb.SB_BOARD_INFO_TB;
import static kr.pe.codda.jooq.tables.SbBoardTb.SB_BOARD_TB;
import static kr.pe.codda.jooq.tables.SbBoardVoteTb.SB_BOARD_VOTE_TB;
import static kr.pe.codda.jooq.tables.SbMemberTb.SB_MEMBER_TB;
 
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashSet;
 
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Record13;
import org.jooq.Record3;
import org.jooq.Record4;
import org.jooq.Result;
import org.jooq.Table;
import org.jooq.types.UByte;
import org.jooq.types.UInteger;
import org.jooq.types.UShort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import kr.pe.codda.common.exception.DynamicClassCallException;
import kr.pe.codda.common.exception.ServerTaskException;
import kr.pe.codda.common.message.AbstractMessage;
import kr.pe.codda.impl.message.BoardListReq.BoardListReq;
import kr.pe.codda.impl.message.BoardListRes.BoardListRes;
import kr.pe.codda.impl.message.MessageResultRes.MessageResultRes;
import kr.pe.codda.jooq.tables.SbBoardHistoryTb;
import kr.pe.codda.jooq.tables.SbBoardTb;
import kr.pe.codda.server.LoginManagerIF;
import kr.pe.codda.server.lib.BoardListType;
import kr.pe.codda.server.lib.BoardStateType;
import kr.pe.codda.server.lib.PermissionType;
import kr.pe.codda.server.lib.ServerCommonStaticFinalVars;
import kr.pe.codda.server.lib.ServerDBUtil;
import kr.pe.codda.server.lib.ValueChecker;
import kr.pe.codda.server.task.AbstractServerTask;
import kr.pe.codda.server.task.ToLetterCarrier;
 
public class BoardListReqServerTask extends AbstractServerTask {
	private Logger log = LoggerFactory.getLogger(AccountSearchProcessReqServerTask.class);
 
	public BoardListReqServerTask() throws DynamicClassCallException {
		super();
	}
 
	private void sendErrorOutputMessage(String errorMessage, ToLetterCarrier toLetterCarrier,
			AbstractMessage inputMessage) throws InterruptedException {
		log.warn("{}, inObj={}", errorMessage, inputMessage.toString());
 
		MessageResultRes messageResultRes = new MessageResultRes();
		messageResultRes.setTaskMessageID(inputMessage.getMessageID());
		messageResultRes.setIsSuccess(false);
		messageResultRes.setResultMessage(errorMessage);
		toLetterCarrier.addSyncOutputMessage(messageResultRes);
	}
 
	@Override
	public void doTask(String projectName, LoginManagerIF personalLoginManager, ToLetterCarrier toLetterCarrier,
			AbstractMessage inputMessage) throws Exception {
		try {
			AbstractMessage outputMessage = doWork(ServerCommonStaticFinalVars.DEFAULT_DBCP_NAME,
					(BoardListReq) inputMessage);
			toLetterCarrier.addSyncOutputMessage(outputMessage);
		} catch (ServerTaskException e) {
			String errorMessage = e.getMessage();
			log.warn("errmsg=={}, inObj={}", errorMessage, inputMessage.toString());
 
			sendErrorOutputMessage(errorMessage, toLetterCarrier, inputMessage);
			return;
		} catch (Exception e) {
			String errorMessage = new StringBuilder().append("unknwon errmsg=").append(e.getMessage())
					.append(", inObj=").append(inputMessage.toString()).toString();
 
			log.warn(errorMessage, e);
 
			sendErrorOutputMessage("게시글 목록 조회가 실패하였습니다", toLetterCarrier, inputMessage);
			return;
		}
	}
 
	public BoardListRes doWork(String dbcpName, BoardListReq boardListReq) throws Exception {
		// FIXME!
		log.info(boardListReq.toString());
 
		try {
			ValueChecker.checkValidBoardID(boardListReq.getBoardID());		
			ValueChecker.checkValidPageNoAndPageSize(boardListReq.getPageNo(), boardListReq.getPageSize());
		} catch (IllegalArgumentException e) {
			String errorMessage = e.getMessage();
			throw new ServerTaskException(errorMessage);
		}
 
		final UByte boardID = UByte.valueOf(boardListReq.getBoardID());		
 
		final int pageNo = boardListReq.getPageNo();
		final int pageSize = boardListReq.getPageSize();
		final int offset = (pageNo - 1) * pageSize;		
 
		final java.util.List<BoardListRes.Board> boardList = new ArrayList<BoardListRes.Board>();
 
		final BoardListRes boardListRes = new BoardListRes();
 
		ServerDBUtil.execute(dbcpName, (conn, create) -> {
 
			ServerDBUtil.checkUserAccessRights(conn, create, log, "게시글 목록 조회 서비스", PermissionType.GUEST, boardListReq.getRequestedUserID());
 
			Record3<String, Byte, Byte> boardInforRecord = create
					.select(SB_BOARD_INFO_TB.BOARD_NAME, SB_BOARD_INFO_TB.LIST_TYPE, SB_BOARD_INFO_TB.WRITE_PERMISSION_TYPE)
					.from(SB_BOARD_INFO_TB).where(SB_BOARD_INFO_TB.BOARD_ID.eq(boardID)).forUpdate().fetchOne();
 
			if (null == boardInforRecord) {
				try {
					conn.rollback();
				} catch (Exception e) {
					log.warn("fail to rollback");
				}
 
				String errorMessage = new StringBuilder("입력 받은 게시판 식별자[").append(boardID.shortValue())
						.append("]가 게시판 정보 테이블에 존재하지  않습니다").toString();
				throw new ServerTaskException(errorMessage);
			}
 
 
			String boardName = boardInforRecord.get(SB_BOARD_INFO_TB.BOARD_NAME);
			byte boardListTypeValue = boardInforRecord.get(SB_BOARD_INFO_TB.LIST_TYPE);
			byte boardWritePermissionTypeValue = boardInforRecord.get(SB_BOARD_INFO_TB.WRITE_PERMISSION_TYPE);
			// byte boardReplyPolicyTypeValue = boardInforRecord.get(SB_BOARD_INFO_TB.REPLY_POLICY_TYPE);
 
 
			BoardListType boardListType = null;
			try {
				boardListType = BoardListType.valueOf(boardListTypeValue);
 
				PermissionType.valueOf("본문 쓰기", boardWritePermissionTypeValue);
			} catch (IllegalArgumentException e) {
				try {
					conn.rollback();
				} catch (Exception e1) {
					log.warn("fail to rollback");
				}
 
				String errorMessage = e.getMessage();
				throw new ServerTaskException(errorMessage);
			}			
 
 
			int total = create.select(SB_BOARD_INFO_TB.CNT).from(SB_BOARD_INFO_TB)
					.where(SB_BOARD_INFO_TB.BOARD_ID.eq(boardID)).fetchOne(0, Integer.class);
 
			SbBoardTb a = SB_BOARD_TB.as("a");
			SbBoardHistoryTb b = SB_BOARD_HISTORY_TB.as("b");
			SbBoardHistoryTb c = SB_BOARD_HISTORY_TB.as("c");			
 
			HashSet<UInteger> boardNoSet = new HashSet<UInteger>(); 
 
			if (BoardListType.TREE.equals(boardListType)) {
				Table<Record4<UByte, UInteger, UShort, Byte>> d = create.select(a.BOARD_ID, a.GROUP_NO, a.GROUP_SQ, a.BOARD_ST)
						.from(a.forceIndex("sb_board_idx1"))
						.where(a.BOARD_ID.eq(boardID))
						.and(a.BOARD_ST.eq(BoardStateType.OK.getValue()))
						.orderBy(a.GROUP_NO.desc(), a.GROUP_SQ.desc())
						.offset(offset).limit(pageSize).asTable("b");
 
				Result<Record1<UInteger>> boardResult = create
						.select(a.BOARD_NO)
						.from(a).innerJoin(d).on(a.BOARD_ID.eq(d.field(SB_BOARD_TB.BOARD_ID)))						
						.and(a.GROUP_NO.eq(d.field(SB_BOARD_TB.GROUP_NO)))
						.and(a.GROUP_SQ.eq(d.field(SB_BOARD_TB.GROUP_SQ)))
						.and(a.BOARD_ST.eq(d.field(SB_BOARD_TB.BOARD_ST))).fetch();
 
				for (Record1<UInteger> boardRecord : boardResult) {
					UInteger boardNo = boardRecord.get(SB_BOARD_TB.BOARD_NO);
					boardNoSet.add(boardNo);
				}
 
 
			} else {
				Table<Record4<UByte, UInteger, UInteger, Byte>> d = create.select(a.BOARD_ID, a.PARENT_NO, a.BOARD_NO, a.BOARD_ST)
						.from(a.forceIndex("sb_board_idx2"))
						.where(a.BOARD_ID.eq(boardID))
						.and(a.PARENT_NO.eq(UInteger.valueOf(0)))						
						.and(a.BOARD_ST.eq(BoardStateType.OK.getValue()))						
						.orderBy(a.BOARD_NO.desc())
						.offset(offset).limit(pageSize).asTable("b");
 
				Result<Record1<UInteger>> boardResult = create
						.select(a.BOARD_NO)
						.from(a).innerJoin(d).on(a.BOARD_ID.eq(d.field(SB_BOARD_TB.BOARD_ID)))
						.and(a.PARENT_NO.eq(d.field(SB_BOARD_TB.PARENT_NO)))
						.and(a.BOARD_NO.eq(d.field(SB_BOARD_TB.BOARD_NO)))
						.and(a.BOARD_ST.eq(d.field(SB_BOARD_TB.BOARD_ST))).fetch();
 
				for (Record1<UInteger> boardRecord : boardResult) {
					UInteger boardNo = boardRecord.get(SB_BOARD_TB.BOARD_NO);
					boardNoSet.add(boardNo);
				}
 
			}
 
			if (! boardNoSet.isEmpty()) {
				Result<Record13<UInteger, UInteger, UShort, UInteger, UByte, Integer, Byte, Object, String, Timestamp, String, Object, Timestamp>> boardResult = null;
				boardResult = create
						.select(a.field(SB_BOARD_TB.BOARD_NO), a.field(SB_BOARD_TB.GROUP_NO),
								a.field(SB_BOARD_TB.GROUP_SQ), a.field(SB_BOARD_TB.PARENT_NO),
								a.field(SB_BOARD_TB.DEPTH), a.field(SB_BOARD_TB.VIEW_CNT),
								a.field(SB_BOARD_TB.BOARD_ST),
								create.selectCount().from(SB_BOARD_VOTE_TB)
										.where(SB_BOARD_VOTE_TB.BOARD_ID.eq(a.field(SB_BOARD_TB.BOARD_ID)))
										.and(SB_BOARD_VOTE_TB.BOARD_NO.eq(a.field(SB_BOARD_TB.BOARD_NO)))
										.asField("votes"),
								b.SUBJECT, b.REG_DT.as("last_mod_date"), c.REGISTRANT_ID,
								create.select(SB_MEMBER_TB.NICKNAME).from(SB_MEMBER_TB)
										.where(SB_MEMBER_TB.USER_ID.eq(c.REGISTRANT_ID))
										.asField(SB_MEMBER_TB.NICKNAME.getName()),
								c.REG_DT.as("first_reg_date"))
						.from(a)
						.innerJoin(c).on(c.BOARD_ID.eq(a.field(SB_BOARD_TB.BOARD_ID)))
							.and(c.BOARD_NO.eq(a.field(SB_BOARD_TB.BOARD_NO)))
							.and(c.HISTORY_SQ.eq(UByte.valueOf(0)))
						.innerJoin(b).on(b.BOARD_ID.eq(a.field(SB_BOARD_TB.BOARD_ID)))
							.and(b.BOARD_NO.eq(a.field(SB_BOARD_TB.BOARD_NO)))
							.and(b.HISTORY_SQ.eq(create.select(b.HISTORY_SQ.max()).from(b)
								.where(b.BOARD_ID.eq(a.field(SB_BOARD_TB.BOARD_ID)))
								.and(b.BOARD_NO.eq(a.field(SB_BOARD_TB.BOARD_NO)))))
						.where(a.BOARD_ID.eq(boardID))
						.and(a.BOARD_NO.in(boardNoSet))
						.orderBy(a.field(SB_BOARD_TB.GROUP_NO).desc(), a.field(SB_BOARD_TB.GROUP_SQ).desc())
						.fetch();			
 
				for (Record boardRecord : boardResult) {
					UInteger boardNo = boardRecord.getValue(SB_BOARD_TB.BOARD_NO);
					UInteger groupNo = boardRecord.getValue(SB_BOARD_TB.GROUP_NO);
					UShort groupSequence = boardRecord.getValue(SB_BOARD_TB.GROUP_SQ);
					UInteger parentNo = boardRecord.getValue(SB_BOARD_TB.PARENT_NO);
					UByte depth = boardRecord.getValue(SB_BOARD_TB.DEPTH);
					int viewCount = boardRecord.getValue(SB_BOARD_TB.VIEW_CNT);
					byte boardStateValue = boardRecord.getValue(SB_BOARD_TB.BOARD_ST);
					int votes = boardRecord.getValue("votes", Integer.class);
					String subject = boardRecord.getValue(SB_BOARD_HISTORY_TB.SUBJECT);
					Timestamp lastModifiedDate = boardRecord.getValue("last_mod_date", Timestamp.class);
					String firstWriterID = boardRecord.getValue(SB_BOARD_HISTORY_TB.REGISTRANT_ID);
					String firstWriterNickName = boardRecord.getValue(SB_MEMBER_TB.NICKNAME);
					Timestamp firstRegisteredDate = boardRecord.getValue("first_reg_date", Timestamp.class);
 
					if (null == subject) {
						subject = "";
					}
 
					BoardListRes.Board board = new BoardListRes.Board();
					board.setBoardNo(boardNo.longValue());
					board.setGroupNo(groupNo.longValue());
					board.setGroupSeq(groupSequence.intValue());
					board.setParentNo(parentNo.longValue());
					board.setDepth(depth.shortValue());
					board.setWriterID(firstWriterID);
					board.setViewCount(viewCount);
					board.setBoardSate(boardStateValue);
					board.setRegisteredDate(firstRegisteredDate);
					board.setWriterNickname(firstWriterNickName);
					board.setVotes(votes);
					board.setSubject(subject);
					board.setLastModifiedDate(lastModifiedDate);
 
					// log.info(board.toString());
					boardList.add(board);
				}
			}			
 
			conn.commit();
 
			boardListRes.setBoardID(boardID.shortValue());
			boardListRes.setBoardName(boardName);
			boardListRes.setBoardListType(boardListTypeValue);	
			boardListRes.setBoardWritePermissionType(boardWritePermissionTypeValue);
			boardListRes.setPageNo(pageNo);
			boardListRes.setPageSize(pageSize);
			boardListRes.setTotal(total);
			boardListRes.setCnt(boardList.size());
			boardListRes.setBoardList(boardList);
		});
 
		return boardListRes;
	}
}