Ch 1. Basics
이장의 내용은 자바 문법 중에서 실행문의 문법을 요약한 것이다. C 언어 복습이라고 할 수 있다.
[Example 1-1. Hello.java] : 이거 모르면 바보
[Example 1-2. FizzBuzz.java] : 미국 판 369 게임이라고나 할까...
[Example 1-3. Fibonacci.java] : 피보나치 수열 출력
[Example 1-4. Echo.java] : command-line argument
[Example 1-5. Reverse.java] : command-line argument
[Example 1-6. FizzBuzz2.java] : switch 문
[Example 1-7. Factorial.java] : for loop 사용법
[Example 1-8. Factorial2.java] : recursive function
[Example 1-9. Factorial3.java] : cashing (계산한 값 보관해놓기)
[Example 1-10. Factorial4.java] : BigInteger class
[Example 1-11. FactComputer.java] : exception handling
[Example 1-12. FactQuoter.java] : 간단한 io
[Example 1-13. Rot13Input.java] : StringBuffer class
[Example 1-14. SortNumbers.java] : selection sort
[Example 1-15. Sieve.java] : prime number 구하기
Ch 2. Objects, Classes, and Interfaces
이장의 내용은 객체지향 관점에서의 자바 문법을 요약한 것이다. 자료추상화의 의미를 다시 한 번 확인해 보는 내용이다.
(자료추상화 : 여러 자료형을 하나로 묶어(단순화하여) 더 높은 단계로 정의하는(추상화하는) 것. / 내가 이해하기로는 property나 method들을 하나의 단위로 묶은 것(class화 한 것) = 자료 추상화인듯. 자료추상화의 장점으로는 외부로부터 내부 자료를 함부로 접근하지 못하게 함. (자료형에 대한 의도되지 않은 변화를 최소화, 캡슐화나 정보 은닉이라고도 함) / 자료추상화에 의해 비로소 객체지향 프로그래밍 기법이 가능하게 됨)
[Example 2-1. Rect.java] : 사각형 정보를 클래스에 담아 보기
[Example 2-2. RectTest.java] : Rect 클래스를 사용하는 메인 클래스
[Example 2-3. DrawableRect.java] : Rect 클래스의 파생 클래스 작성 예 <read only>
[Example 2-4. ColoredRect.java] : 또 다른 파생 클래스의 예 <read only>
[Example 2-5. ComplexNumber.java] : 복소수를 클래스로 표현해 보기 <read only>
[Example 2-6. Averager.java] : static inner 클래스로 작성된 메인 프로그램 실행 예
[Example 2-7. IntList.java] : a growable array, Vector와 비슷한 클래스 <read only>
* assert 문 소개 (Java 1.4부터 도입)
[Example 2-8. Tokenizer.java] : 입력 스트림을 토큰 별로 인식하는 클래스를 만들기 위한 (범용성 있는) 인터페이스
[Example 2-9. AbstractTokenizer.java] : Tokenizer를 구현하는 클래스
* 범용성은 있지만 아주 지저분함
[Example 2-10. CharSeqenceTokenizer.java] : 예제 2-8, 2-9의 사용 예
* Java 1.5로 컴파일하고 실행할 것
* 원본은 command line argument를 이용하지만 내가 바꿨음
Ch 3. Input/Output
이 장에서는 입출력과 관계되는 API 클래스들 소개하고 있다.
- 파일에 쓰기, 일기
- 디렉토리 내용 보기, 파일 정보 보기
- 스트림 클래스들 사용하기
- 사용자 정의 스트림 클래스 만들기
- File 클래스의 특징: 파일 정보만을 다루며 파일 내용을 다루는 것이 아니다.
- 바이트 단위 입출력: InputStream, OutputStream
- 유니코드 문자 단위 입출력: Reader, Writer
[Example 3-1. Delete.java] : 파일 지우기
[Example 3-2. FileCopy.java] : 파일 복사하기
[Example 3-3. FileViewer.java] : 간단한 파일 보여주기 도구
[Example 3-4. FileLister.java] : 디렉토리 안의 파일 리스트하기와 파일 정보 보여주기 도구
[Example 3-5. Compress.java] : 파일 압축하기
[Example 3-6. RemoveHTMLReader.java] : 문자 스트림 필터링 예제 - HTML 태그들을 필터링하여 제거하는 프로그램
[Example 3-7. ReaderTokenizer.java] : 파일 리더를 입력으로 토큰화하는 프로그램
[Example 3-8. WordList.java] : 랜덤 엑세스 파일 만들어보기
Ch 4. Threads
이장에서는 스레드와 관련된 기초 내용을 다룬다.
- 스레드는 독립적으로 실행되는 프로그램 단위이다. (cf.) 프로세스.
- java.lang.Runnable 인터페이스 이용 시에 run() method 사용
- java.lang.Thread 클래스 사용 시에는 관련 메소드들을 이용
- synchronized modifier 를 이용하여 코드 블록 보호
- java.lang.Object 클래스의 wait()를 이용하여 서스펜드 시키거나 notify()를 이용하여 다시 실행 시킬수 있음
[Example 4-1. ThreadDemo.java] : 스레드 만들어보기 (priority, run(), join(), sleep(), yield())
[Example 4-2. ThreadSafeIntList.java] : synchronized method의 필요성 <read only>
* 객체의 상태 변화를 동시에 시도하는 것을 방지
* safe but inefficient (overhead of object locking)
* java.util.Vector : safety 보장
* java.util.ArrayList : efficient unsynchronized alternative
[Example 4-3. ThreadLister.java] : 스레드 그룹과 스레드 정보 리스트하기
[Example 4-4. Deadlock.java] : deadlock 시범
* deadlock을 피하는 한 가지 방법은 모든 스레드가 똑같은 순서에 의해 자원을 획득하도록 하는 것이다.
[Example 4-5. TimerTask.java] : java.util.TimerTask 추상 클래스
[Example 4-6. Timer.java] : java.util.Timer 클래스
* Test class의 메인 함수에서 타이머의 사용법을 주로 볼 것
Ch 5. Networking
Java는 SUN Microsystems에서 Device Independent 개념으로 만든 언어이다. 이런 SUN사의 창립이념은 “Network is Computer”이다. 즉 “네트워크는 컴퓨터이다”는 주장인데, 그런 만큼 Java에서는 network에 대한 막강한 지원을 제공한다. 여기서는 이러한 je3.net API에 대해 알아볼 것이다.
net 클래스는 네트워크를 통해 이루어지는 대부분의 작업을 지원한다. 이러한 네트워크 부분은 크게 address classification, data transfer 부분으로 나뉘어진다. 우리가 흔히 사용하는 URL을 이용한 대상지정법은 Java에서 가장 편리하게 사용할 수 있는 network 클래스 중 하나이다. URL을 이용하여 서버에 있는 http, ftp등의 문서를 편리하게 얻어올 수 있다. 이러한 URL은 상당히 강력한 기능을 제공해서 개발자로 하여금 SUN의 개발팀에게 감사의 인사를 전하게 만드는데, 바로 ANSI표준 URL을 모두 지원한다는 것이다. 이는 ftp를 통한 파일전송, mailto: 헤더를 이용한 메일 전송, gopher, https 등의 부분을 알아서 처리해줘서 개발자의 수고를 덜어준다. 하지만 이런 URL을 사용할 수 없을 때가 있다. 바로 전용의 서버/클라이언트를 제작하는 등의 일을 할 경우이다. 예를 들어 클라이언트가 서버에게 “Give me money 1000” 이라고 보냈고, 서버가 이에 대한 응답으로 “Give money 1000”을 전송했다면 이러한 부분은 표준 프로토콜을 따르지 않는다고 할 수 있다. 이러한 것은 대부분의 다른 언어에서도 사용하는 Socket을 이용하여 프로그래밍 할 수 있다. 이러한 Socket이 다룰 수 있는 유형은 크게 두 가지로 나뉘어진다. 하나는 TCP이며 하나는 UDP이다. TCP는 전송의 신뢰성을 어느 정도 보장하는 방법으로서 데이터를 보낸 후, 제대로 받았는지 확인(Ack)하고, 만약 문제가 있으면 재전송하는 구조를 취한다. 그 때문에 TCP는 저속의 통신환경에서는 상당히 느리며, 작은 데이터를 전송하기엔 오버헤드가 매우 크다. 반면에 UDP는 전송 오류 확인을 하지 않음으로서, 고속의 데이터 전송을 보장한다. 이는 데이터가 늦으면 그 가치가 크게 떨어지는, 즉 실시간성의 요구되는 VOD서비스 등에서 사용하는 대표적인 프로토콜이다.
기본적으로 네트워크는 C/S(Client/Server) 구조로 이루어져 있다. 이러한 구조에서 Java는 주로 클라이언트로서 동작하지만 그 강력한 네트워크 지원 때문에 Sun에서는 J2EE라는 엔터프라이즈 플랫폼용 Java를 만들기에 이르렀다. 하지만 이만큼의 고급 기술법 없이도 Java에서 서버를 구현하는 것은 매우 쉽다.
Java는 기본적으로 멀티쓰레드 프로세싱을 지원하기 때문에, 각 쓰레드가 하나씩의 클라이언트 요청에 대해 응답하는 구조로 간단한 서버를 구현할 수 있다. 이를 이용해서 수많은 사용자의 요청을 처리할 수 있게 된다.
이장의 주요 내용은 다음과 같다.
- URL 클래스 사용법
- URLConnection 클래스를 이용하여 network 자원 다운 받기
- Socket을 이용한 클라이언트 프로그래밍
- Socket과 ServerSocket을 이용한 서버 프로그래밍
- datagram을 이용한 통신
[Example 5-1. GetURL.java] : URL 내용 다운 받기
[Example 5-2. GetURLInfo.java] : URL 정보 알아내기
[Example 5-3. SendMail.java] : mailto: 프로토콜을 이용하여 메일 보내기
[Example 5-4. Connect.java] : Socket을 이용한 간단한 클라이언트
[Example 5-5. GenericClient.java] : Socket을 이용한 간단한 범용 클라이언트
* java -cp ..\.. je3.net.GenericClient taejo.pufs.ac.kr 110
* Connected to taejo.pufs.ac.kr/203.203.71.222:110
* +OK empal POP3 server ready
* USER ktg
* +OK hello ktg?
* PASS ******
* +OK ktg's mailbox opened. 256 messages
* RETR 1
* ---------- message ---------
* QUIT
* +OK empal POP server signing off (256 messages left)
* Connection closed by server.
[Example 5-6. HttpClient.java] : HTTP 클라이언트
* https: 프로토콜도 처리할 수 있음 (근데 https가 뭐지 ?)
* 여러줄의 request를 보낼 수 있음
* 서버 응답의 헤더 부분과 내용 부분을 분리
[Example 5-7. PopClean.java] : 메일을 리스트하거나 옵션에 따라 지우는 POP3 클라이언트
[Example 5-8. HttpMirror.java] : 클라이언트의 리퀘스트를 되돌려 주는 간단한 서버
* 서버를 작동 시킨 뒤 브라우져에서 http://localhost:4444/testing.html 이라고 칠 것
[Example 5-9. SimpleProxyServer.java] : 간단한 프록시 서버
* 서버를 작동 시킨 뒤 브라우져에서 http://localhost 혹은 http://203.230.65.56 (서버가 작동하는 컴퓨터의 IP) 이라고 칠 것
[Example 5-10. Server.java] : 범용 서버
* Server.Service 인터페이스를 구현하는 서비스(예, 타임, 리버스 서비스) 클래스의 기능을 제공
* Control 서비스를 이용하여 동적으로 서비스를 로드하거나 제거할 수 있음
* 서버를 작동 시킨 뒤 클라이언트 용 도스 창을 띄운 뒤 GenericClient 를 이용하여 접속
* 타임 서비스 이용 경우 :
java -cp ..\.. je3.net.GenericClient localhost 3001
* reverse 서비스 이용 경우 :
java -cp ..\.. je3.net.GenericClient localhost 3002
* control 서비스를 이용하여 서버에 명령할 수 있음 (password, add, remove, max, status, help, quit) java -cp ..\.. je3.net.GenericClient localhost 3000
[Example 5-11. UDPSend.java] : UDP (Unreliable Datagram Protocol) 데이터그램 보내기
* 당연한 야그지만 UDPReceive 를 먼저 실행 시킨 후 이걸 실행 시킬 것
[Example 5-12. UDPReceive.java] : UDP (Unreliable Datagram Protocol) 데이터그램 받기
Ch 6. New I/O
New I/O는 서버나 다른 애플리케이션에서 고성능의 입출력을 처리하게 하기 위하여 JDK 1.4에 새로 추가된 API이다. New I/O는 java.nio 패키지로 제공되는 기능으로 크게 버퍼관리 클래스들, 확장된 네트워크 그리고 파일 I/O, 문자 집합 지원, 그리고 정규식 문자 표현에 새로운 특징들과 개선된 성능을 제공한다.
nio의 패키지 들은 다음과 같다.
java.nio.package : 자바 기본행 유형에 맞는 버퍼 클래스들
java.nio.channels.package : 채널과 셀렉터
java.nio.charset.package : 문자 암호화들,
java.nio.channel.spi.package : Service 프로바이더는 채널들을 위해 분류
java.nio.charset.spi.package : Service 프로바이더는 문자-set을 위해 분류
java.util.regex.package : 정규식들에 의해서 지정된 패턴들에 대해서 문자 표현에 대한 클래스들
java.lang.charSequence.interface : 다양한 종류의 문자 순서에의 통일된 read 전용 액세스 제공
와 같은 일을 한다.
java.nio 패키지에서 눈여겨 봐둘 것은 지금까지 지원이 되지 않았던 io의 논블록킹의 지원이다. 이러한 논블로킹의 지원으로 쓰레드는 더 이상 읽기나 쓰기에 블로킹 되지 않으며, selector의 도입으로 클라이언트의 많은 접속을 처리할 서버의 부하가 상당히 줄어들게 되었다. 또한 java.nio 패키지는 네트워크 기능이 강화되었는데 채널의 도입으로 강화된 새로운 기능들을 사용하려면 이와 연관된 java.net 패키지를 참조해한다. java.nio는 크게 버퍼류 패키지와 채널류 패키지로 나눌 수 있다. 이들은 모두 Buffer클래스를 상속받고 버퍼클래스는 여러 종류가 있어서 각각 기본형 데이터에 맞는 클래스들이 존재한다.
nio에서의 큰 특징은 채널의 도입이다. 채널의 도입으로 인해 사용법은 다소 복잡해지더라도 성능이 향상되었다고 한다. 채널의 사용은 크게 파일 처리와 통신 처리의 두 가지 용도로 사용되며 이장의 구조도 이 두 가지 사용 방식에 맞춰 설명되어 있다. 즉 처음에는 주로 파일 처리 시의 채널 사용법을 설명하고, 나중에는 주로 통신 처리 시의 채널 사용법을 설명한다. 채널은 무조건 바이트버퍼의 사용과 연관되어 있기 때문에 버퍼에 받은 후에는 사용자 필요에 따라 문자버퍼나 다른 형태의 버퍼로 변환하는 과정이 필요하다. 파일 처리의 경우에 채널은 버퍼의 사용없이 입력을 출력방향으로 통째로 redirect 하는 것이 가능하며 논블럭킹으로 인한 효율성을 달성하는 장점을 갖는다. 통신의 경우에 채널은 서버와 클라이언트간의 통신수단을 나타낸다. 채널은 비동기적으로 닫히고 중단 될 수 있는데, 따라서 한 쓰레드가 한 채널에서 하나의 입출력 작업으로 블록화되면 다른 쓰레드가 그 채널을 닫을 수도 있다. 그래서 파일입출력에서 블록화된 쓰레드를 언제든지 중지시킬 수 있으며, 이를 이용해서 네트워크의 non-blocking입출력이 가능하다. 통신 시에 채널을 도입함으로써 얻을 수 있는 장점은 과거에 멀티쓰레드로 구현되어야 할 기능들이 채널과 Selector 객체의 이용을 통하여 싱글쓰레드 어플리케이션으로 만들어질 수 있다는 것이다.
어쨌건 nio의 특징을 요약하면,
- 네트웍 채널은 nonblocking mode 로 사용되며
- Selector를 이용하여 여러개의 nonblocking 채널을 멀티플렉스화 함으로써 단일쓰레드를 이용해서도 여러 통신을 유지할 수 있고
- 파일들이 메모리에 매핑될 수도 있으며
- file들에 대한 배타적인 locking이 가능하고
- character set에 대한 인코딩과 디코딩 시의 좀더 효율적인 서비스도 제공되며
- 정규표현과 관련한 서비스도 제공한다.
[Example 6-1. Lock.java] : 임시 파일에 lock을 걸기 (lock을 이용하여 동시에 두 어플리케이션을 실행하는 것을 방지함, OS에 따라 lock된 파일의 내용을 읽을 수 있기도 하고 읽을 수 없기도 함)
[Example 6-2. FileCopy2.java] : 채널을 이용한 파일 복사
* 버퍼를 이용하지 않고 왕창 보냄 (transferTo() 함수)
[Example 6-3. BGrep.java] : java.util.regex 패키지를 이용한 정규표현(regular expression) 다루기
* 채널로부터 받은 데이터를 메모리 맵에 복사하기 FileChannel.map() 함수
* 바이트버퍼를 문자버퍼로 변환 Charset.decode() 함수 [채널은 바이트버퍼 만을 이용하기 때문에 ...]
* 매치시키기 : Pattern.mactch() 함수 + Matcher.find() 함수
[Example 6-4. FileCopy3.java] : 채널을 이용하면서 바이트버퍼를 이용한 파일 복사
* 버퍼의 내용을 다 소비하지 않고 블럭된 경우의 대처 방식을 유심히 볼 것 (compact() 함수 이용)
[Example 6-5. ChannelToWriter.java] : 바이트를 문자로 변환하기
* Charset.decode() 메소드보다 하위 수준이지만 성능이 좋은 CharsetDecoder 클래스 이용
[Example 6-6. ByteBufferTokenizer.java] : abstract class 임 (6-7, 6-8의 슈퍼 클래스로 사용됨)
[Example 6-7. MappedFileTokenizer.java] : FileChannel 객체로부터 만들어지는 바이트버퍼의 내용을 토크나이즈하기
[Example 6-8. ChannelTokenizer.java] : 아무 ReadableByteChannel 객체로부터 만들어지는 바이트버퍼의 내용을 토크나이즈하기 (아마도 이 클래스는 통신 채널로 들어오는 입력을 토크나이즈하기 위해 사용될 수 있는 것으로 보임, 단 실행 파일의 예제는 6-7과 동일 함)
[Example 6-9. HttpGet.java] : 간단한 HTTP 클라이언트
* 서버와의 통신을 위해 SocketChannel 객체 이용
* 다운 받은 내용의 저장을 위해 FileChannel 객체 이용
[Example 6-10. SimpleDaytimeServer.java] : ServerSocketChannel을 사용하는 간단한 TCP 서버
* 디폴트로 13 포트 사용
* 6-12가 클라이언트이기는 하지만 그 클라이언트는 데이터그램을 이용하기 땜시 이 서버를 사용할 수 없음 (이 프로그램을 테스트하기 위해서는 GenericClient를 이용해 볼것)
* 즉 net 디렉토리로 이동 후, java -cp ..\.. je3.net.GenericClient localhost 13 실행
[Example 6-11. SimpleDaytimeServer.java] : Selector.select() 메소드를 이용하여 싱글 스레드로 구현된 TCP & UDP 서버
* 만약 nio가 아니라 이전 기술을 이용하는 경우에는 TCP 커넥션을 위해서 하나의 스레드를 돌리고, UDP 커넥션을 위해서 다른 하나의 스레드를 돌려야 함
[Example 6-12. DaytimeClient.java] : 데이터그램을 이용하는 Daytime 클라이언트
[Example 6-13. PrinterServiceWebInterface.java] : 멀티플렉스 서버
* 프린터 정보를 알려준다는데 하는 일은 중요하지 않음
* 6-12 서버와 달리 command based 서버임 (바로 응답 만하는 서버가 아님)
* 그럼에도 불구하고 멀티스레드를 이용하지 않고 싱글스레드로 만들어짐
* 역시 Selector 이용
* 클라이언트 접속이 있을 때마다 SocketChannel을 Selector에 새로 등록하고 ... 사용하다가 접속이 끊어지면 그 채널을 Selector에서 제거하는 방식으로 운영됨
* 8000 포트를 이용하니깐 GenericClient를 이용하여 테스트해 볼 것 (명령어는 아무 글자를 치면 되고 ...)
* 즉 net 디렉토리로 이동 후, java -cp ..\.. je3.net.GenericClient localhost 8000
* 그 다음에 원래는 GET 명령어를 쳐야 논리적으로 의미가 있으나 이 프로그램은 명령어를 파싱하지 않고 무조건 결과를 돌려주기 땜시 아무 글자를 치면 됨
[Example 6-14. HttpDownloadManager.java] : 멀티플렉스 클라이언트
* 이유는 모르겠지만 됐다 안됐다 ... 약간 불안함
Ch 7. Security & Cryptography
Java의 보안 기술에는 Access Control과 Authentication(인증)이 있다. 이러한 기능을 가진 class들은 모두 java.security package 안에 있다. Access Control이란 믿을 수 있는 code에만 실행시 어떤 서비스를 하는 것을 허락하는 것을 일컫는다. 믿을 수 있는 code인지 아닌지는 Authentication을 이용해서 확인한다. Cryptography는 암호화, 복고화기능을 말하는데 이러한 기능들은 javax.crpto package 안의 class들이 가지고 있다. 이 cryptography는 보안기술과 밀접한 관계를 가지고 있는데 이는 Authentication에서 digital signature를 만드는데 암호화가 쓰이기 때문이다.
(1)Access Control
Access Control은 Security Manager 와 Access Controller란 Clsss로 이루어진다. Security manager가 등록되면 실행시 Java는 각 연산이 허용되는지 안 되는지를 체크한다. 이러한 체크는 Security Manager가 Access Controler을 이용해서 하는데 Access Controller은 확장명 policy인 파일을 읽어 허용된 사항들을 파악한다.
Java interpreter를 이용할 때에 -Djava.security.manager란 것을 붙이면 Security manager가 등록된다. 만일 -Djava.security.policy = <policy 파일명>을 해주지 않으면 default security manager가 등록되는데 이 security manager 는 허용하는 것이 별로 없어서 보안 상태가 너무 tight하게 된다. Java interpreter 의 매크로 옵션를 쓰지 않고 code 자체에 Security Manager를 하나 instantiation 함으로써 Security Manager를 등록할 수도 있다.
Policy 파일에는 grant codeBase “<적용되는 Code의 URL>”{<Permission으로부터 상속 받은 class명> “<그 class의 Constructor의 Parameter>” ...}라고 명시 해주면 된다. Permission으로부터 상속받은 class는 java.lang.RuntimePermission, java.io.FilePermission, java.net.SocketPermission등이 있다.
(2)Authentication
인증에는 digital signature, message digest, keystore의 세가지 요소로 구성된다. keystore은 파일을 인증할 권한이 있는 사람들의 별명(Alias)과 그에 해당하는 public key, private key가 저장되어 있다. 요전 시스템이 가지고 있다. private key를 이용해서 파일명과 파일의 message digest를 내용으로한 signature를 만들고 그 signature와 messege digest를 MANIFEST 파일에 저장하여 인증된 파일인지 확인할 때 쓴다. messege digest는 일정한 알고리즘으로 요약한 것이라 볼 수 있다. keystore은 Java 환경의 제공하는 keytool이란 명령어로 만들 수 있다. 그리고 keystore을 access 하기 위해서는 또한 keystore에 해당하는 암호를 알아야 한다.
(i)Key Store
key store을 읽을 수 있는 기능을 가진 class로 keystore.getInstance(<keystore의 type명>)이란 static member function으로 instantiation 한 다음 load(<inputstream>, <keystore를 읽을수있는암호>)란 함수로 keystore 읽을 수 있다. getkey(<alias명>, <alias만 있는 암호:privatekey를 받을수 있는 암호>)를 통해 private key 객체 하나를 받을 수 있다. getCertiticate(<alias명>).getPuliskey()는 Publickey를 return 시킨다.
(ii)Signature
signature를 만들고, signature가 제대로 되어 있는지 확인하는 기능을 가진 class다, getInstance(<알고리즘명>)을 통해 instantiation 할 수 있다.
signature 만드는법
initSign(<Privatekey>); Update(<signature내용의 byte형>);... sign(); <-signature를 byte형으로 return
제대로된 signature인지 확인하는 법
initVerify(<Publickey>); Update(<signature내용의 byte형>);... verify(<signature인지 확인할 byte 형>); <-boolean형으로 결과 return
(iii)DigestInputStream, DigestOutputStream
messge digest를 만들거나 읽을 수 있는 InputStream, OutputStream의 Subclass다.
(3)Cryptography
(i)Cipher
암호화 및 복고화를 하는 기능을 가진 class로 init(Cipher.ENCRYPT_MODE, <Seretkey>), init(Cipher.DECRYPT_MODE, <secretkey>)로 암호화, 복고화의 초기화를 할수 있다. 그리고 CrpherINputStream, CipherOutputStream으로 암호화 복고화를 할 수 있다.
(ii)Key Generator
getInstance(<알고리즘명>)으로 instantiation한다음 generatekey()로 Secretkey를 생성할수있다.
(iii)SecretKeyFactory
Secret key를 keySpec으로 또는 반대로 변환하는 기능을 가진다.
[Example 7-0. policy 파일 사용법] 프로그램이 있는 것은 아님
* SafeServer.policy 파일
* (1) 도스 창을 띄워서 5 장의 net 디렉토리로 옮긴 뒤
* (2) 다음과 같이 쳐서 security manager를 띄운 후
* java -cp ..\.. -Djava.security.manager je3.net.Server -control password 4000
* (3) 또 다른 도스 창을 이용하여 클라이언트를 실행 시키면
* java -cp ..\.. je3.net.GenericClient localhost 4000
* (4) Server 쪽에서 access denied와 관련된 exception이 발생하며 접속이 되지 않는다. (그 이유는 디폴트 시큐리티 메니저의 제약이 넘 타이트하기 땜이다.)
* 그래서 다시 폴리시 파일(SafeServer.policy) 을 이용하여 서버를 실행시키면 ...
* java -cp ..\.. -Djava.security.policy=Server.policy je3.net.Server -control password 4000
-------------------------------------- Server.policy ------------
grant codeBase "file:/lec/JavaExamples3" {
permission java.net.SocketPermission "*:1024-", "listen,accept";
};
-----------------------------------------------------------
* 접속이 되고 잘 돌아간다. (주의사항: 파일 이름에 한글이 적혀있으면 절대 안됨)
[Example 7-1. SafeServer.java] : net 패키지의 서버를 이용하여 만든 임의의 서비스 객체를 로딩할 수 있는 서버
* 이 테스트는 munjong.pufs.ac.kr에서 로드한 경우임 (Time 서비스만)
[Example 7-2. SafeServer.policy] : policy 파일 문법의 예 <read only>
* 로드될 클래스 파일들의 access property들을 명시함
[Example 7-3 SecureService.java] 서비스 파일 작성 예 (access 허용 체크가 목적임)
* 이 작업을 테스트하려면 시큐리티 메니저를 로드해야함
* 글고, 디렉토리를 만들어야 함 C:\tmp\services 와 C:\tmp\scratch
## 주의 : 테스트해본 결론적으로 윈도에서는 잘 안 먹히는 거 같음
## 메니저를 이용하면 클래스로더가 특히 SecureService 클래스를 찾지 못함(내가 잘못 했을 수도 있고 ... 그렇다고 유닉스에서 해보기도 귀찮고 ...)
[Example 7-4 Manifest.java] message digests and digital signatures
* message digest : 파일이 손상 혹은 침범되었는가를 확인하는 용도
* digital signature : manifest 파일이 수정되어졌는가를 확인하는 용도
* 프로그램 실행 전에 keytool을 이용해서 패스워드 만들 것
* keytool -genkey -alias kim
* keystore 암호를 입력하십시오: kimkim
* ... kimkim2
* make7-03-1, 2, 3을 실행시켜 볼 것 (와중에 TestFile1.txt 을 변경하고)
[Example 7-5 TripleDES.java] file encryption and decryption
* -g 옵션은 키를 담은 파일 생성
* -e 랑 -d 는 키파일의 키를 이용하여 암호화와 해독 실행
* 그런데 이 프로그램은 표준 입출력에서 수행하기 때문에 쓸모는 없음
* 유용한 프로그램으로 만들기 위해서는 네트웍 상에서 써먹어야 할 것 같음
Ch 8. internationalization
internationalization이란 여러 나라에서 프로그램을 상용케 할 때 쓰는 기술이다. 국제화란 뜻을 가진 이 단어는 때로 줄여서 그저 il8n이라도 표기하는데, 그 이유는 영어표기에서 첫글자인 i와 마지막글자인 n의 사이에 18개의 문자가 들어있기 때문이다.
국제화는 제품이나 서비스를 특정지역의 언어나 문화에 맞추는, 즉 현지화라고 불리는 과정을 쉽게 할 수 있도록 계획하거나 이행하는 과정을 말한다. 국제화는 때로 번역 및 현지화능력부여 작업이라고도 불리는데, 여기에는 다음과 같은 것들이 포함된다.
- 하드웨어 레이블이나 도움말 페이지, 온라인 메뉴등 사용자 인터페이스를 설계할 때, 더 많은 수의 글자가 들어갈 때를 대비하여 여유를 둔다.
- 웹에디터나 저작도구 등과 같은 제품을 개발할 때 국제문자셋, 즉 유니코드를 지원할 수 있게 한다.
- 인쇄용 그래픽이미지나 웹사이트를 만들어서 ??? 레이블을 번역할 때 비용이 많이 들지 않게 한다.
- 전세계적으로 통용될 수 있는 예시를 사용한다.
- 소프트웨어의 경우에는, 메시지들이 영어와 같은 단일 바이트 문자코드에서, 한글과 같은 다중 바이트 문자코드로 변환될 수 있도록 데이터 공간을 확보한다.
여기까지는 il8n에 대한 일반적인 설명이었고, 이제 책에 있는 example에 관한 글을 적어보겠다
우선, unicode
자바는 유니코드 캐릭터 인코딩을 사용한다. 유니코드는 사용 중인 플랫폼, 프로그램언어에 관계없이 문자마다 고유한 숫자를 제공한다. 유니코드는 자바에서 널리 사용되는 표준에서 필요하다. 이는 많은 운영체제 요즘 사용되는 모든 브라우저 및 기타 많은 제품에서 지원되는데, 유니코드 표준의 부상과 이를 지원하는 도구의 가용성은 최근 전세계에 불고 있는 기술경향에서 가장 중요한 부분을 차지하고 있다.
유니코드를 클라이언트-서버 또는 다중-연결응용프로그램과 웹사이트에 통합하면 레거시문자세트 사용에 있어서 상당한 비용절감 효과가 나타난다. 유니코드를 통해 엔지니어링 없이 다중 플랫폼, 언어 및 국가 간에 단일 소프트웨어 플랫폼 또는 단일 웹사이트를 목표라 삼을 수 있다. 이를 사용하면 데이터를 손상 없이 여러 시스템에 보낼 수 있고 이로써 internationalization에 이용되는 큰 역할을 발휘한다.
실제로 유니코드가 il8n에 있어서는 많은 부분을 차지한다고 볼 수 있다.
결론
il8n은 국제화에 필수적인 요수이다.
[Example 8-1. UnicodeDisplay.java] : 유니코드 문자를 보여주는 Swing application
[Example 8-2. ConvertEncoding.java] : 특정 인코딩으로 되어 있는 파일을 읽어 다른 인코딩으로 저장하기
* 내 PC에서의 encoding은 MS949 임(default encoding)
* encoding이 불가능한 문자의 경우에는 물음표(?)로 나옴
* encoding 종류: UFT-8 UTF-16 US-ASCII ISO8859-1
[Example 8-3. Portfolio.java] : locale 사용하기
* 로케일 표시법 : <language>_<country> fr_FR, fr_CA, en_US, en_GB ...
* Collator 클래스는 로케일을 고려하여 스트링을 비교함. 따라서 유니코드 문화에서는 소팅과 서치 시에 항상 이 클래스를 이용하는 버릇을 들여야 함. 예를 들어 스페인에서는 ch가 한 개 문자로 취급되며 알파벳 순서 상으로 c와 d 사이라고 함.
* 화면에 나오는 표는 html text 로부터 만들어짐. (참 재미있는 자바야 ... 크 ...)
* command line argument 없이 실행시키면 대 ~ 한 ~ 민 ~ 국 ~~~
* locale 세팅 법 :
유닉스 씨셀경우 % setenv LANG fr_CA
유닉스 셀 경우 $ export LANG=en_GB
윈도 경우에는 제어판에서 Regional Setting(국가별 옵션)
[Example 8-4. SimpleMenu.java] : 리소스 번들을 이용하여 프로그램이 보여줘야 할 텍스트가 커스터마이즈될 수 있도록 하기
* 원본 파일에 리소스 번들 파일 이름이 잘 못 되어있음
* getBundle() 함수가 서치하는 파일 이름의 순서: 파일 이름이 중요함
(1) basename_language_country_variant
(1) basename_language_country
(1) basename_language
(1) basename
[Example 8-5. LocalizedError.java] : 메시지 포맷을 이용하여 에러 메시지 만들어보기
* 원본 파일에 리소스 번들 파일 이름이 잘 못 되어있음
* Errors.properties 파일의 코리안 버전 만들어 보기
Ch 9. Reflection
리플렉션이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법. Reflection의 구체적인 쓰임중 하나가 빌더 툴을 이용해서 소프트웨어 component를 만드는 것. 툴은 Reflection을 사용하여 동적으로 로딩되는 자바 클래스의 속성을 얻을수 있음. → 코드를 사용할 시점에 어떤 타입의 클래스를 사용할지 모르지만, 런타임 시점에 지금 실행되고 있는 클래스를 가져와서 실행해야 하는 경우 사용. 이해한게 맞다면 RTTI기법용으로 사용하는 듯함. Framework나 IDE에서 이런 동적인 바인딩을 이용한 기능을 제공함. IntelliJ의 자동완성 기능, Spring의 Annotation이 Reflection을 이용한 기능. Car x 라는 객체가 있을때, x.drive(100,200) => x는 receiver object, drive는 method, (100,200)은 argument. Reflection에서 가장 중요한 함수는 invoke().
C와 같은 compile 언어에서는 필드명, 메소드명 등의 정보를 주소값으로 만 알 수 있다. 그런데 Java나 C#과 같은 언어는 프로그램을 실행하면서 필드명, 메소드 명 등을 직접 알아낼 수 있는 새로운 기능을 제공한다. 이러한 것을 리플렉션(Reflection)이라고 부른다. 다시말하면, 런타임 시에 이미 로드된 클래스 내에서 다른 클래스를 동적으로 로드하여 생성자, 필드, 메소드 등에 access할 수 있는 기능이다.
Reflection을 하기 위한 가장 기본이 되는 중요한 것은 Java.lang.reflect의 클래스다.
java.awt에 의해 사용되는 것으로 Invocation TargetException(불려간 메소드 또는 constructor에 의해 쓰로우되는 예외를 확인), java.beans에 의해 사용되는 것으로 Method(1개의 메소드에 access)가 있다. 또, java.lang은 Constructor(클래스의 단일 constructor에 대한 정보 및 access 제공), Field(클래스, 인터페이스에 대한 정보 및 access 제공). Method(클래스, 인터페이스에 대한 정보 및 access 제공)을 가능하게 한다. 이 외에도 java.lang.reflect에 의해 사용되는 AccessibleObject, InvocationHandler(proxy instance의 호출 핸들러를 구현), Invocation Target Exception, Method, Member(1개의 멤버나 constructor에 관한 식별정보를 리플랙트 한다.), java.rmi.server에 의해 사용되는 Method, java.swing에 의해 사용되는 Invocation Target Exception 등이 있다. 몇 가지는 중복되기도 한다.
Example 9.1은 클래스 내의 멤버들에 대한 자세한 정보를 Class.forName()에 동적으로 로드한다. 그리고 그 내용을 화면에 표시한다. Example 9.2는 Command class를 정의하는 프로그램인데, Command는 reflection을 효과적으로 사용하는 아주 다양한 기능을 제공한다. 종합하여 보면 reflection은 많은 정보를 제공하는 객체지향적인 tool이라고 할 수 있다. 또한 이 기능은 JavaBeans 기술과 밀접한 연관이 있다. 즉 디자인 패턴 Command Pattern의 기법.
[Example 9-1. ShowClass.java] : 클래스 파일로부터 클래스와 멤버 정보 보기
[Example 9-2. Command.java] : Method 클래스 객체를 이용하여 문자 스프링을 실행 가능한 메소드로 바꾸어보기 (아주 특이한 indirect invocation)
[Example 9-3. CommandProxy.java] : 해시 맵을 이용하여 앞의 예제보다 좀 더 유연하고 일반화된 indirect invocation이 가능하게 한 커맨드 프록시 객체 만들기 (실제 쓸모가 있어보이지는 않음) 포커스를 주었다 뺐었다 해 볼 것
ch 10. object serialization
객체를 시리얼라이제이션 시킨다는 것은 그것의 내부 상태를 byte stream 상태로 저장하여 후에 다시 그것을 읽어서 재구축 할 수 있게 하는 것이다.
객체가 시리얼라이제이션 될 때 그 객체에 연결된 객체들이 모두 시리얼라이제이션 되게 되는데, 그러므로 binary tree와 같은 복잡한 구조를 가진 데이터 구조도 시리얼라이제이션을 할 수 있게 된다. 이것을 이용하면 gui 컴포넌트나 applet도 같이 serialization을 할 수 있다. 또한 이 책에서 serialization도 deep clone 이라는 것을 해주는데 이는 객체를 저장했다 load하는 방법으로 링크를 따라가면서 copy하는 것을 말 한다
serialization은 java.io package에 속하여 있으므로, 이를 사용하기 위하여 이 패키지를 꼭 import하여야 한다. 객체는 ObjectOutputStream class에 속한 writeObject() method를 이용하여 serialization되며 ObjectInputStream class안의 readObject() method에 의하여 deserialization된다. 위에서 언급한 class들로 각각 Object Output과 Object Input Interface를 Implement하며, 이것들은 data output과 data input interface를 implement한다.
serialization 되어야 하는 객체는 java.io.Serializable interface를 꼭 implement 하여야 한다. Serialization 인터페이스는 아무 method도 정의되어 있지 않지만 readObject와 writeObject시 marker interface로 작동한다. writeObject()는 앞에서도 말했듯이 서로 link되어 있는 모든 것을 재귀적으로 serialization 하는데 이 경우 쉽게 infinite recursion 상태에 빠질수 있다. 그러나 이것을 계속 자신이 serialization 하는 것을 저번 것과 비교함으로써 그것을 피한다.
Example 10-1에서는 앞에서 언급한 것과 같이 read와 write를 이용하여 deep clone을 만들고 그것을 통하여 사본을 만든 후 이를 원래의 것과 비교하게 된다.
Serialization을 할 때, 분명 Serialization이 필요 없는 것이 있다. 예를 들면 일시적인 deep copy를 위한 temporary field나 각 GUI component마다 다를 수 있는 Font나 font size는 저장할 필요가 없을 것이다. 이때 객체의 선언시 transient라는 modifier를 달아주면 Serialization시에 이를 저장하지 않게 된다. 또한 defaultReadObject라는 method는 이런 것들을 처리하는 가장 typical한 방법으로 Serialization된 파일들을 읽어주게 된다. Example 10-2의 경우 이러한 defaultReadObject를 이용하여 transient로 customize되어 serialization된 파일을 읽음으로써 10-1과 똑같은 일을 하는 것이다. 그러나 10-2의 경우 같은지 다른지만 비교하여 출력하게 되고 output은 당연히 "equal"이다.
Externalizable interface는 Serialization을 extend한 것으로 그 내부에는 writeExternal과 readExternal() method가 정의되어 있다. 이 Externalizable의 경우 Serializable의 사용법과 똑같게 사용하면 되는데 다음 두 함수, readExternal()과 writeExternal()를 오버라이드 함으로써 저장과 로드 작업을 커스터마이즈 시킨다.
Externalizable은 이미 저장할 type이 지정된 경우 특히 유용한데 예로써 Example 10-3의 CompatInt를 들 수 있다. 일반적으로 int는 4byte의 저장 공간이 필요하지만 CompactInt의 경우 작은 숫자를 2byte로 저장하는 Int list를 Externalizable을 implement 함으로써 저장 할수 있게된다. Example 10-3의 경우로 int list를 CompactInt의 방법으로 Serialization 한후 다시 불러오고 원본과 비교한다. Output도 당연히 "equal compare"이다.
데이터에 대한 버전 관리는 SerialVersionUID라는 변수의 값을 이용하는데 이 값을 알기 위해서는 그 클래스를 컴파일한 후에 serialver라는 도구를 이용하면 된다.
% serialver je3.Serialization, SerialIntList
SerialIntList: static final long serialVersionUID = 295...220L;
주의할 것은 클래스의 멤버 함수가 변경되더라도 자바 가상 머신은 버전이 다른 데이터로 인식함으로 클래스를 개발 중에 버전 넘버를 반드시 사용하여야 버전관리가 용이하다. 보통의 경우에 일단 버전 넘버를 명시한 후에 멤버 함수의 변경만 이루어진 경우에는 그 버전 넘버를 계속 사용하다가 데이터 멤버의 변경이 발생하면 새로운 버전 넘머를 부여받아 다시 명시한다. 물론 이 경우에 새로운 버전의 클래스는 기존에 저장된 데이터를 인식하지 못한다.
[Example 10-1. Serializer.java] : 예제로 만든 연결 리스트를 시리얼라이즈해 보기
[Example 10-2. SerialIntList.java] : 정수 리스트를 시리얼라이즈해 보기
* readObject() 함수와 writeObject() 함수를 오버라이드 해서 커스터마이즈 해 보기
* 이 프로그램에서는 정수 배열의 크기를 직접 관리하여 기억 장소를 절약함
[Example 10-3. CompactIntList.java] : 사용자 멋대로 커스터마이즈 해보기
* 정수 배열에 정수를 저장할 때 큰 수는 4 바이트 이용, 작은 수는 2 바이트 이용
Ch 11. GUI(Graphical User Interface)
GUI는 말 그대로 소프트웨어와 사용자 사이를 연결해주는 Interface를 말하여, Graphical, 즉 우리 눈에 익숙한 모양과 형태로 시스템을 조작 가능하게 해주는 것을 말한다. GUI는 modularity와 재사용의 관점에서 볼 때, 상당히 좋은 예시가 될 수 있다. 이것은 GUI가 대부분 구성요소(block)들의 조합으로 이루어져 있기 때문이다. 여기서 말하는 이 구성요소는, Unix에서는 "widgets"라 불리고, 자바에서는 "component(컴포넌트)"라 불린다.(윈도에서는 컨트롤이라 불림) 자바에서 GUI는 java.awt.Component에서 그 구성요소를 찾아 쓸 수 있다. 자바에서 GUI를 구현하는 기본적인 순서를 알아보자.
먼저, Component의 constructor를 사용해 새로운 component를 생성한다. 예를 들어, 버튼을 생성하고 싶다면 JButton quit = new JButton("Quit") 이라고 하면, 버튼 "Quit"이 만들어지고 그 버튼에는 "Quit"이라고 씌여져 있게 된다. 그리고 이 component의 속성을 명시할 수 있다. 예를 들어, 폰트를 바꾼다면 quit.setFont(new Font("sansserif", font.BOLD, 18)); 이라고 하면, 크기 18에 굵게 표시된 "sans serif"폰트로 글씨체가 바뀌게 된다.
component를 만들었다면 이제 이 component가 생성되어서 화면에 띄워지도록 해 주는 것이 필요하다. 대부분의 컴포넌트들은 스스로 화면에 나타날 수 없으며 컴포넌트들을 관리하는 컨테이너 컴포넌트에 소속되어 나타날 수 있다. container는 그 안에 여러 개의 component를 가질 수 있으며, container 내부에 또 다른 container가 들어갈 수 있어서, component를 쉽게 관리할 수 있게 해준다.
이제 이렇게 들어간 component들은 화면상에 기본적인 Layout으로 보이게 된다. 이 Layout에는 FlowLayout, GridLayout, BorderLayout, BoxLayout, GridBagLayout, HardcodedLayout 등등 여러 가지 Layout이 있으며, 자신이 새로운 Layout을 만들 수도 있다. 중요한 것은, 자신이 만들려는 프로그램의 성격에 맞는 Layout을 골라서 적용시키는 것이다. Layout은 프로그램 사용자의 편이성에 직접적으로 영향을 주기 때문에 쉽게 간과해서는 절대 안 되는 부분이다. 위에서 예를 든 여러가지 Layout에 대한 개별적인 설명을 하자면 너무 길어지기 때문에 여기서는 생략하도록 한다.(대충 이름만 봐도 어떤 정렬방식인지 알 수 있다. 사실은..)
그리고 이제 GUI에서 가장 중요하다고도 할 수 있는, Event를 Handle 시켜줘야 한다. 프로그램이 실행될 때, 사용자가 마우스로 조작을 하거나 키보드를 치면 프로그램에서는 그것을 실시간으로 받아들여서 여러가지 event를 발생시킴으로써, 사용자에게 완벽한 GUI를 제공하게 된다. 다시 말해서, 사용자와 실시간으로 정보를 교환할 수 있어야 만이 진정한 GUI가 구현되었다고 볼 수 있는 것이다. 이벤트를 받아들이기 위해서 쓰이는 것이 event listener이다. 일단 사용자가 앞에서 언급한 component에 대해 마우스 또는 키보드로 어떤 조작을 가하면, component는 event를 발생시킨다. event라는 것은 단순히 어떤 정보 - 사용자의 component에 대한 조작에 관한 정보 - 를 담고있는 object이다. 시시각각으로 발생하는 이 event들을 event listener에서 받아들이고, 이렇게 받아들여진 정보는 프로그래머가 작성한 소프트웨어(이벤트 핸들러) 내에서 어떤 작용을 하고, 그 결과를 화면에 다시 출력하고를 반복하게 되는 것이다.
앞에서 설명한 기본적인 조직과정(component - container - layout - event listener 작성)을 적절히 이용하여, 여러 가지 GUI가 만들어질 수 있다. 좋은 GUI는, 일단 어떤 상황에 대해서 사용자가 쉽게 알아볼 수 있도록 화면을 깔끔하고 체계적으로 보여주며, 사용자의 조작에 대해 상당히 즉각적이면서도 융통성이 있고 유연하게 반응하는 것이라 할 수 있다. 세상이 급변하면서, 프로그램 자체의 알고리즘의 우월성 보다는 사용자와의 인터페이스가 더욱 중요해지고 있다. 따라서 GUI의 구현은 더더욱 그 중요성이 커지고 있으며, 앞으로는 보다 알기 쉬우면서도 자세하고, 간단하면서도 유연한 GUI를 가진 프로그램이 더욱 선호될 것이다.
[Example 11-0. ShowBean.java] : ShowBean 객체의 사용법
* ShowBean 클래스는 이 장의 마지막 부분에서 구현된 도구이다.
* 개별적으로 작성된 컴포넌트를 실행시키기 위해 일일이 main() 함수를 구현하는 번거로움을 피하기 위해서 만든 도구이다.
[Example 11-1. Containers.java] : 컨테이너들의 포함 관계 보이기
[Example 11-2. FlowLayoutPane.java] : 프로그램 제목 그대로 ...
[Example 11-3. GridLayoutPane.java] : 프로그램 제목 그대로 ...
[Example 11-4. BorderLayoutPane.java] : 프로그램 제목 그대로 ...
[Example 11-5. BoxLayoutPane.java] : 프로그램 제목 그대로 ...
[Example 11-6. GridBagLayoutPane.java] : 프로그램 제목 그대로 ...
[Example 11-7. NullLayoutPane.java] : 프로그램 제목 그대로 ...
[Example 11-8. CoulmnLayout.java] : 레이아웃 커스터마이즈 하기
* LayoutManager2 인터페이스와 슈퍼 인터페이스인 LayoutManager 인터페이스의 함수들을 구현하여야 함
* LayoutManager 인터페이스의 layoutContainer(Container) 함수의 구현이 중요함
[Example 11-9. CoulmnLayoutPane.java] : 11-8의 레이아웃을 이용하는 판
[Example 11-10. ScribblePane1.java] : 낙서장 만들기
* 이벤트 리스너를 사용하는 경우
[Example 11-11. ScribblePane2.java] : 낙서장 만들기
* 이벤트 리스너를 구현하는 anonymous inner class를 사용하는 경우
[Example 11-12. ScribblePane3.java] : 낙서장에 버튼이랑 리스트 컴포넌트 추가하기
* ActionListener 와 ListSelectionListener와 같은 고급 이벤트 리스너 사용법
[Example 11-13. ScribblePane.java] : 낙서장 완성 본
* low level 이벤트 핸들링
* processMouseEvent() 와 processMouseMotionEvent() 함수와 같이 Component 클래스에 정의된 이벤트 처리 한수를 오버라이드 하는 방식
* 함수 작성의 마지막 부분에서 슈퍼클래스의 같은 함수를 반드시 호출해야 함
* 컴포넌트 생성 시에 enableEvent() 함수를 이용하여 잡을 이벤트들을 등록해야 함
* 이벤트 리스너와 동시에 사용하는 경우에 어떤 방식으로 “쫑”이 나는지 각자 확인할 것
* 이 클래스는 데이터를 PolyLine 객체들로 저장하므로 repaint()를 처리함
[Example 11-14. ItemChooser..java] : 커스터마이즈된 이벤트 만들고 notify 해보기
* 화면 아래 나오는 이벤트 정보가 이 예제의 중요 관심사임
[Example 11-15. ScribbleApp.java] : 어느 정도 GUI 골격이 갖추어진 예제
* Action 클래스의 사용을 유심히 볼 것 (Action = Label + actionPerformed 함수)
[Example 11-16. CommandAction.java] : 쪼깨 범용화된 Action 객체 만들어 보기 <read only>
* 메인 프로그램이 없기 때문에 어디에서 인용해서 사용하는지는 모르겠음
* Action 보다는 좀더 dynamic 해보임
* 리플렉션에서 만들었던 Command(actionPerformed 역할) 와 Label 과 기타 등등 묶인 객체임
[Example 11-17. FontChooser.java] : JDialog로부터 상속 받는 컴스텀 다이어로그 만들어 보기
* 일반적으로 간단한 메시지를 출력하고 싶을 때는 JOptionPane 클래스의 정적 멤버 함수들을 이용함
[Example 11-18. ErrorHandler.java] : JOptionPane 객체를 이용하여 커스터마이즈된 에러 메시지 보이기
* 아울러 exception 객체의 자세한 정보 알아보기
* exception 객체를 시리얼라이즈해서 서버에게 보고하고 응답받아보기 (그런데 어떤 서버에 접속해야 되는지는 모르겠음)
[Example 11-19. PropertyTable.java] : 테이블 만들어 보기
* 전형적인 MVC 패러다임 적용 예
* 모델 따로, 뷰 따로 ... 따로 국밥
[Example 11-20. ComponentTree.java] : 트리 만들어 보기
* 이것도 MVC 의 예임
[Example 11-21. WebBrowser.java] : 간단한 웹브라우저 만들어 보기
* 이 예제는 11-21부터 11-29 까지의 클래스들과 앞 장에서 인용되었던 클래스들을 섞어서 만든 섞어찌개 임
* 헌데 이 예제의 주제는 웹브라우저의 기능 중에서 html 텍스트를 뷰에 뿌리는 임무에 초점이 맞춰져 있는 것이 아니라 ... 오히려 프로퍼티 파일에 명시된 GUI 리소스 번들을 처리하는 임무에 초점이 맞춰져있음
* html 텍스트는 JEditorPane 객체가 알아서 처리함 (고로 이 예제에서 별로 중요하지 않음)
* 이 예제의 화면 구성은 하드코딩 방식으로 구현되어있지 않고 프로퍼티 파일인 WebBrowserResources.properties 파일에 기술되어 있음 (사실 이런 방식이 윈도 프로그래밍의 중요 기술이기도 함)
* WebBrowser 클래스 안에 resources 라는 GUIResourceBundle 객체가 있고 ...
* 요 객체를 위한 파서 객체들은 WebBrowser의 static initializer에서 등록이 이루어지고 있음
* 어쨌건 resource 객체를 이용한 GUIResourceBundle 클래스의 사용법을 유심히 보면 상당히 재미있는 코딩 스타일 임을 알수 있음
[Example 11-22. GUIResourceBundle.java] : gui 구성을 위한 리소스 뭉탱이들을 다루는 클래스
* 두 번째 컨스트럭터에서 ResourceBundle.getBundle(bundleName) 함수 호출을 통해 명시된 파일로부터 리소스 번들을 만듦
* ResourceBundle은 주로 스트링 자원에 대한 해쉬 테이블처럼 작동하는 것처럼 보임 (프로퍼티 파일에 명시된 리소스의 양식을 remind 할것 - resource_name: 어쩌구 저쩌구 스트링들)
* 반면에 GUIResourceBundle은 ResourceBundle을 확장해서 스트링 외의 객체들을 다룰 수 있게 한 것 같으며 아울러 getResource() 함수를 만들고 파서들 객체를 이용함으로써(parsers 라는 HashMap 객체) 번들에 들어 있는 스트링을 파싱하여 필요한 객체(특히 메뉴나 툴바 같은 gui 객체)들을 만들 수 있도록 구현했음
[Example 11-23. ResourceParser.java] : 다음 코드들에 나오는 각종 파서들의 대표자
[Example 11-24. CommandParser.java] : 스트링 리소스를 invocation 가능한 명령어로 파싱하여 커멘드로 만듦 (예제 9-2 참조)
[Example 9-2. Command.java] : Method 클래스 객체를 이용하여 문자 스프링을 실행 가능한 메소드로 바꾸어보기 (아주 특이한 indirect invocation)
[Example 11-25. ActionParser.java] : 마찬가지로 파싱하여 actionPerformed()를 수행할 커멘드 액션 객체로 만듦 (CommandAction은 예제 11-16 참조)
[Example 11-26. MenuBarParser.java] : 마찬가지로 메뉴바 객체 만듦
[Example 11-27. MenuParser.java] : 마찬가지로 메뉴 객체 만듦
[Example 11-28. ThemeManager.java] : Theme 메니저 만듦 (리소스 파서를 구현한 객체는 아님)
[Example 11-29. LookAndFeelPrefs.java] : look-and-feel 전담 메뉴 생성 및 작동 객체
* ShowBean에서 사용됨
[Example 11-30. ShowBean.java] : 앞에서 계속 사용되었던 ShowBean 소스
Ch 12. Graphics
자바 1.0과 1.1에서는 java.awt.Graphics 클래스와 이와 같이 사용되는 java.awt.Font 같은 클래스를 통해 기초적인 그래픽스 능력을 제공한다. 자바 1.2와 그 이후 버전에서는 어느 정도 수준급의 능력이 제공되는데 Graphics의 하위클래스인 java.awt.graphics2D나 이와 함께 사용되는 java.awt.AlphaComposite등으로 2D 그래픽 처리 능력을 보여준다. 모든 Graphics의 중요한 중심 클래스는 Graphics로 이 클래스의 목적은 크게 세 가지이다.
1. 이것은 Graphic이 그려질 면(surface)를 정의한다. Graphics 개체는 AWT성분으로 화면상에 도면(drawing-area)을 표현할 수 있다. 또한 인쇄 작업들을 위한 비화면 이미지(off-screan image)를 나타낼 수도 있다.
2. 이것은 그리는 방법들을 정의한다.
가장 기본적인 명령어들, 선을 그리거나 모양을 채우고, 텍스트를 출력하는 것은 Graphics클래스에 포함된 방법(method)을 사용해 수행된다.
3. 이것은 그리는 방법(method)에 대한 속성을 정의한다.
수많은 방법들(Graphics)은 폰트, 색상, 잘리는 부분, 다른 속성들을 선을 그리거나 모양을 칠하고 텍스트를 출력할 때 설정 가능하다. 이러한 속성들은 가끔 AWT 클래스에서 요구되는 사항이기도 하다.
Java의 거의 모든 기초적 그래픽 능력들은 AWT와 밀접한 연관이 있다. Graphics와 Graphics2D클래스들은 java.awt의 패키지이다. AWT의 중심 클래스는 java.awt.component이다. Component는 java에서 사용되는 모든 GUI의 기초적인 구성요소(building block)이다. Graphic 객체들은 도면 (drawing surface)을 나타내지만 Java는 이를 컴퓨터 화면에 바로 출력할 수 있게 해주지 않는다. 대신에 Component를 이용하여 나타낼 수 있도록 한다. 따라서 자바에서 그래픽을 다루려면 당신은 그리기 위해 Component를 반드시 가지고 있어야 한다. 그리기는 보통 어떠한 특정 component의 하위클래스를 정의하고 print() 메소드를 정의하면서 이루어진다.
java.awt.Graphics는 기초적인 능력만을 제공한다. 이것은 선을 그리고, 간단한 모양을 그리고 색을 채워 넣으며, 글자를 출력하고, 이미지를 그리며 간단한 이미지 조작을 할 수 있다. 또한 그리는 색깔, 글씨체, 잘리는 부분, 기본 위치 등을 설정할 수도 있다. 또한 선의 굵기나 이미지의 크기를 조절할 수도 있다.
[Example 12-1. GraphicsSampler.java] : Graphics 클래스의 그리기 함수 사용 예
* 애플릿 임 > appletviewer GraphicsSampler.html
[Example 12-2. FontList.java] : 폰트의 예
[Example 12-3. ColorGradient.java] : 색칠하기의 예
* 애플릿에 argument 넘겨주기
[Example 12-4. BouncingCircle.java] : 무진장 간단한 에니메이션
[Example 12-5. GraphicsExample.java] : 다음 예제부터 구현해 주어야 하는 인터페이스 <read only>
* 지금까지는 애플릿으로 예제를 실행시켰지만 다음부터는 GraphicsExampleFrame 객체를 이용할 것이며 ... 이 객체는 GraphicsExample 인터페이스를 구현한 객체들을 실행시킬 수 있다.
* 실행 방법: java je3.graphics.GraphicsExampleFrame Shapes
[Example 12-6. Shapes.java] : Java2D API 객체의 예
[Example 12-7. Transforms.java] : transformed된 객체의 예
[Example 12-8. LineStyles.java] : 라인 스타일의 예
[Example 12-9. Stroking.java] : 스트로킹의 예
[Example 12-10. Paints.java] : Paint 객체에 칠해보기 예
[Example 12-11. AntiAlias.java] : 이미지의 아웃라인을 부드럽게 하기 위한 기능
[Example 12-12. CompositeEffects.java] : 반투명의 칼라 효과 주기 + 클리핑
[Example 12-13. ImageOps.java] : 이미지 처리 종류
[Example 12-14. MakeFades.java] : 페이드 효과를 연출하는 백그라운드 이미지들을 생성하는 기능
* 이미지를 파일에 write 하는 api를 소개하는 목적으로 보여준 예제
* 웹 페이지에서 배경 이미지로 사용할 여지가 있음
[Example 12-15. Spiral.java] : Shape 인터페이스를 구현한 나선형 객체
* 예제 12-6 에서 이미 사용되었음
[Example 12-16. PolyLine.java] : Shape 인터페이스를 구현한 폴리라인 객체
* 예제 12-6 에서 이미 사용되었음
[Example 12-17. CustomStroke.java] : Stroke 인터페이스를 구현한 다양한 사용자 정의 스트로크 예
[Example 12-18. GenericPaint.java] : Paint 인터페이스를 구현한 사용자 정의 페인팅을 위한 추상 클래스
* 예제 12-10 에서 이미 사용되었음
[Example 12-19. Hypnosis.java] : 더블 버퍼링을 이용한 향상된 에니메이션
* 번쩍임이 없어짐
* repaint() 함수를 써서 다시 그려져야 할 일부분만 paint함
* 타이머를 사용하고 있음
[Example 12-20. GraphicsExampleFrame.java] : 이 장에서 계속 사용되었던 프레임의 소스
Ch 13. Printing
그래픽과 그래픽 2D 오브젝트는 drawing surface" 에 표현된다. 프린팅이라는 것은 단진 drawing surface로 설정된 target이 프린터라는 점만이 다르고 나머지는 스크린에 드로잉하는 작업과 동일하다.
자바 1.1에서는 java.awt.PrintJob 클래스를 사용했다. 그 당시의 코드는 상당히 불편했으며, Java 2D graphics를 지원하지 않았다. Java 1.2에서는 좀 더 다양한 printing 기능을 지원하기 시작했다. java.awt.print라는 패키지는 java 2D graphics를 지원하기 시작했고 page margins, orientation, use of color 설정을 할 수 있었다. Java 1.3에서는 좀 더 강화된 기능과 java.awt.PageAttributes와 java.awt.PageAttributes 클래스들을 사용할 수 있게 되었다. 하지만 여전히 1.3은 java 2D graphics methods를 사용할 수 없었다.
Java 1.4에서는 새로운 API를 javax.print 패키지에 정의했는데, 1.2의 패키지의 기본내용을 가지고 있으면서 여러 가지 기능이 또 추가되었다. 여기에 추가된 기능으로는 프린터를 선택할 수 있게 하는 기능, 파일로 프린트하게 하는 기능, 이벤트 리스너를 이용하여 프린트 작업의 진행상황을 알아볼 수 있는 기능, 출력 내용을 프린터로 직접 스풀링할 수 있는 기능들이 추가되었다.
[Example 13-1. JuliaSet1.java] : Java 1.1 API를 이용한 프린트의 예
* print() 함수의 프로그래밍 스타일을 확인 할 것
* 그런데 내 컴퓨터에서는 출력이 되지 않음 (아마도 virtual machine을 옛것으로 깔아야 하는지 몰겠음 ... 쩝)
[Example 13-2. JuliaSet2.java] : Java 1.2 API를 이용한 프린트의 예
* Printable interface를 구현하는 PrintableComponent 클래스의 내용을 유심히 볼 것
* 이것부터는 프린트 결과물이 출력됨
[Example 13-3. JuliaSet3.java] : Java 1.4 API를 이용한 프린트의 예
* PrintService 객체의 사용
* PrintJabAdapter 인터페이스를 이용한 프린트 잡 이벤트 보이기
[Example 13-4. HardCopyWriter.java] : 여러 페이지 텍스트 도큐먼트 출력과 관련된 API 사용 예 (Java 1.1 API 이용 + 페이지 다루기)
* Writer로부터 상속 받고 있기 때문에 write 함수에서 프린트 작업 수행
* write() 함수에서 라인 수가 초과되어 새로운 페이지가 필요할 때마다 그래픽 객체를 새로 할당 받음으로써 새로운 페이지의 내용을 작성하도록 함
* 예제 1) Demo 클래스
* 예제 2) PrintFile 클래스
[Example 13-5. Print.java] : Java 1.4의 진보된 기능들
* 프린터 리스트 기능
* 프린터 상태 퀴리 기능
* 스풀 기능
* 이미지 파일을 ps 파일로 바꾸는 기능
Ch 14. Data Transfer
컴퓨터 사용자가 한 어플리케이션에서 다른 어플리케이션으로 텍스트나 데이터를 이동할 때 사용하는 기술을 data transfer라고 한다. 예를 들어서 복사하기(copy), 잘라내기(cut), 붙여넣기(paste)와 Drag and Drop 등에서 필요한 기술이다.
Java 1.1 에서는 java.awt.datatransfer 패키지를 릴리즈 함으로써 cut-and-paste를 지원하였으며 Java 1.2 에서는 java.awt.dnd 패키지를 릴리즈 함으로써 drag-and-drop을 지원하였다. Java 1.4 에서는 javax.swing 패키지에 TransferHandler라는 클래스를 도입함으로써 cut-and-paste를 좀더 쉽게 사용할 수 있게 했으며 drag-and-drop도 스윙에서 쉽게 처리되도록 조치하였다.
JListsk JTable 같이(JLabel은 말고 ...) 텍스트를 다루는 객체들은 기본적으로 카피엔 드랙 작업이 허용되도록 조치되어 있다. 물론 JColorChooser 나 JFileChooser 같은 객체도 드랙이 허용되어 있다. 단 이들 객체가 드랙이 가능하게하기 위해서는 setDragEnabled() 함수를 이용하여 프로퍼티를 설정해주어야 한다.
[Example 14-1. ColorDrag.java] : 간단한 드랙 예
* TransferHandler 객체 사용의 용이성 (자바빈의 프로퍼티 이름을 이용한 드랙 가능, 만약 해당 프로퍼티 이름이 없는 경우에는 TransferHandler 클래스로부터 상속 받아서 customize 해야 함)
* JColorChooser와 함께 실험해 볼 것: (14-1-1 과 14-1-2)를 동시에 실행
* JColorChooser로부터 드랙할 경우에 밑에 있는 아이콘을 이용해야만 함
[Example 14-2. DigitalClock.java] : TransferHandler 커스터마이즈 하기
* 드랙만 됨
* 드롭은 JTextField 같은 객체를 이용할 것
* TransferHandler의 속성 “time”은 access function “getTime()”과 바인딩 됨
* 만약 setTime() 함수도 구현되어 있으면 write 즉 drop 기능도 지원할 수 있을 것으로 보임
* InputMap과 ActionMap 클래스를 이용한 키 바인딩 예제 포함 - <Ctrl-C>
[Example 14-3. FileTranseferFlavor.java] : 파일을 드랙해 보기
* DataFlavor 객체의 필요성
* DataFlavor.stringFlavor 와 DataFlavor.javaFileListFlavor 의 사용 예
* TransferHandler 클래스로 상속 받아 커스터마이즈해보기
* text area 객체에 커스터마이즈된 TransferHandler 적용한 예
[Example 14-4. TransferablePolyLine.java] : 드랙앤드롭이 가능한 폴리라인
* 다음 예제에서 사용됨
[Example 14-5. TransferableScribblePane.java] : 드랙앤드롭이 가능한 낙서장
* java.awt.datatransfer 와 java.awt.dnd 아키텍처를 이용해서 프로그램한 예
* 객체 선택 시에 <Shift> 키를 누르고 선택할 것
* 3개의 인터페이스를 구현해야 함
- DragGestureListener, DragSourceListener, DropTargetListener
ch 15. JavaBeans
JavaBeans API는 재사용 가능하고, 임베디드될 수 있는 모듈화된 소프트웨어 컴포넌트를 정의하기 위해 사용될 수 있는 체제를 제공한다. 자바빈 스팩에서 “빈”은 “빌더 도구에서 가시적으로 조작되어 구현될 수 있는 재사용 가능한 소프트웨어 컴포넌트”로 정의되어 있다. 자바 빈의 형태는 다양한 모습을 가지며 한 쪽의 극단으로는 모든 GUI 컴포넌트를 빈이라 볼 수 있으며 다른 극단으로는 다른 응용 소프트웨어에 삽입될 수 있는 스프레드 쉬트 같은 어플리케이션을 빈이로 취급한다. 대부분의 빈은 이들 양 극단의 중간적인 위치에 있다.
빈의 조합을 위해서는 beanbox 같은 도구의 사용이 필수적이며 이와 관련한 최근 도구는 “Bean Builder"라 불리는데 http://java.sun.com/products/javabeans 로부터 다운 받을 수 있다. 자바 빈은 윈도 시스템의 COM 기술이나 ActiveX 기술에 대응된다. (주의사항: 자바 빈은 EJB와 동일한 것이 아니다. 물론 기본 기술로서의 뿌리는 같지만 ...)
빈과 관련된 프로그래머는 다은과 같이 세 부류에 속한다.
- 툴을 사용하는 최종 사용자: 빈에 대해서 알 필요 없음
- 빈을 만드는 프로그래머
- 빈을 조작하는 툴을 만드는 프로그래머: 난이도가 가장 높은 프로그래밍
JavaBeans 컴포넌트 모델에서 제시하는 특징들은 다음과 같다.
(1) Introspection - Bean의 속성과 메소드를 찾아 제어할 수 있는 특징
컴포넌트 모델의 가장 중요한 특징으로 해당 컴포넌트의 실행모듈만 가져다 사용해도 reflection을 통해 실행 시점에 method, property를 발견하여 사용할 수 있는 특징을 의미한다. 이를 위해 JavaBeans 컴포넌트 명세에서는 Naming Convention을 제시하고 있고, Java.lang.reflect API와 BeanInfo인터페이스가 제공되고 있다.
(2) Customization
개발자는 해당 Bean을 디자인시점에 자신의 어플리케이션 상황에 적합하도록 Customising 할 수 있다.
(3) Event
Java 이벤트 모델을 적용하여 Bean과 Bean간의 통신과 연결이 가능하다. 즉, Listener인터페이스를 이용하여 서로 연결될 수 있다.
(4) Property
Bean은 property를 가지고 있고, properties를 handling 할 수 있는 get/set method를 제공한다. properties를 변경하면 자동으로 get/set method가 수행될 수 있도록 할 수 있다.
(5) Persistence
Bean은 Serializable 객체로 해당 Bean 객체 상태를 파일로 저장할 수도 있고 파일로부터 Bean의 상태로 복귀할 수도 있다.
Bean을 사용하기 위해서는 Jar, Jara archive 파일로 변환해 주어야 한다. Bean에 맞는 menifest파일을 만들고 Jar명령어로 합쳐서 BeanBox를 이용해 구성하는 것이다.
* 빈의 기초
빈은 몇 가지 원칙과 이름짓기 관습을 따르는 객체를 말하는 것이지 특별히 고안된 클래스로부터 상속받은 클래스의 객체를 말하지는 않는다. 또한 반드시 스크린에 나타나는 객체일 필요도 없다.
빈은 세 가지 요소를 외부에 익스포트 할 수 있어야 하는데, 그들은 프로퍼티, 이벤트 그리고 메소드이다. 프로퍼티는 엑세스 함수를 제공해야 하며, 이벤트는 GUI에서 커스터마이즈드 이벤트 모델에서 다룬바와 같은 구조를 제공해야 하고, 메소드는 public으로 공개되어야 한다. 빈의 프로퍼티 중에는 약간 특수한 것들이 있는데 그들은 indexed property, bound property, constrained property 들이다. indexed property는 전체 컨테이너 객체에 대한 엑세스 함수 외에 개별 아이템을 엑세스 할 수 있는 엑세스 함수를 제공해야 하고, bound property는 프로퍼티의 변경 시에 notification event를 발생 시킬 수 있어야 하며, constrained property는 변경 시에 notification을 발생시키되 프로퍼티의 변경을 거부할 수 있어야 한다.
빈은 리플렉션을 이용하여 여러 정보를 제공할 수 있어야할뿐더러 BeanInfo 클래스를 이용하여 보조적인 정보도 제공해야 한다. BeanInfo 클래스에 포함되는 정보들은 여러 FeatureDescriptor 객체들을 통해 제공되는데 FeatureDescriptor 클래스의 하위 클래스에는 BeanDescriptor, PropertyDescriptor, IndexedPropertyDescriptor, EventSetDescriptor, MethodDescriptor, ParameterDescriptor 가 있다.
빈의 속성을 명시하기 위해 사용되는 도구가 beanbox 이지만, 이 도구의 기능이 매우 미흡한 관계로 복잡한 속성을 변경할 필요가 있는 경우에는 빈을 위해 Customizer 클래스를 정의할 필요가 있으며 step-by-step 커스터마이즈 과정을 지원하는 위저드 도구를 만들 필요가 있다.
[Example 15-1. MultiLineLabel.java] : 간단한 빈
* 간단한 빈은 데이터 멤버를 엑세스하기 위한 set(), get() 함수와 디폴트 생성자만 있으면 된다.
[Example 15-2. Alignment.java] : enumeration type을 위한 클래스 만들기의 전형적인 예
* MultiLineLabel.java 클래스에서 사용되는 클래스
* 빈 목록 파일 만들기 - manifest.stub
(manifest 파일 작성 시 주의: 마지막에 리턴 넣어서 빈 줄 만들 것)
* jar 파일 만들기
* beanbox 나 Bean Builder 인스톨하기 (http://java.sun.com/products/javabeans)
* beanbox를 이용하는 경우에는 jar 파일을 jars 디렉토리에 옮겨 놓아도 됨
[Example 15-3. YesNoPanel.java] : 약간 복잡한 빈
[Example 15-4. AnswerEvent.java] : YesNoPanel에서 사용되는 커스텀 이벤트
[Example 15-5. AnswerListener.java] : YesNoPanel에서 사용되는 커스텀 이벤트 리스너
* 일단 여기까지 빈 만든 거 (make15-03 + manifest2.stub)
[Example 15-6. YesNoPanelBeanInfo.java] : YesNoPanel 빈의 정보를 빈 툴에 전달해 주기 위한 정보
* bean과 함께 뭉쳐져서 디자인 시에 이용될 수 있음 (다음에 나오는 클래스들과 함께 ...)
[Example 15-7. AlignmentEditor.java] : 얼라인먼트를 명시하기 위해 사용되는 프로퍼티 에디터
[Example 15-8. YesNoPanelMessageEditor.java] : YesNoPanel의 멀티라인 텍스트를 명시하기 위해 프로퍼티 에디터
[Example 15-9. YesNoPanelCustomizer.java] : YesNoPanel의 여러 내용을 쉽게 명시하기 위해 프로퍼티 에디터
* 요거 모양을 보려면 beanbox의 <Customize> 메뉴 눌러 볼 것
* 어쨌건 make15-09를 수행하면 YesNoPanel 빈의 모든 것이 묶여짐
[Example 15-10. Bean.java] : Component로 된 빈의 모든 것을 알아내어 관리하는 객체
* reflection 기능 이용
* GUI 장의 ShowBean 객체가 이용함
* make15-10 을 실행시킨 후 프로퍼티 에디터들을 사용해 볼 것 (ShowBean 조차도 빈박스의 일종임)
Ch 16. Applets
작은 application 으로 웹 브라우저에서 applet viewer를 통해 볼 수 있도록 만들어진다. 다른 응용프로그램은 exe 확장명을 가지고 있어서 파일로부터 실행되는 반면에 applet은 인터넷으로부터 다운 받아 익스플로러에 포함된 자바가상 머신에 의해 실행된다.
모든 applet의 sub class는 java.applet.Applet로부터 파생되는데, 이는 frame과 거의 유사하기 때문에 패널을 붙인다거나 버튼에 기능을 부여하는 것 같이 Frame에서와 비슷하게 event를 처리하는 일을 할 수 있다.
main() 함수를 갖지 않는 대신에 여러 기본 method를 구현하고, html 파일에서 이를 불러내어 html에서 지정해주는 parameter값과 위치에 의해 viewer 창에 실행된다.
기본 함수는 다음과 같다.
init() : browser나 viewer에 처음 실행이 될 때 호출되는 함수로 초기화를 시키고 생성자 역할도 할 수 있다.
destroy() : browser나 viewer창이 닫힐 때 호출되어 applet을 끝낸다.
start() : init() 함수 다음으로 호출되고 applet은 실질적으로 실행시킨다. applet 이 현재창에서 나타낼 때마다 실행된다.
stop() : 더 이상 창이 보이지 않거나 다른 페이지로 이동, 실행되고 있는 applet을 중지시킬 때 호출된다.
getAppletInfo() : 현재 applet에 대한 정보를 string 형태로 얻어옴. 잘 사용 안 됨.
getParameterInfo() : applet이 사용하는 parameter에 대한 정보를 string의 형태로 얻어옴.
그밖에, 필요에 따라 paint(), print()등을 자유롭게 쓸 수 있다.
자주 사용되는 method들로는
getImage() : network를 통해 image 파일을 불러온다.
getAudioClip() : network를 통해 AudioClip 파일을 불러온다.
getCodeBase() : applet 관련 file을 가져온 URL을 알려준다.
getDocumentBase() : applet에 쓰이는 HTML 파일의 URL을 알려준다.
showStatus() : 상태 표시 창에 메시지를 표시한다.
가 있다.
예전에는 web browser에서 별다른 설치 없이 동적인 모습은 보여주어 각광받았으나 요즘은 플래쉬나 JavaScript에 밀려 잘 사용되고 있지 않는 추세라 한다.
[Example 16-1. FirstApplet.java] : Hello World 찍기
[Example 16-2. Clock.java] : 디지털 시계 보기
[Example 16-3. Countdown.java] : HTML 파일을 이용하여 애플릿 변수 지정하기
* 양념으로 마우스 이벤트 처리도 ...
[Example 16-4. Scribble.java] : 애플릿으로 만든 낙서장
Ch 17. Sound
사운드 기능을 많은 응용에서 중요한 역할을 한다. 초기에는 사용자에 알리거나 주의를 주는 정도였지만 GUI 시스템이 도입된 후 점차 여러 가지 흥미로운 것들을 만들기 시작한다. 즉 미디어 플레이어, 레코더, 에디터 등 많은 것들이 나와 더욱 사운드가 발전하고 있다. Java sound API는 하위 수준의 인터페이스만을 지원하기 때문에 MP3와 같이 압축된 양식은 지원하지 못한다. 이 장에서 다루는 사운드의 양식은 .wav .aiff .au 등이다. dksxkRKqrp도 이 장에서 다루는 내용 중에 사운드를 녹음하는 예제는 다루지 못하는데 그 이유는 서로 다른 플랫폼에서 녹음을 하기위해 환경을 설치하고 잡아주는 작업이 상이하기 때문이다.
[Example 17-1. Beep.java] : "삑“ 소리 내기
* console-based application : \007 이용
* GUI-based application : beep() 함수 이용
[Example 17-2. PlaySound.java] : 오디오클립으로 사운드 플레이하기
* static java.applet.Applet.newAudioClip() 함수 이용
* 사운드 플레이는 기본적으로 백그라운드 스레드 형태로 돌아가기 땜시 저절로 프로그램이 멈추지 않는다. 이 문제를 해결하기 위해서는 JavaSound API를 이용해야 한다.
[Example 17-3. SoundPlayer.java] : 간단한 사운드 플레이어
* 두 가지 형태의 파일을 플레이 할 수 있음: MIDI 와 PCM(sampled audio)
* 두 가지 경우에 대하여 다른 API를 이용하고 GUI 구성도 약간 다름
[Example 17-4. PlaySoundStream.java] : javax.sound를 이용한 사운드 스트리밍하기
* 음악 파일을 몽땅 메모리에 로드하지 않고 플레이 되는 부분만을 스트림으로 받아 플레이 하기
* 단점: 아무 곳이나 원하는 곳으로 이동할 수는 없음
[Example 17-5. PlayerPiano.java] : 미디 입력 플레이하기
* 미디는 실제 음파를 저장하는 sampled audio와 달리 악기의 키보드를 흉내 낸 것임
* 소스 코드의 주석문을 보면 입력 데이터의 의미가 설명되어 있음
[Example 17-6. Drums.java] : 키보드를 이용해서 실시간 미디 사운드 플레이하기
* 10 번 채널은 타악기용임
Ch 18. Database Access with SQL
이 장에서는 JDBC API를 통해서 디비 서버와 통신하는 방법을 다룬다. JDBC는 SQL 쿼리 명령어를 이용하여 서버에 접근할 수 있도록 하는 API이다. 주의할 것은 JDBC는 SQL API이지 자바 언어를 이용한 임베디드 SQL 프로그래밍이 아니라는 것이다.
java.sql은 디비 서버에게 SQL 쿼리를 보내거나 쿼리 결과를 받아보기 위한 직접적인 메커니즘을 제공한다. 이를 이용하기 위해서는 디비에 대한 사전 지식이 있어야하며 이런 지식은 개별적으로 습득하기 바란다. 이 책의 예제를 돌리기 위해서는 디비에 엑세스할 수 있어야 하며(직접 깔든지), 그 디비를 위한 JDBC 드라이버를 인스톨해야 한다. 직접 깔 사람은 오픈 소스 서버인 MySQL(http://www.mysql.com)이나 PostgreSQL (http://www.postgresql.com)을 사용해 보기 바란다. - 이 예제에서는 MySQL을 이용했으므로 각자는 이 예제들을 사용하기 전에 반드시 서버를 인스톨하고 드라이버를 깔 것 - 드라이버 인스톨은 상대적으로 쉬운데 다운로드 받은 후에 classpath를 명시하거나 혹은 다운 받은 결과를 jre/lib/ext/ 디렉토리 밑에 쳐 박아두면 된다. (그런데 나는 이 짓도 귀찮다고 생각하기 땜시 jar 파일을 명령어에서 직접 명시했다. 배치 파일 참조)
디비에 엑세스하기 위해서는 네가지 JDBC 프로그래밍 입무에 익숙해야 한다. 그 네가지는 디비 드라이버 등록하기, DriverManager 클래스를 이용하여 Connection 객체를 얻어오기, Statement 객체를 이용하여 쿼리 날리기, 그리고 ResultSet 객체를 이용하여 쿼리 결과를 알아내기이다.
일단 염두에 둘 내용은 java.sql 패키지에 있는 Connection, Statement, ResultSet등의 멤버들이 클래스가 아니라 인터페이스들이라는 것이다. 이 점에서 JDBC 드라이버의 역할을 짐작할 수 있는데 드라이버의 내용은 이들 인터페이스를 구현한 클래스의 집합이라는 점이다.
글고, DriverManager 클래스의 임무는 시스템에서 사용가능한 드라이버들을 관리하는 것이기 때문에 우리는 JDBC 프로그래밍을 하기 전에 우선적으로 사용될 드라이버를 등록해야한다. 대개의 경우 JDBC 드라이버들은 처음 로드될 때 DriverManager에 등록되므로 등록하는 명령어를 직접 사용할 필요없이 로드만 하면 되며, 커맨드 라인 아규먼트로 드라이버 클래스를 명시하고 프로그램 안에서 Class.forName() 함수를 이용하여 로드하면 등록이 된다.
드라이버 로드 후에 JDBC 프로그램은 DriverManager.getConnection() 함수를 이용하여 디비에 연결된다. 사용하고자하는 디비의 명시 방법은 URL 스타일을 따르는데 예를 들어 jdbc:subprotocol://host:port/database 와 같은 문법을 이용하면 된다. 원서에서는 다음 URL을 사용한다. jdbc:mysql://dbserver.mydomain.com:1234/mydb 그런데 만약 localhost에 서버가 구동중인 경우에는 jdbc:mysql:///mydb 라고 해도 되며 우리는 후자 스타일을 이용할 것이다. 그 다음 부터의 API 사용법은 프로그램 소스로부터 이해하면 될 것이다. (getConnection, createStatement, executeQuery, executeUpdate, getResultSet, next, result set에 대한 access function 사용법 등 ...)
[Example 18-1. ExecuteSQL.java] : 간단한 SQL 인터프리터 만들기
* console-based sql 클라이언트처럼 작동
* 일단 디비부터 만들어 보자 ...
* 그런 다음 실행해 보자 ...
[Example 18-2. GetDBInfo.java] : 데이터베이스 정보(metadata) 읽어오기
* DatabaseMetaData 클래스를 이용해서 테이블 정보 엑세스
* 프로퍼티 사용법도 함께 - DB.props
* 결과는 아래처럼 ...
[Example 18-3. MakeAPIDB.java] : 디비 내용 구축하기
* 자바 API와 관련된 정보들을 저장하는 디비 구축
* 이 프로그램에서도 프로퍼티 파일을 이용함 - APIDB.props
* 데이터베이스 이름 - apidb
* 테이블 이름들 - package, class, member
* 이 프로그램을 실행시키기 전에 디비에 apidb라는 데이터베이스를 생성해야 함
- create database apidb;
[Example 18-4. LookupAPI.java] : [18-3]에서 만들어진 디비에 엑세스하기
* 패키지, 클래스, 멤버 함수에 대한 정보 찾아보기
Ch 19. XML
XML(Extensible Markup Language)는 HTML이나 SGML 문서에서의 것과 비슷한 구조적 태그를 가지고 문서를 구조화하는 메타언어이다. XML은 사용자 나름대로의 문서 포맷과 내용을 기술하는 구조적 markup을 허용하는 점 때문에 유명해졌다. XML은 “Portable data”를 가능케 하고, 이는 JAVA가 지원하는 “portable code”와 결합해 강력한 도구가 될 수 있다. XML의 대중성 덕분에 XML문서를 파싱하고 조작하기 위한 수많은 도구가 존재한다. 이 장에서는 파싱 도구로 SAX와 DOM에 대해 알아본다.
파싱 도구로서 SAX는 실제로는 파서로 작동하지 않음에 유념하기 바란다. SAX는 단지 파싱을 위한 API를 제공할 뿐이다. SAX를 이용하는 경우에 프로그래머는 필요한 이벤트 메소드를 구현하는 클래스들을 정의해주어야 한다. 라이브러리에서 제공되는 기본 파서가 다양한 종류의 엘리먼트 타입을 마주치는 경우에 그 파서는 단순히 프로그래머가 정의한 해당 이벤트 메소드를 호출할 뿐이다. (요기에서 이벤트 핸들러는 GUI의 이벤트 핸들러를 말하는 것이 아니라 XML 문서 중에서 특정 타입의 엘리먼트를 만나는 상황 혹은 위치를 말한다.) 즉 SAX 모델에서 파서는 XML 문서에 대한 파스 트리를 만드는 것이 아니라 문서의 내용에 매치되는 함수 호출로 변환하는 임무를 수행한다고 볼 수 있다. (물론 프로그래머가 작성한 핸들러에서 파스 트리를 만들도록 코딩하면 당연히 파스 트리가 만들어지겠지만 ...) SAX 스타일의 파싱 기법은 파서가 이벤트를 이벤트 메소드 쪽으로 보내주기 때문에 “push parsing" 이라 한다. 반면에 일반적인 파싱기법은 프로그래머가 작성한 함수들이 파서로부터 토큰을 땡겨오기 때문에 "pull parsing"이라 한다.
SAX API는 David Megginson (http://www.megginson.com)이 만들었고 http://www.saxproject.org에 의해 관리되고 있는 중이다. 이 API가 실질적으로는 표준이지만 공식화되어 있지는 않단다. SAX가 API 이다 보니깐 이것을 실제로 구현한 파서는 종류가 다양한가보다. 그 중에서 JAXP는 자바 버전이다. javax.xml.parsers 와 javax.xml.transform 패키지가 요 계통의 클래스들을 구현한 결과이다.
SAX와 달리 DOM은 XML 문서에 대한 파싱 결과인 파스 트리를 제공하는 API이다. DOM API는 W3C(World Wide Web Consortium)에서 정의되었다. 이 API의 자바 구현은 org.w3c.dom 패키지와 그 서브패키지로 제공된다. DOM에 의해 제공되는 파스트리는 org.xml.dom.Node 인터페이스를 이용하여 traverse 할 수 있으며 관련된 인터페이스에는 Document, Element, Entity, Comment 등이 있다. DOM은 SAX에 비해 훨씬 유용하며 특히 입력 자료를 여러 번 패스하는 과정을 거치거나, 입력 트리 구조를 변경하거나, XML 자료를 랜덤하게 엑세스할 때 유용하다.
XML의 응용분야가 여러 가지가 있겠지만 결국 우리가 관심을 가져야 되는 초점은 “XML 문서는 구조화되어 있으며 우리는 이 구조화된 자료를 다른 형태의 구조화된 정보로 자유자재로 변환할 수 있어야 한다”는 점이다.
[Example 19-1. ListServlets.java] : 간단한 xml 문서로부터 정보를 걸러서 출력하기
* DefaultHandler 클래스의 함수에 오버라이드한 함수들의 사용목적 이해하기
[Example 19-2. WebAppConfig.java] : DOM의 API 맛보기
* getElementsByTagName() 함수를 이용하여 태그의 내용을 알아오기
* 파스 트리에 새로운 노드 만들어 붙여보기
* 파스 트리의 내용을 출력 스트림으로 바꿔 출력하기(노드를 직접 visit해서 처리하는 방법도 있지만 여기서는 그냥 통째로 ...)
[Example 19-3. XSLTransform.java] : XML 입력을 XSL 스타일시트 양식에 맞추어 변환하기
* XML 입력 중에서 필요한 내용들만 태그를 없애고 간결하게 출력하는 기술
* 원래 이 프로그램의 입력 파일은 java.util.logging 패키지에 의해 생성되는 XML 로그 파일이어야 하며, 이 프로그램은 입력 파일 중에서 <record> 태그가 붙은 아이템들을 걸러내어 <sequence>, <date>, <message> 정보만 추려내는 것이 목적이다. 그런데 로그 파일이 뭔지 나도 본적이 없기 땜시 ... 그냥 web.xml 파일을 이용했드만 ...
[Example 19-5. ListServlet2.java] : XML pull 파서를 간단이나마 만들어보기
* 옛날에 다루었던 토크나이저등을 이용
* DOM 파서같은 도구를 만들기 위한 기본 기술이라고나 할까 ...
Ch 20. Servlets and JSPs
웹서비스는 정적 HTML을 이용한 단방향 서비스로 시작했다. 주로 하이퍼텍스트만이 지원되던 그것에서 사용자들은 좀 더 다양한 정보와 다이나믹하게 반응하는 콘텐츠를 원하게 되었고, 기업 등에서도 다양한 방법으로 사용자를 대할 필요성을 느끼게 되었다. 이에 동적 콘텐츠의 요청을 수행가능 한 외부 프로그램과의 인터페이스가 정의되었고 이의 기반이 CGI 프로토콜이다. 그러나 이것은 요청을 받을 때마다 프로세스를 생성시켰기 때문에 무리가 있다거나, 메모리 사용에 불편함이 드러났고 서버의 기능을 좀 더 확장하여 확장 CGI를 개발하게 되었다. 이 확장 CGI의 대표적인 예가 Servlet과 JSP 혹은 microsoft사의 ASP 같은 것이다.
Servlet과 JSP는 자바 서블릿 응용 프로그램으로서, 이의 개발과 서비스를 위해서는 Java Servlet API와 Servlet 컨테이너라는 게 필요하다. Java Servlet API란 SUN사에서 application 개발자가 FTP, HTTP, DHCP와 같은 application level의 protocol의 자세한 이용방법을 몰라도 쉽게 이용하여 개발할 수 있도록 제공한 API들의 확장 인터페이스 집합이다. 이것을 이용하여 만든 Java Servlet Application Program을 서비스하는데 서블릿 컨테이너가 필요한 것인데, 서블릿 또한 자바 클래스이기 때문에 JVM이 필요하고, 서버측이 가져야 하는 JVM상에서 서비스 할 수 있는 프로그램이 컨테이너이다. 컨테이너에는 여러 종류가 있는데, 이 책에서는 Tomcat(http://jakarta.apache.org/tomcat)을 이용한다.
일단 실질적으로 서블릿과 JSP를 어떻게 사용하는지 알아보자. 우선 서블릿은 보통의 자바 클래스와 다른 것이 없다. 다만 출력을 HTML형태로 할 뿐이다. 서블릿을 만들 때에는 Java Servlet API 및 javax.servlet.*, javax.servlet.http.*을 import하고 HttpServlet을 상속받아 만들게 된다. Http 서블릿에서 사용되는 중요 메소드는 doPost(), doGet() 이다. 이는 보통 HTML Form Tag를 사용할 때 지정하게 되는 get이나 post method와 같은 것으로 보면 된다. 그러니까 doPost()는 자료를 받아 어떤 출력을 만들 때 사용하고, doGet()은 그 자료를 보내야 할 필요가 있을 때 사용한다. 이 doPost()나 doGet() 함수 안에서 연산하고 출력하면 되는데 출력은 PrintWriter 객체를 이용하면 된다. 이는 Java Servlet API에서 제공하는 것이며 사용방법은 println 함수를 이용하여 HTML 형태를 출력하게 되면 웹브라우저에서 HTML 내용을 출력해준다. 그리고 이것은 따로 컴파일 할 필요 없이 *.java 파일만 웹서버 내의 지정해준 특정 디렉토리에만 있으면 container가 알아서 컴파일 후 loading 과정을 거쳐 client와 상호작용하게 된다.
JSP도 서블릿과 마찬가지로 Java Servlet Application인데, 이는 class 파일로 만드는 것이 아니고 *.jsp의 확장자를 가지며 HTML 태그 사이에 자바 코드가 삽입된 형태로 볼 수 있다. 자바 클래스가 아니라 따로 구현하거나 상속받을 클래스가 없는 것은 당연하며, 그저 HTML 문서 사이에 <%-- .... --%>, <%! ... %>, <% .... %> 등의 문자를 사용하여 그 안에 자바 코드를 삽입하면 된다. <%-- ... --%> 는 주석, <%! ... %>는 함수나 변수를 정의할 때, <% .... %>는 실질적으로 자바 코드를 삽입할 때 쓴다. <%= ... %>라는것도 있는데 <% .... %>만 사용하여 HTML 태그 중에 어떤 변수 값을 출력하고자 할 때에는 너무 긴 노력이 필요하므로 간단하게 <%= variable %>과 같은 형태로 출력할 수 있다. <%@taglib url= ~%>를 이용 사용자가 정의한 태그도 사용할 수 있고, <%@include file="URL"%>로 다른 문서를 include하여 사용할 수도 있다. 이렇게 자바 코드를 이용하여 연산하고, 출력을 그냥 HTML tag안에 자바 코드가 삽입하는 형태이므로 HTML tag가 출력이 된다.
어쨌건 이장의 예제를 실험하기 위해서는 다음과 같이 환경을 잡아야 한단다 ... 쩝 (아니면 서블릿을 지원하는 웹서버에 가서 작업하던지)
- 웹 서버 깔기: Tomcat 이용
- 서블릿 컨테이너 깔기: Tomcat
- JSP를 돌리는 경우를 위해 Java Standard Tag Library 명시하기
- 서블릿 API 를 제공하는 클래스들 깔기: 원래는 J2EE에 포함되어 있으나 Tomcat의 common/lib/servlet-api.jar를 이용하면 된다고 함(PC에서는 이거 안 해도 되는 것 같음)
- deployment descriptor 만들기: 이거는 서버 컨테이너가 URL들을 서블릿 클래스로 매핑시킬 때 필요 함
서블릿을 돌리기 위해서는 자바 코드와 관련 파일들을 만든 후에 이들을 몽땅 묶어서 war 파일로 만든 후, war 파일을 웹서버(Tomcat)의 webapps 디렉토리에 옮겨 놓기만 하면 된다. 웹 서버는 잠시 후에 war파일을 자동으로 풀어서 사용한다. 이장의 모든 예제는 je3.war 파일로 묶여서 데모로 사용된다.
[Example 20-1. HelloNet.java] : 무진장 간단한 서블릿
* http://localhost:8080/test1/Hello 라고 칠 것
* 서블릿 이름 Hello와 자바 파일 이름 HelloNet의 매핑 관계는 WEB-INF/web.xml 에 적혀 있다.
[Example 20-2. ErrorHandlerServlet.java] : 또 다른 간단한 서블릿 (별로 간단한 것 같지는 않지만 ...)
* 이 서블릿은 앞에서 다루었던 ErrorHandler 클래스로 부터의(사용자로 부터가 아니라) HTTP POST 요구를 받아 예외를 풀고 그 반응을 돌려 주는 예제임
* 이 서블릿을 설치한 후에 실행 시키고 싶으면 make11-18-for-20-2.bat 배치 파일을 실행 시킨 후에 <Send Report> 버튼을 눌러 볼 것
[Example 20-3. Counter.java] : 저장되는 객체를 다루는 서블릿
* 웹 페이지의 히트 수를 관리하는 경우와 같이 데이터를 persistent 양식으로 저장하고 로드하는 예를 보여 줌
* 이 프로그램을 실행시키기 위해서는 C:\tmp 디렉토리를 만들어 놔야 함 (이 디렉토리 밑에 counts.ser 파일에 카운터의 이름과 값이 해시맵으로 시리얼라이즈됨, 이 파일이 저절로 생길 수 있는지는 확인해 보지 않았음. 저절로 생기지 않은 경우에는 이 디렉토리의 counts.ser 파일을 이용할 것, 이 파일은 내가 억지로 만든 것임)
* http://localhost:8080/test3/Counter 혹은
* http://localhost:8080/test3/Counter?counter=numhits 라고 칠 것
[Example 20-4. Hello.jsp] : 간단한 JSP 예제
* 태그의 문법은 알아서 찾아 볼 것
* JSP의 개발 시에 deploy를 하기 전에 컴파일하는 환경은 이 책에서 다루고자 하는 범위를 벗어남
* http://localhost:8080/test4/hello.jsp
[Example 20-4. Hello2.jsp] : 간단한 JSP 예제 다시
* JSP2.0의 EL 이라 불리는 Java-like Expression Language를 이용함
* JSP의 이상한 태그들을 대치하는 expression들을 이용함 (태그 라이브러리를 필요로 함)
* 요거 돌리기 위해서는 사전 작업이 필요함
http://jakarta.apache.org/taglibs 에 가서 jstl.jar 와 standard.jar 파일을 다운 받아(사실은 잘 뒤져서 어떤 파일을 다운 받아 푼 다음에 그 디렉토리에 가서 복사해야함) Tomcat의 common/lib/ 디렉토리에 모셔 놓고 실행 해야 함 (물론 디렉토리에 모셔 놓은 다음에 Tomcat 서버를 다시 부팅해야 함은 물론이고 ... 아이고 힘들어 죽갔다.)
* 요렇게 한 후에 http://localhost:8080/test5/hello2.jsp (20-4 와 똑같이 돌아감)
[Example 20-6. Hello3.jspx] : XML 태그 스타일을 이용한 JSPX 프로그램
* [20-5]가 [20-4] 보다 깔끔하기는 하지만 태그 양식이 XML 스타일과는 다름
* 커스텀 태그를 정의하여 XML 스타일 태그를 이용하도록 한 프로그램
* 이 프로그램을 돌리기 위한 커스텀 태그는 WEB-INF/tags/xhml.tag 파일에 저장되어 있음
* 어쨌건 마지막에 http://localhost:8080/test6/hello3.jspx
[Example 20-7. User.java] : MVC 패러다임을 이용하여 어플리케이션 만들어 보기(시작부분)
* Controller - 자바 서블릿으로 구현하며 사용자 입력 처리
* View - JSP 로 구현하며 화면 보이기
* Model - 정보를 저장하며 빈 형태로 만들기(get/set property accessor 만들어서)
* User.java 는 메일 리스트 정보 구축을 위한 Model 객체
[Example 20-8. UserFactory.java] : 유저 객체와 디비 레코드와의 연동작업을 수행하는 객체
* 소스 코드에 수정할 부분 있음 getInt() -> getBoolean()
[Example 20-9. Controller.java] : Controller 객체(입력 처리, 화면 이동)
[Example 20-10. login.jsp] : 로그인을 위한 뷰 객체
[Example 20-11. edit.jsp] : 사용자 정보 편집을 위한 뷰 객체
[Example 20-12. attention.tag] : 커스텀 태그
[Example 20-13. box.tag] : 커스텀 태그
[Example 20-14. web.xml] : configuration file (서블릿 속성들을 명시하기 위한 파일)
* 어쨌건 이들을 실행하기 위해서는 ...
* 디비에 다음과 같이 설정되어 있어야 함:
CREATE TABLE subscribers (
email VARCHAR(64) PRIMARY KEY,
password VARCHAR(20),
html BIT, digest BIT);
* 데이터베이스 이름은 ... jdbc:mysql:///test
* jdbc connector를 common/lib에 배치할 것
* web.xml 파일에 유저이름(root)와 패스워드 명시할 것
* 마찬가지로 tablename은 subscribers 로 명시
* 어쨌건 je3.war 파일이 완성본 임
Ch 21. RMI
RMI는 remote method invocation의 준말이다. 이 RMI는 네트워킹에서 사용되며 네트워킹에서의 상세한 프로토콜에 신경 쓸 필요가 없이 프로그래밍 할 수 있는 최신 기술이다. 이 기술은 사실 컴포넌트 공학 기술의 출발점이기도 하다. RMI가 구동되는 리모트 객체 모델에서 서버는 멀리 있는 클라이언트가 사용하는 객체를 생성할 수 있으며 클라이언트는 사용되는 객체가 마치 로칼 가상 기계에 있는 것처럼 생각하며 프로그래밍 할 수 있다. 특히 인자들과 리턴 값들이 어떻게 마샬링되고 언마샬링 되는 가에 신경 쓸 필요가 없다. RMI 방식의 어플리케이션 개발을 위해서는 다음과 같은 단계를 거친다.
1. 사용되어야 할 객체를 위해 java.rmi.Remote 인터페이스로부터 상속된 인터페이스를 만든다. 이 인터페이스는 클라이언트에게 알려지는 외부 서비스의 목록으로 보이게 된다. 이 인터페이스에 정의되는 함수들은 반드시 java.rmi.RemoteException을 던져야 된다.(요 사항은 별로 중요하지 않다.)
2. 첫 번째 단계의 인터페이스를 구현하는 클래스를 만들되 이 클래스는 java.rmi.server.UnicastRemoteObject로부터 상속된 클래스여야 한다. 이 클래스가 실제로 서비스를 제공하는 객체로 인스턴시에이트된다. 여기서 구현되는 인터페이스의 함수들은 RemoteException을 던지도록 프로그래밍되어야 하는 점 외에 특별한 속박이 없다.
3. 사용자의 요구가 있을 때 사용되는 객체(1, 2에 의해 만들어지는 객체)를 생성하는 서버 프로그램(요런 기능의 프로그램은 COM에서는 팩토리라 부름)을 만든다. 이 프로그램은 객체 생성과 더불어 시스템에 객체 식별자를 등록하는 레지스트리 서비스도 제공해야 한다.
4. 서버 프로그램의 컴파일 후에 rmic 명령어를 이용하여 그 객체를 위한 stub과 skeleton을 만든다. 요것들은 마샬링과 언마샬링을 위한 자바 코드이며 이 내용을 읽거나 이해할 필요는 전혀 없다.(실제로는 기계적으로 만들어지는 코드이기 때문에 어려워서 읽을 수도 없다.) stub 객체의 기능은 리모트 객체(즉 사용될 객체)를 네트워크 상에서 얼굴 마담이나 삐끼처럼 대표하는 일이며, skeleton은 stub으로부터 전달 받은 네트워크 프로토콜 형태의 정보를 프로그래밍 형태의 정보로 변환하는 일을 한다. 이 파일들의 이름은 _Stub 과 _Skel로 시작된다.
5. 레지스트리 서버를 실행 시켜서 객체의 존재를 만방에 알린다. (그렇다고 브로드케스팅 한다는 건 아니고 ...) 이 작업을 할 때는 rmiregistry 명령어를 이용한다.
6. 그 다음에 클라이언트 프로그램을 작성하면 된다. 클라이언트 프로그래머는 리모트 객체의 이름을 알아야하고, 그 객체가 제공하는 인터페이스의 함수를 이용하여 코딩하면 그만이다. 리모트 객체의 명칭은 rmi: 로 시작하는 URL 방식으로 명명된다. 자세한 코딩, 즉 어떻게 인스턴시에이션하고 어떻게 호출하는 가는 예제 코드에서 직접 보도록 하자.
7. 서버 프로그램 실행 후에 클라이언트 프로그램 ... 여러개 ... 실행 시켜보라.
[Example 21-1. Bank.java] : 가상 뱅킹의 클라이언트 프로그램
* Bank.java 라기보다는 BankClient라는 이름으로 작성해야 맞을 것 같은데 ...
* 어쨌건 서버 실행 후에 다음과 같이 사용하면 됨
> java je3.rmi.Bank$Client open david javanut
Account opened.
> java je3.rmi.Bank$Client deposit david javanut 1000
Deposited 1000 wooden nickels.
> java je3.rmi.Bank$Client withdraw david javanut 100
Withdrew 100 wooden nickels.
> java je3.rmi.Bank$Client balance david javanut
You have 900 wooden nickels in the bank.
> java je3.rmi.Bank$Client history david javanut
...
> java je3.rmi.Bank$Client close david javanut
900 wooden nickels returned to you.
Thanks for banking with us.
* remote에서 접속하려면 -
java -Dbank=rmi://203.230.**.**/FirstRemote -cp ..\.. je3.rmi.Bank$Client open david javanut
[Example 21-2. RemoteBankServer.java] : 가상 뱅킹의 서버 프로그램
* 이걸 실행하는 절차는 make21-01.bat 파일 참조
* 교재에 나오는 절차대로 했을 때는 RemoteBankServer_Stub을 로드하는 문제가 발생
* 땜빵으로 조치 (이유도 모르고 ...)
[Example 21-3. PersistentBankServer.java] : DB를 이용하는 가상 뱅킹의 서버 프로그램
* MySQL에 데이터베이스 bank를 만든 후 다음과 같이 테이블 생성
CREATE TABLE accounts (name VARCHAR(20),
password VARCHAR(20),
balance INT);
* 요거 실행할 때 jdbc 드라이버 명시할 것
* 프로퍼티 파일 BankDB.props 이용
* 요것도 실패할 뻔 했는데 ... Stub 파일을 자르로 잘 묶어서 jkd 의 jre/lib/ext 쪽에 잘 모셔두니깐 돌아가드만
* 기본적으로 내 콤에서 패스 지정이 개판인가 보구만 어쨌건 이상 끝.
[나머지 예제 프로그램들] MUD 서버의 예제 프로그램 - make-MUD.bat
Bank 프로그램의 경우 두 명의 유저가 서버에 동시접속 할 수가 없다. 따라서 여러 사람이 동시에 사용할 수 있도록 프로그램을 하는데 그것이 MUD(Multiple User Domain)이다. MUD도 역시 서버와 클라이언트로 구성된다. MUD 클라이언트의 경우 당연히 한 서버에 여러 사람이 접속할 수 있으며 서로 의사소통이 가능하다.
예제의 MUD client는 다음과 같은 명령어를 갖는다.
examine <thing> : thing을 조사한다.
describe <person> : person을 설명한다
go <direction> : 특정방향으로 움직인다.
say <message> : 모두에게 말한다.
talk <person> : 특정 person에게 말한다.
change : 설명을 바꾼다
create <thing> : thing를 만든다.
destory <thing> : thing을 삭제한다.
open <direction> : direction에 참가한다.
close <direction> : direction에서 나온다
quit : MUD프로그램을 빠져나간다.
어쨌건 여러 클라이언트가 참여하여 쓰고 즐기는 서버람.
댓글