본문 바로가기
작디 작은 나만의 라이브러리/EPSON 써멀 프린터 라이브러리

[신입 개발자의 '0' 번째 라이브러리] 프린터 상태 관리와 예외 처리 - EPSON 써멀 프린터 라이브러리 제작기(4)

by 시니성 2024. 12. 16.
728x90

들어가며

지난 글에서는 EPSON 써멀 프린터 라이브러리의 출력 기능 구현에 대해 살펴보았습니다.
이번 글에서는 프린터의 상태 관리와 예외 처리 시스템에 대해 상세히 분석해보겠습니다.

프린터는 하드웨어 장비이기 때문에 다양한 상태와 오류 상황이 발생할 수 있습니다.
용지 부족, 덮개 열림, 전원 문제 등 여러 상황에 대한 적절한 대응이 필요합니다.
이를 위해 라이브러리는 다음과 같은 구조를 가지고 있습니다:

  1. 상태 enum 클래스를 통한 프린터 상태 표현
  2. 각 연결 방식별 상태 체크 메커니즘
  3. 커스텀 예외 클래스들을 통한 에러 처리

1. 프린터 상태 관리 시스템

T83IIIPrinterStatus Enum 클래스

enum class T83IIIPrinterStatus(val message: String) {
    /** 프린터가 정상적으로 작동하는 상태 */
    NORMAL("정상"),

    /** 회복이 불가능한 오류 상태 */
    UNRECOVERABLE_ERROR("회복 불가능한 오류"),

    /** 프린터가 연결되지 않은 상태 */
    DISCONNECTED("연결되지 않음"),

    /** 프린터 뚜껑이 열린 상태 */
    COVER_OPEN("프린터 뚜껑 열림"),

    /** 용지가 없는 상태 */
    PAPER_OUT("용지 없음"),

    /** 용지가 거의 다 떨어진 상태 */
    PAPER_NEAR_END("용지 거의 다 떨어짐"),

    /** 용지가 걸린 상태 */
    PAPER_JAM("용지 걸림"),

    /** 프린터가 오프라인 상태 */
    OFFLINE("오프라인"),

    /** 프린터가 과열된 상태 */
    OVERHEATED("과열"),

    /** 용지 절단기에 문제가 있는 상태 */
    CUTTER_ERROR("용지 절단기 오류"),

    /** 기계적 오류 상태 */
    MECHANICAL_ERROR("기계적 오류"),

    /** 알 수 없는 상태 */
    UNKNOWN("알 수 없음")
}

상태 enum의 특징:

  1. 명확한 상태 구분과 메시지
  2. 상태별 처리 메서드 제공
  3. 한글 메시지를 통한 사용자 친화적 에러 처리

상태 유틸리티 함수들

fun T83IIIPrinterStatus.isError(): Boolean = this != T83IIIPrinterStatus.NORMAL
fun T83IIIPrinterStatus.isNormal(): Boolean = this == T83IIIPrinterStatus.NORMAL
fun T83IIIPrinterStatus.isDisconnected(): Boolean = 
    this == T83IIIPrinterStatus.DISCONNECTED
fun T83IIIPrinterStatus.toException(): T83PrinterException = 
    T83PrinterException(causeMessage = this.message)

// 프린터 상태 체크 확장 함수
private fun PrinterStatusInfo.isNormal(): Boolean =
    this.connection.isTrue()
            && this.errorStatus.isNoError()
            && this.coverOpen.isFalse()
            && this.paper.isOk()

2. 연결 방식별 상태 체크 구현

NetworkPrinterAdaptor의 상태 체크

object NetworkPrinterAdaptor : T83PrinterAdaptor() {
    override fun validationCheck(): Result<Unit> {
        try {
            connect()
            Thread.sleep(100)
            disconnect()
        } catch (e: Exception) {
            return Result.failure(e)
        }
        return Result.success(Unit)
    }
}

네트워크 프린터 상태 체크의 특징:

  1. 연결 테스트를 통한 상태 확인
  2. Result 타입을 통한 에러 처리
  3. 적절한 대기 시간 설정

AndroidSerialPrinterByteArrayAdapter의 상태 체크

class AndroidSerialPrinterByteArrayAdapter(
    private val printer: Printer,
) : T83PrinterAdaptor() {
    override fun validationCheck(): Result<Unit> = runCatching {
        when (val status = printer.status.toEnum()) {
            T83IIIPrinterStatus.NORMAL -> Unit
            else -> throw status.toException()
        }
    }

    fun getStatusDetail(): PrinterStatusInfo = ePos2ExceptionWrapper {
        printer.status
    }
}

안드로이드 프린터 상태 체크의 특징:

  1. EPSON SDK의 상태 정보 활용
  2. 상세한 상태 정보 제공
  3. 커스텀 예외 변환 처리

3. 커스텀 예외 시스템

기본 예외 클래스

class T83PrinterException(
    causeMessage: String = "알 수 없음", 
    cause: Exception? = null
) : Exception("T83III 프린터 오류 발생 ($causeMessage)", cause)

class EPos2ExceptionWrapperException(
    val status: Int,
    message: String,
    cause: Exception,
) : Exception(message, cause)

기능별 예외 클래스들

class IllegalKeycodeException: IllegalArgumentException(
    "올바른 프린터 이미지 키 코드 값이 아닙니다."
)

class ImageLoadFailException: FileNotFoundException(
    "이미지를 불러오는 데 실패했습니다."
)

class UnsupportedBarcodeException : UnsupportedOperationException(
    "해당 바코드 타입을 지원하지 않습니다."
)

class UnsupportedFontException: UnsupportedOperationException(
    "해당 폰트 스타일을 지원하지 않습니다."
)

예외 시스템의 특징:

  1. 명확한 에러 메시지
  2. 예외 계층 구조
  3. 원인 예외 보존

예외 래퍼 유틸리티

internal fun <T> ePos2ExceptionWrapper(block: () -> T) = try {
    block()
} catch (e: Epos2Exception) {
    throw EPos2ExceptionWrapperException(
        e.errorStatus, 
        "occurred Epos2Exception.. status(${e.errorStatus})", 
        e
    )
} catch (e: Exception) {
    throw e
}

예외 래퍼의 특징:

  1. SDK 예외의 일관된 변환
  2. 상태 코드 보존
  3. 스택 트레이스 유지

4. 상태 관리와 예외 처리의 활용

AndroidSerialPrinter에서의 활용

class AndroidSerialPrinter(
    printer: Printer,
    config: AndroidSerialPrinterConfig = AndroidSerialPrinterConfig(),
    beforePrint: () -> Unit = { },
    afterPrint: () -> Unit = { },
) : BlockingPrinter(config, beforePrint, afterPrint) {

    init {
        adaptor.connectionType = config.connectionType
        adaptor.address = config.address
        adaptor.deviceId = config.deviceId
        adaptor.timeout = config.timeout
        runCatching { 
            adaptor.connect() 
        }.onFailure { 
            logger.error("Failed to connect printer", it) 
        }
    }

    fun getStatusDetail(): T83IIIPrinterStatus = 
        adaptor.getStatusDetail().toEnum()
}

활용 특징:

  1. 초기화 시점의 안전한 연결 처리
  2. 로깅을 통한 문제 추적
  3. 상태 정보의 일관된 변환

상태 관리와 예외 처리의 이점

1. 안정성

  • 하드웨어 상태 모니터링
  • 예외 상황의 체계적 처리
  • 연결 상태 관리

2. 사용자 경험

  • 명확한 에러 메시지
  • 상태별 대응 방안 제시
  • 일관된 에러 처리

3. 개발 편의성

  • 상태 체크 자동화
  • 예외 처리 표준화
  • 디버깅 용이성

마치며

프린터의 상태 관리와 예외 처리 시스템은:

  1. 명확한 상태 정의
  2. 체계적인 예외 처리
  3. 일관된 에러 메시지

를 통해 안정적이고 사용자 친화적인 프린터 제어를 가능하게 합니다.

다음 글에서는 어느덧 1년이 지난 지금 시점에서 이 라이브러리를 돌아보며, 아쉬운 점과 개선할 점에 대해 이야기해보도록 하겠습니다.

728x90