'2010/01'에 해당되는 글 62건
- 2010/01/25 1. 서문 & 언터프라이즈 환경의 서블릿
- 2010/01/25 세번째 자바 이야기 - Professional Java Sservlets 2.3
- 2010/01/17 06. Java EE 6 - EJB 3.1
- 2010/01/17 29. J2SE 5.0 Concurrency
- 2010/01/17 28. J2SE 5.0 Annotations
- 2010/01/17 27. J2SE 5.0 Generics
- 2010/01/17 26. J2SE 5.0 Language Features Enhancements
- 2010/01/16 05. Java EE 6 - JPA 2.0
- 2010/01/14 04. Java EE 6: DI (JSR 330) and CDI (JSR 299)
- 2010/01/13 02. 변수 part 02
- 1. 서문 & 언터프라이즈 환경의 서블릿
- BOOK Study/J2EE
- 2010/01/25 23:49
- Posted by 들기름왕자
- 이 책은 자바 언어와 자바 핵심 API에 익숙한 개발자들을 대상으로 한다.
ㅇ 이책에서 다루고 있는 내용
- 엔터프라이즈 환경에서 서블릿을 사용하기 적합한 곳과 사용법에 대한 전반적인 개념 설명으로 시작한다.
- 2,3장에서는 서블릿 API를 다룬다.
- 4장에서는 웹 애플리케이션의 구조와 웹 서버에 배치하는 방법을 알아본다 .
- 5-7장에서는 서블릿의 강력한 특징 중 일부분인 새션관리, 서블릿 영속성, 필터에 대해서 알아 볼것이다.
- 8장에서는 자바 서블릿을 보완하는 기술인 JSP에 대해서 알아 볼것이다.
- 9-11장에서는 실제 실행하는 환경에 웹 애플리케이션을 배치할 때 발생되는 문제들에 대해서 알아보게 된다. 디버깅 방법에 대해서 알아보고, 틀래스 로딩과 동기화를 고려하지 않았을때 발생될수 있는 문제점들을 알아볼것이다.
- 12,13장에서는 성능과 유지보수에 영향을 줄수 있는 효과적인 웹 애플리케이션 설계 방법에 대해서 알아본다. 좋은 애플리케이션을 만들기 위해 사용되는 여러가지 패턴들에 대해서 알아보고, 웹 애플리케이션의 성능과 확장성을 개선하기 위해 사용하는 테크닉과 도구들에 대해서 알아볼것이다.
- 마지막으로 14장에서는 웹서비스의 정보에 접근하는 에이전트로 서블릿을사용하는 방법에 대해서 알아볼것이다.
이책의 소스 코드를 다운로드 하는 방법
http://www.wrox.com/에 접속하여, 검색 기능을 이요하면 이책의 코드를 다운로드 할수 있다.
1, 엔터프라이즈 환경의 서블릿
자바는 분산 프렛폼에서 사용할수 있는 이미 검증된기술이다. 이책을 읽고 있는 독자들은 이미 J2SE에 익숙할거싱다. 이책에서 초점을 맞추어 진행 할 내용은 J2EE이다. 좀더 정확하게 말하자면, J2EE의 한 부분인 자바 서블릿 2.3API에 대해서 자세하게 다룰 것이다.
J2SE를 기반으로 한 J2EE는 엔터프라이즈 애플리케이션개발과 배치에 필요한 API와 서비스들을 제공한다. J2SE와 J2EE의 서비스와 라이브러리를 이용하면 플래폼 독립적인 웹 서기반 애플리케이션 개발을 쉽게 할수 있다. 그리고 J2EE 플렛폼에서는 J2EE애플리케이션이 설치되고 작동될 환경을 서버 벤더가 제공할수 있다.
- 분산 애플리케이션으로 앤터프라이즈 아키텍처를 구성하는 방법과 웹 애플리케이션이 포함되는 계층에 대해서 알아본다.
- J2EE아키텍처가 웹 컨테이너와 자바 서블릿을 이용하여 쉽게 웹 개발을 하는 방법과 서블릿 개발자들이 애플리케이션을 개발하면서 필요한 J2EE서비스와 라이브러리에 대해 알아본다.
- 서블릿 2.4 스펙을 이용하여 자바 서블릿으로 웹 애플리케이션을 개발할때 얻을수 잇는 장점에 대해서 알아본다.
- 컨테이너 제작 업체와 개발자가 서블릿 스펙을 구현할때 각자의 역할에 대해서 이야기 하며, 서블릿 스펙의 참조 구현 웹 컨테이너 / 서버인 톰캣을 소개한다.
- 이장의 마무리는 앤터프라이즈 애플리케이션에서 서블릿의 역할, 중요성, 적절함 등에 대해서 알아본다.
ㅇ 네트워크와 프로토콜
모든 시스템은 유선등의 물리적인 네트워크로 서로 연결된다. 이러한 네트워크는 컴퓨터 시스템과 그안에서 작동되는 소프트웨어들 사이에 커뮤니케이션을 위한 연결을 제공한다. 기본적인 네트워크 토폴로지들은 아래 내용과 같다.
- 스타 토폴로지 : 허브라고 불리는 중심점이 되는 컴퓨터에 연결시키는데 사용된다.
- 링 토폴로지 : 각각의 컴퓨터들이 막힌 루프형태로 서로 연결되어 있다.
- 공유된 하나의 통로를 이용하여 시스템 커뮤니케이션을 한다.
이 토폴로지들은 주로 LAN환경에서 사용된다. 이러한 토폴로지들은 가장 일반적인 구조이며, 서로 조합되거나 파생된 형태의 다른 토폴로지도 존재한다.
프로토콜이란 커뮤니케이션을 위한 규칙의 집합이다. 많은 프로토콜들이 공통 표준과 메시지 형식을 지정하여 개발되었기 때문에, 서로 다른 시스템간에 정보와 데이터를 교환할수 있다. 이러한 프로토콜은 특정 서비스를 제공하도록 설계되었으며, 실뢰성있는 네트워킹 서비스를 제공하기 위하여 계층으로 되어 있다.
물리적 단계에서는 하드웨어적인 물리적 연결이 통신하는 컴퓨터들 사이에 놓이게 된다. 그리고, 필수적으로 네트워크 카드와 유무선 연결이 포함된다. 이러한 연결은 컴퓨터간에 전달하는 메시지가 전달될 매체를 제공된다.
네트워크 레이어에서는 컴퓨터간의 커뮤니케이션을 수비게 해주는 이더넷과 같은 프로토콜을 구현하며, 데이터를 프레임이라는 단위로 나누어 네트워크로전송하는것을 다룬다. 또한 데이터 전송크기와 큰 메시지의 분할과 재조립 방법을 결정혐, 네트워크에 문제가 발생하였을때 처리할 방법도 결정하게 된다.
시스템에서 전송된 메시지들은 계층화된 프로토콜에 쌓여서 네트워크에 있는 다른 시스템으로 전송되며, 메시지를 받은 시스템에서는 반대로 메시지의 프로토콜을 제거한다. 논리적으로 각 레이어는 상대 컴퓨터의 동일한 레이어와 통신하게 된다.
TCP/IP
IP는 패킷의 크기를 결정하고 각 패킷이 목적지로 찾아가는 매커니즘을 정의하게 된다. 이 프로토콜은 연결된 컴퓨터의 IP주소를 이용하여 데이터가 네트워크를 통해 목적지로 찾아 갈수 있게 한다. 그리고 데이터의 유실이나 도착 순서가 바뀌는 등의 문제 ㅁ때문에 비교적 신뢰할수 없는 프로ㅗ콜이기도 하다. TCP는 연결성 통신으로 애플리케이션 레이어를 제공한다. 그리고 데이터의 모든 패킷을 받고 정확한 순서로 재조립하기 땜분에 IP와는 다르게 신뢰성이 있다.
HTTP
주로 애플리케이션 레이어의 통신방법으로 제공된다. 웹애플리케이션에서 가장 많이 사용되는 프로토콜은 HTTP이다. 웹 컨테이너와 J2EE 애플리케이션들은 사용자의 요청, 응답 프로토콜로 HTTP를 지원해야 한다. 웹의 가장 일반적인 최상위 프로토콜이기 때문에 HTTP를 사용하는 애플리케이션은 통신하려는 대부분의 서버들과 메시ㅣ지 교환이 가능하다.
HTTP는 송수신 요청을 정의된 형식으로 제공하며, 서로 다른 시스템과 언어로 개발된 애플리케이션들이 통신할수 있는 공통 언어의 역할을 하게 된다.
HTTP는 다른 프로토콜보다 많은 서버와 클라이언트가 사용하룻 이슨 웹의 표준언어이며, 대부분의 웹 서블릿 개발에 사용되는 궁극적인 프로토콜이다.
ㅇ계층화된 아키텍쳐
엔터프라이즈 애플리이케이션 개발 방식이 점점 3계층이상의 다계층 애플리케이션 모델로 많이 변화되고 있다. 애플리케이션을 논리적으로 서로 다른 여러 계층으로 분리 시키는것은 아래와 같은 장점이 있다.
- 관련된 규칙과 각 계층에 적합한 기능을 모듈로 캡슐화 할수 있으며, 쉬운 유지보수와 개발이 가능하다.
- 모듈화는 컴포넌트 기반 개발을 통하여 비즈니스, 프리젠테이션 등 로직의 유연성과 재사용성에 도움을 준다.
- 다른 계층간의 관계와 제공해야 할 서비스들을 미리 정의한다면, 각 개발자들이 자신이 갖고 있는 기술들을 특정 계층에만 초점을 맞추어 개발 할수 있다.
클라이언트 계층 : 데이터와 정보를 사용자에게 설명하거나 보여주는 계층이다.
서버와 중간계층 : 클라이언트가 요청한 데이터나 액션을 처리하여 응답한다. 여기서는 일반적으로 핵심 애플리케이션 로직이 존재하게 된다. 그러나 중간계층은 다시 두개의 계층으로 구분되게 된다.
비즈니스 계층 : 비즈니스 로직을 책임지는 계층이다. 애플리케이션 신뢰도를 위해 비즈니스규칙을 구현하는 것이 중요하다.
웹 계층(프리젠테이션 계층) : 비즈니스 데이터를 클라이언트에게 보여주기 위해서 재가공하는 계층이다. 클라리언트의 요청을 받아 해당되는 비즈니스 로직이 있는 비즈니스 계층으로 데이터를 포워드 한다.
ㅇ J2EE 플랫폼
자바는 스펙에 따라 표준화도니 많은 서비스와 API가 있기 때문에 개발자가 쉽게 이용할수 있다. 다시말해 표준에 맞는 서버에서 개발한다면, 다른 벤더의 서버에서도 별 다른 어려움 없이 개발된 애플리케이션을 배치 할수 있다는 의미이다.
J2EE 애플리케이션의 자바 기반 클라이언트는 씬 클라이언트의 구조를 이용한다. 씬 클라이언트란 서버와 통신하는 비교적 가벼운 클라이언트 애플리케이션을 의미한다.
ㅇ 웹 컨테이너
웹 애플리케이션을 위한 웹 컴포넌트인 서블릿과 JSP페이지의 실행을 관리하는 자바 실행환경이다. 그리고 웹 서바나 애플리케이션 서벙듸 일부분으로 요청과 응답을 만드는 네트워크 서비스를 제공한다. 웹 컨테이너는 반드시 HTTP를 지원해야 하며, 부가적으로 다른 종류의 프로토콜을 지원할수 있고, 웹 서버의 일부분으로 제작되거나 웹 서버의 플러그인 컴포넌트로 제작될수 도 있다. 웹 컨테이너는 서블릿과 JSP 인스턴스의 라이프 사이클과 실행을 관리한다.
ㅇ EJB 컨테이너
엔터프라이즈 자바빈즈는 비즈니스 규칙과 로직이 있는 비즈니스 컴포넌트이다. EJB에는 두가지 기본적인 종류가 있으며, 구중 하나는 데이터 자체와 강하게 결합되어 데이터 접근과 영속성 관리를 하는 엔티티빈이다. 다른 하나는 세션빈으로 로직을 표현하며, 클라이언트 요청을 처리하거나 데이터 처리 로직을 담당한다.
EJB 컴포넌트는 EJB컨테이너 안에서 실행된다. EJB컴포넌트는 재사용 가능하며 최적화를 위해 인스턴스가 풀링 되고 재활용되도록 설계하였다. EJB컨테이너는 애플리케이션을 위해서 EJB컴포넌트의 실행과 폴링을 관리할 책임이 있다.
ㅇ 자바 서블릿
서블릿은 동적으로 요청을 처리하고 응답을 생성하는 자바 클래스이다. 결국 요청에대해서 동적 HTML 페이지를 응답으로 생성한다는 뜻이다. 그러나, 애플릿이나 자바 애플리케이션에 직렬화된 자바 객체를 응답으로 생성한다는 뜻이다. 그러나, 애플릿이나 자바 애플리케이션에 직렬화된 자바 객체를 응답으로 보낼수 있으며, XML 같은 다른 형태로도 응답의 데이터를 보낼수 있다. 서블릿은 서블릿 컨테이너에서 동작하며 컨테이너가 제공하는 서비스에 접근할수 있다.
ㅇ서블릿 라이프 사이클
1. 컨테이너는 서블릿이 요청을 처리하기 전에 초기화 한다.
2. 서블릿 컴포넌트는 클라이언트 계층의 요청을 받는다. 컨테이너가 실제적으로 요청을 받아 적절한 컴포넌트의 인스턴스와 연결하고, 형식화된 요청과 응답 객체를 컴포넌트에 전달한다.
3. 서블릿은 비즈니스 계층의 로직의 도움을 받거나 직접 데이터베이스나 엔터프라이즈 인포메이션 계층에서 정보를 추출하여 요청을 처리한다.
4. 처리가 끝나면 클라이언트에게 응답을 리턴한다.
5. 최정적으로 컨테이너는 생성된 서블릿 인스턴스를 종료한다.
ㅇ 서블릿 통신
1. 요청/응답 사이클 중에 클라이언트와 하는 통신
2. 컨테이너 호나경에 관한 정보나 JNDI리소스에 접근하기 위해서 서블릿 테이너와 하는 통신
3. 다른 서블릿이나 EJB같은 서버의 다른 리소스와 하는 통신
4. 요청을 처리하기 위해서 데티어베이스나 레거시 시스템, EIS와 하는 통신
일반적으로는 서블릿의 역할은 클라이언트와의 통신이다. 컩테이너와의 통신은 클라이언트에게 리턴하기 위하여 데이터를 만드는 것과 달리 서비스를 제공하는 리소스에 접근한다. 실제로 유용하게 사용하기 위해서 스블릿은 다른 서버 컴포넌트나 데이터베이스 같은 외부 백엔드 리소스와도 통신한다.
ㅇ서블릿-클라이언트 통신
클라이언트와의 통신은 여러 형태로 할수 있짐나, 텍스트기반의 통신을 한다.
HTTP통신에서 일부 또는 모든 정보 파라미터는 요청의 일부분으로 전달된다. 서버의 응답으로 부터 클라이언트에 리턴할수 있는 데이터의 형식은 클라이언트에 따라서 다르다.
ㅇ서블릿의 이점
동적으로 생성되는 페이지가 필요하였고 CGI가 개발되어 이러한 역할을 수행하였다. CGI는 분리된 프로세스로 동작하는 CGI프로그램으로 요청을 넘겨 처리하게 되어 있다. 그러나, CGI 스크립트를 분리된 새로운 프로세스로 실행시키기 위해서는 처리시간이나 서버 리소스가 낭비되고 결국 확장성에 문제가 있게 되었다. 한번 실행된후에는 서버의 리소스나 정보에 접근할수 없다는 단점을 갖고 있다. 그리고 CGI 스크립트는 데이터베이스 커넥션 같은 리소스를 공유하거나 풀링 할수 없기 대문에 성능상의 문제가 있다.
이러한 CGI를 대체하기 위해여 서버 벤더들이 만든 기술이 있다.
CGI와 자바의 가장 분명한 차이는 프로세스 실행방식이다. CGI 스크립트는 개별적인 프로세스로 동작하는 데 비하여 자바 서블릿은 서버 프로세서ㅡ의 일부로 동작하기 때문에, 확실한 성능상의 이익이다. 그리고 서블릿 인스턴스는 각각의 호출 사이에 유지되기 때문에 매번 호출될 때마다 다시 생성할 필요가 없다. 또한 서블릿은 서블릿 컨테이너와 서블릿이 실행되는 실행 환경에 접근할수 잇다. 이것은 서블릿이 데이터베이스 같은 공유자원에 접근할수 있다는 뜻이다.
서블릿은 요청-응답 형식의 모든 CGI서비스를 제공하며, J2SE, API 서블릿 API 전체 J2EE API를 포함하여 여러가지 자바 라이브러리를 사용할수 있다. 그리고 외부 벤더가 제공하는 JDBC 드라이버나 XML 파서 같은 외부의 다른 API들도 사용할수 있으며, 이러한 라이브러리와 API는 플렛폼과 서버에 독립적으로 사용할수 있다.
ㅇ프로토콜의 유연성
- javax.servlet
- javax.servlet.http
ㅇJSP 컴포넌트
JSP 는 서블릿 기술을 웹 컨텐츠를 생성하는 일부분으로써 확장한 기술이다. JSP는 directive 태그, scriptlets로 불리는 일반 자바코드와 HTML을 포함할수 있으며 태그와 scrptlet은 동적 컨텐츠를 생성하는데 사용된다. JSP페이지는 최초로 호출할때 서블릿으로 컴파일되어 실행된다.
J2EE Connector아키텍처 있는 표준 아키텍처를 제공한다. 즉, 프로그래머에게 기본 정보 시스템에 접근할수 있는
Connector 아키텍처는 개발자들에게 J2EE와 다양한 EIS접근할수 API를 제공하는 것이다.
J2EE Connector 아키텍처는 엔터프라이즈 정보 시스템과 데이터를 주고 받게 된다. Connector API를 사용하여 엔터프라이즈 정보 시스템에 접근하기 위해서는 데이터베이스를 접근하기위한 JDBC와 유사하게 동작하는 resource adapter가 필요하다.
ㅇ자바 트랜잭션 서비스
JTS는 복잡한 분산 트랜잭션 처리를 위한 API를 제공하고commit과 rollback으로 고수준의 트랜잭션을 제어할수 있게한다. 이러한 트랜잭션 서비스는 여러 데이터베이스를 하나의 트랜잭션으로 관리할 수 있게 한다. 여러 트랜잭션 중에 하나라도 실패한다면 모든 트랜잭션이 rollback 되고 반대로 실패한 트랜잭션이 없으며 전체 트랜잭션이 commit 되게 한다.
ㅇ웹애플리케이션에서 서블릿의 역할
1. 적절한 요청 파라미터를 추출하여 데이터베이스 쿼리를 만든다.
2. 데이터베이스와 연결하고 데이터베이스로부터 결과를 받는다.
3. 마지막으로 클라이언트에 적하ㅏㅂ하게 결과를 보여준다.
'BOOK Study > J2EE' 카테고리의 다른 글
| Spring Conept (0) | 2010/05/22 |
|---|---|
| 1. 서문 & 언터프라이즈 환경의 서블릿 (0) | 2010/01/25 |
| 세번째 자바 이야기 - Professional Java Sservlets 2.3 (0) | 2010/01/25 |
| 06. Java EE 6 - EJB 3.1 (0) | 2010/01/17 |
| 05. Java EE 6 - JPA 2.0 (0) | 2010/01/16 |
| 04. Java EE 6: DI (JSR 330) and CDI (JSR 299) (0) | 2010/01/14 |
- 세번째 자바 이야기 - Professional Java Sservlets 2.3
- BOOK Study/J2EE
- 2010/01/25 21:12
- Posted by 들기름왕자
C언어를 다 보고 나서 이젠 다음 것을 공부하기 위해 미루고 미루던 Servlet에 대해서 공부하기로 했다.
그래서 책을 고르다 고르다 보니. 옛날책을 고르게 되었다.
우리나라는 Servlet만을 다룬 책이 별로 없어 외국의 번역본을 보기로 했다.
원서를 샀지만. 빠르게 보고 다른것을 봐야 하는 일정때문에 이책을 고르기로 했다. 1,2 장을 보았는데 이책은 정말 쉽게 되어 있었다. Servlet에 기본적으로 쓰이는 문법들을 왜 써야 하는지에 대한 정보가 정말 마음에 들었으며, 요즘 JSP만을 배우는 학생들에게 기본을 배울수 있는 좋은 책이라는것을 알게 해주는 책이다.
이 책이 다루는 내용
|
목 차 |
서문 누구를 위한 책인가? 이 책에서 다루고 있는 내용 이 책을 읽기 위해 필요한 것들 표기 방법 고객지원 이 책의 소스 코드를 다운로드하는 방법 오탈자 P2P 온라인 포럼 제 1 장 엔터프라이즈 환경의 서블릿 엔터프라이즈 아키텍처 네트워크와 프로토콜 계층화된 아키텍처 J2EE 컨테이너 아키텍처 J2EE 컨테이너 종류 J2EE 웹 컴포넌트 자바 서블릿 JSP 컴포넌트 다른 J2EE API를 서블릿과 함께 사용하기 서블릿으로 정보 소스에 접근하기 J2EE의 메시징 서블릿 보안과 JAAS JNDI JAXP 웹 애플리케이션에서 서블릿의 역할 전형적인 서블릿 기반 애플리케이션 요약 제 2 장 서블릿 2.3 API javax.servlet 패키지 Servlet 인터페이스 서블릿의 라이프 사이클 서블릿의 정보 얻기 GenericServlet 클래스 라이프 사이클 메소드 서블릿 환경 메소드 유틸리티 메소드 기본 서블릿 만들기 Tomcat에서 서블릿 컴파일과 실행하기 요청응답 사이클 요청응답 인터페이스와 래퍼 클래스 ServletRequest 인터페이스 ServletResponse 인터페이스 입출력 스트림 서블릿컨테이너 커뮤니케이션 ServletConfig 인터페이스 ServletContext 인터페이스 ServletContext 라이프 사이클 클래스 부가적인 인터페이스 스레딩과 SingleThreadModel 인터페이스 RequestDispatcher 인터페이스 서블릿 익셉션 클래스 ServletException 클래스 UnavailableException 클래스 Personal Portal 웹 애플리케이션 Personal Portal 웹 애플리케이션 구현하기 애플리케이션 실행하기 요약 제 3 장 HTTP 서블릿 애플리케이션 레이어 프로토콜 HTTP HTTP 메소드 HTTP 헤더 HTTP 상태 코드 HTTP 인증 HTTP와 서블릿 HttpServlet 클래스 HTTP 요청과 응답 HTTP 서블릿 구현하기 HttpRequestResponseServlet 구현하기 QuizServlet 구현하기 서블릿과 커스텀 클라이언트 애플리케이션 설계하기 클라이언트 구현하기 Common 클래스 구현하기 애플리케이션 구현하기 요약 제 4 장 웹 애플리케이션 배치하기 웹 애플리케이션이란? 웹 애플리케이션의 구조 WAR ServletContext Tomcat에서 컨텍스트 정의하기 웹 애플리케이션의 라이프 사이클 디플로이먼트 디스크립터 디플로이먼트 디스크립터 예제 서블릿 정의와 매핑 서블릿 매핑 서블릿 컨텍스트 초기화 파라미터 에러 페이지 환영 페이지 파일 기반 보안 태그 순서 디플로이먼트 디스크립터의 유효성 검사 예제 웹 애플리케이션 배치하기 상점 시나리오 고급 배치 이슈 JAR 종속성 클래스 로딩 요약 제 5 장 세션 핸들링 상태 유지 없는 HTTP의 특징 클라이언트 구분과 상태 추적을 하는 이유 세션 관리 방법 URL 다시 쓰기를 이용한 세션 트래킹 쿠키를 사용하는 세션 트래킹 숨긴 폼 필드를 사용해서 세션 트래킹하기 서블릿 API를 사용하여 세션 관리하기 HttpSession 인터페이스 세션 관리 구현하기 세션 라이프 사이클 이벤트 감지하기 고급 세션 핸들링 요약 제 6 장 서블릿 영속성과 리소스 영속적인 리소스 데이터베이스 네이밍과 디렉토리 서비스 XML 서블릿 초기화와 환경설정 초기화 파라미터 서블릿 XML 환경설정 JDNI로 리소스 바인딩하기 JNDI 지원의 특징 표준 리소스 바인딩 데이터 소스 바인딩 내장 데이터 소스 바인딩 커스텀 데이터 소스 바인딩 영속적인 리소스 접근하기 DAO 패턴 인증 애플리케이션 프레임워크 JDBC를 사용해서 리소스 접근하기 LDAP을 사용해서 리소스 접근하기 서블릿 영속성 서블릿 상태 저장하기 세션 상태 저장하기 요약 제 7 장 필터 필터란 무엇인가? 새로운 기능 프로토타이핑하기 새로운 기능 추가하기 필터 이해하기 필터의 논리적 관점 필터의 물리적 관점 필터 설정하기 필터 정의하기 필터 매핑하기 필터 연결하기 필터 사용하기 필터 로그 XSLT 전환 필터 필터 연결하기 필터 설계하기 요약 제 8 장 JSP JSP 기본 JSP 스크립트 엘리먼트 선언문 스크립릿 표현식 JSP 내장 객체 디렉티브 page 디렉티브 include 디렉티브 JSP 액션 jsp:include 액션 jsp:forward 액션 jsp:param 액션 JSP 대출 계산기 JSP 페이지에서 자바빈즈 사용하기 서블릿과 JSP 함께 사용하기 데이터베이스 생성하기 시스템 아키텍처 아이템 목록 만들기 아이템 삭제하기 아이템 편집하기 아이템 수정하기 새로운 아이템 추가하기 애플리케이션 배치, 실행하기 요약 제 9 장 보안과 컨테이너 인증 서버측 자바 2 보안 모델 서버측 정책 파일 서버측 정책 파일 사용하기 SSL SSL 동작 모델 Tomcat 4에서 SSL 사용하기 서블릿 2.3 보안 보안 접근과 J2EE 비즈니스 로직 Tomcat 4의 보안 컨테이너 관리 보안 선언을 이용한 보안 사용하기 MemoryRealm 사용하기 다이제스트된 패스워드 사용하기 FORM 기반 인증 JDBCRealm 사용하기 다중 인증 요청 싱글 사인 온 프로그래밍을 이용한 보안 요약 제 10 장 서블릿 디버깅 방법 서블릿 디버깅 이슈 디버깅 방법 디버깅 툴 이벤트 중심 디버깅 필터로 디버깅하기 디버깅 필터 구현하기 디버깅 필터 사용하기 이벤트 리스너로 디버깅하기 디버깅 리스너 구현하기 디버깅 리스너 사용하기 JPDA로 디버깅하기 JDPA 디버거 구현하기 디버그 모드로 서버 실행하기 JPDA 디버거 사용하기 JPDA 디버거 출력 디버깅 결과 시각화하기 디버깅 결과 시각화 예제 디버깅 방법 선택하기 J2SE 1.4의 발전된 로그 기술 실시간 UML 역공학 요약 제 11 장 클래스 로딩과 동기화 클래스 로딩 서블릿 컨테이너의 클래스 로딩 배치 구조 클래스와 다른 리소스의 위치 Tomcat 4의 클래스 로딩 우선순위 클래스 로딩이 애플리케이션에 주는 영향 사용자 추적 애플리케이션 서블릿 로딩과 리로딩 스레드와 동기화 뱅킹 애플리케이션 단일 스레드 서블릿 사용하기 서블릿 풀링 다중 스레드 서블릿 세션과 컨텍스트 변수를 사용하는 서블릿 요약 제 12 장 웹 애플리케이션 설계와 서블릿 패턴 좋은 애플리케이션 설계의 중요성 유지보수성 재사용성 확장성 J2EE 웹 애플리케이션 설계 모델 1 아키텍처 소개 모델 2 아키텍처 소개 디자인 원칙 문서화 디자인 패턴 사용하기 J2EE 패턴 패턴을 사용하는 이유 웹 기반 토론 포럼 만들기 비즈니스 도메인 내의 엔티티 토론 포럼의 클래스 모델 모델 1 아키텍처를 사용하여 포럼 구축하기 토론 주제 보기 로그인 페이지 로그인 처리 응답 보기 새로 응답 추가하기 신규 응답 처리하기 기존 응답 삭제하기 애플리케이션의 페이지 흐름 애플리케이션 리팩토링 모델 2 아키텍처를 사용하여 포럼 구축하기 Front Controller 패턴 응답 보기 로그인 처리 새로 응답 추가하기 신규 응답 처리하기 기존 응답 삭제하기 Intercepting Filter 패턴 사용하기 View Helper 패턴 Service to Worker 패턴 사용하기 요약 제 13 장 성능과 확장성 좋은 코딩 방법 아키텍처 고려사항 비즈니스 로직 핸들링 데이터 접근하기 데이터 캐시하기 세션 관리 비동기 커뮤니케이션 사용하기 로드 밸런싱과 클러스터링 분석 툴 스트레스 테스트 툴 프로파일링 툴 커스텀 성능 모니터링 툴 모니터 프레임워크 클래스 예제 사용하기 요약 제 14 장 웹 서비스와 서블릿 에이전트 웹 서비스 웹 서비스 동작 방식 SOAP 웹 서비스 사용하기 SOAP 요청 SOAP 응답 에러 응답 Apache SOAP 웹 서비스 배치하기 Apache Axis 서블릿 에이전트 정보 수집 SOAP 서비스 사용하기 정보 캐시하기 집합과 복합 집합 예제 샘플링 애플리케이션 디자인 고려사항 현재와 미래의 도전자들 WSDL UDDI 웹 서비스 스택 트랜잭션과 웹 서비스 ACID XAML과 XLANG 요약 부록 A 톰캣 4.0 설치하기 Tomcat 4.0 설치하기 용어 정리 기본 Tomcat 설치 Tomcat 실행하기 Tomcat 4.0 디렉토리 구조 Tomcat 4.0 환경설정 도움 얻기 부록 B HTTP 레퍼런스 HTTP 버전 HTTP 트랜잭션 HTTP 클라이언트 요청 HTTP 서버 응답 HTTP 헤더 MIME 타입 상태 코드 추가 정보 부록 C 서블릿 2.3 API 레퍼런스 javax.servlet javax.servlet 인터페이스 javax.servlet 클래스 javax.servlet 익셉션 javax.servlet.http javax.servlet.http 인터페이스 javax.servlet.http 클래스 찾아보기 |
'BOOK Study > J2EE' 카테고리의 다른 글
| Spring Conept (0) | 2010/05/22 |
|---|---|
| 1. 서문 & 언터프라이즈 환경의 서블릿 (0) | 2010/01/25 |
| 세번째 자바 이야기 - Professional Java Sservlets 2.3 (0) | 2010/01/25 |
| 06. Java EE 6 - EJB 3.1 (0) | 2010/01/17 |
| 05. Java EE 6 - JPA 2.0 (0) | 2010/01/16 |
| 04. Java EE 6: DI (JSR 330) and CDI (JSR 299) (0) | 2010/01/14 |
- 06. Java EE 6 - EJB 3.1
- BOOK Study/J2EE
- 2010/01/17 21:29
- Posted by 들기름왕자
Lab Exercises
It is strongly encouraged, leveraging what is provided in this lab, you do your own experimentation meaning creating/adding your own code as much as you can.
If you have written some code that might help everyone else, please feel free to share them on this codecamp email alias or directly send them to the instructors. Your name will be recognized in this lab if your sample code is chosen to be included. For the tasks that need to be done, please see the "Things to be done" section above.)
Before you start this lab, you have to get sample applications from "glassfish-samples" and "Java EE tutorial" as described in LAB-4530: Java EE 6 - Examples.Exercise 1: EJB in a war packaging (step by step)
더보기
In this exercise, you are going to build a Web application step by step in which a servlet invokes a method of an EJB. You will see both servlet and EJB beans are included in a single war file.
- Create a new Web project
- Create a Session Bean
- Create a Servlet
- Build and run the application
- Check the war file
(1.1) Create a new project
0. Start NetBeans IDE.
1. Create a new Web project.

Figure-1.11
- For the Project Name field, enter EJB-in-a-war (or whatever project name of your choice).
- Click Next.

Figure-1.12
- Click Finish.

Figure-1.13
(1.2) Create a Session bean
1. Create a new Session bean.
- Right click project and New->Other. (If you see Session Bean in the pop-up menu, select it.)

Figure-1.21

Figure-1.21a
- For the EJB Name field, enter MySessionBean (or whatever name of your choice).
- For the Package field, enter server (or whatever package name of your choice).
- Click Finish.

Figure-1.22
2. Modify IDE generated MySessionBean.java as shown below. The modification is to add a simple business method called sayHello(..) to the bean.
| package server; import javax.ejb.Stateless; /** * * @author sang */ @Stateless public class MySessionBean { // Add business logic below. (Right-click in editor and choose // "Insert Code > Add Business Method") public String sayHello(String name){ return "Hello " + name + "!"; } } |

Figure-1.23
(1.3) Create a Servlet
In this step, you are going to create a servlet, which invokes sayHello() method of the MySessionBean you created above.
1. Create a new Servlet.

Figure-1.31
- For the Class Name field, enter HelloServlet (or whatever class name of your choice).
- For the package field, enter client (or whatever package name of your choice).
- Click Finish.

Figure-1.32
2. Inject MySessionBean into the servlet.
- Type @EJB My and observe code completion feature kicks in. (If the code completion does not appear, press CTRL+Space or CTRL+CMD+Backslash on Mac OS X.)
- Select MySessionBean (server).
- Type client;

Figure-1.33
- Observe that you have added the line in bold and red-colored font below.
| ... @WebServlet(name="HelloServlet", urlPatterns={"/HelloServlet"}) public class HelloServlet extends HttpServlet { @EJB MySessionBean client; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ... |
3. Fix imports.
- Right click any spot in the editor window and select Fix Imports.

Figure-1.34
4. Call the EJB.
- Remove comments on the statements within try{..} block.
- Modify the code as shown below. The modification is to invoke sayHello() method of the EJB.

Figure-1.35
NetBeans Tip: You can leverage code-completion feature of the IDE as shown below. When you type client. and press CTRL+SPACE ( CTRL+Space or CTRL+CMD+Backslash on Mac OS X.), observe that sayHello(String name) is one of the selections.

Figure-1.36
(1.4) Build and run the application

Figure-1.41
- Select Run under Categories on the left.
- For the Relative URL field, enter /HelloServlet. The value of the Relative URL is appended to the context path when the application is accessed for the first time.
- Click OK.

Figure-1.42
2. Build and run the application.

Figure-1.43
- Observe that "Calling EJB Hello Sang Shin!" gets displayed. This verifies that sayHello() method of the EJB is invoked successfully.

Figure-1.44
In this step, you are going to see that both EJB and Servlet classes are in the same war file.
1. Verify that a single war file contains both HelloServlet.class and MySessionBean.class.
- Select Files tab. The Files window show the files from local file system point of view.
- Expand build->web->WEB-INF->classes.
- Observe that the MySessionBean EJB is part of the war file.

Figure-1.51
Solution: The solution of this exercise is provided as "ready to build and run" NetBeans project as EJB-in-a-war under <LAB_UNZIPPED_DIRECTORY>/javaee6_ejb3.1/solutions directory.
Summary
In this exercise, you built a Web application in which EJB is used. You observed that you don't need to create EJB module jar file and you don't have to create EAR file. Instead, the war file contains the EJB.
Exercise 2: Singleton
더보기
Singletons are POJOs just like our Session beans, and the container is guaranteed to maintain a single shared instance of this Singleton. These Singletons are thread safe and also transactional. Like all other EJB’s, singletons have all the services such as security, remoting, dependency injection, web services, interceptors and so on.
In this exercise, you are going to use a singleton-based counter, which is used as an application-wide counter. You are also going to use @Startup annotation, which provides life-cycle methods.
(2.1) Singleton-based counter: "counter" sample application
1. Open counter NetBeans project (from "Java EE 6 tutorial").
- Select File->Open Project (Ctrl+Shift+O, Cmd+Shift+O on a Mac).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/docs/javaee-tutorial/examples/ejb directory. ("Java EE 6 tutorial")
- Select counter.
- Click Open Project.
- Observe that the counter project node appears under Projects tab window.
2. Build and run counter project.
- Right-click counter project and select Run.
- Browser gets displayed.
- Observe that "This page has been accessed 1 time(s)." message gets displayed.

Figure-2.11
- Click Refresh button to access the page again.
- Observe that the counter has been changed to 2 (from 1).

Figure-2.12
3. Access the application from a different user - the 2nd user. Since the counter is application-wide scope, accessing the page from the second user should increase the counter's value to 3.
- Using another instance of the browser, or different type of browser (here Safari is being used), go to http://localhost:8080/counter/

Figure-2.13
- Observe that the value of the counter is increased to 3 as expected.

Figure-2.14
4. Access the application from the first user. Now accessing the counter from the first user should increase the counter to 4.

Figure-2.15
- Observe that the counter is increased to 4 as expected.

Figure-2.16
(2.2) Study code
Note: We have not covered the "template" concept and "Facelets" of JSF 2.0 yet in this codecamp. Just consider template-client.xhtml and template.xhtml are used to display #{count.hitCount} for now.
1. template-client.xhtml. This is a JSF display page using the template called template.xhtml.
| <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"> <body> This text above will not be displayed. <ui:composition template="/template.xhtml"> This text will not be displayed. <ui:define name="title"> This page has been accessed #{count.hitCount} time(s). </ui:define> This text will also not be displayed. <ui:define name="body"> Hooray! </ui:define> This text will not be displayed. </ui:composition> This text below will also not be displayed. </body> </html> |
2. template.xhtml. This is the template.
| <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>counter - A singleton session bean example.</title> <link href="./css/default.css" rel="stylesheet" type="text/css" /> </head> <body> <h1> <ui:insert name="title"Default Title</ui:insert> </h1> <p> <ui:insert name="body"Default Body</ui:insert> </p> </body> </html> |
3. CounterBean.java. Note that CounterBean is a Singleton bean.
| package counter.ejb; import javax.ejb.Singleton; /** * * @author ian * CounterBean is a simple singleton session bean that records the number * of hits to a web page. */ @Singleton public class CounterBean { private int hits = 1; // Increment and return the number of hits public int getHits() { return hits++; } } |
4. Counter.java.
| package counter.web; import counter.ejb.CounterBean; import javax.ejb.EJB; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; /** * * @author ian */ @ManagedBean @SessionScoped public class Count { @EJB private CounterBean counterBean; private int hitCount; public Count() { this.hitCount = 0; } public int getHitCount() { hitCount = counterBean.getHits(); return hitCount; } public void setHitCount(int newHits) { this.hitCount = newHits; } } |
(2.3) Application Startup/Shutdown callbacks
The introduction of singletons also provides a convenient way for EJB applications to receive callbacks during application initialization or shutdown. By default, the container decides when to instantiate the singleton instance. However, you can force the container to instantiate the singleton instance during application initialization by using the @Startup annotation. This allows the bean to define a @PostConstruct method that is guaranteed to be called at startup time. In addition, any @PreDestroy method for a singleton is guaranteed to be called when the application is shutting down, regardless of whether the singleton was instantiated using lazy instantiation or eager instantiation. In lazy instantiation, the singleton isn't instantiated until it's method's are first needed. In eager instantiation, the singleton is instantiated at startup time whether or not it gets used.
1. Add MyStartupBean.java to the project.
| package counter.ejb; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.Singleton; import javax.ejb.Startup; @Singleton @Startup public class MyStartupBean { @PostConstruct private void startup() { System.out.println("----startup() method of MyStartupBean is called"); } @PreDestroy private void shutdown() { System.out.println("----shutdown() method of MyStartupBean is called"); } } |

Figure-2.31
2. Build and run the application.
- Right-click counter project and select Run.
- Browser gets displayed.
- Observe that "This page has been accessed 1 time(s)." message gets displayed.

Figure-2.32
3. Observe the message "----startup() method of MyStartupBean is called" in the GlassFish v3 Domain system.log.

Figure-2.33
Note: if you do the exercise 2 in sequence, you will see several instances of "----startup() method of MyStartupBean is called"and "----shutdown() method of MyStartupBean is called" because the project is redeployed before it is run or because you close the browser window inbetween.
4. Undeploy the application.

Figure-2.34
5. Observe the message "----shutdown() method of MyStartupBean is called" in the GlassFish v3 Domain system.log.

Figure-2.35
Summary
In this exercise, you learned how to use @Singleton annotation. You have also used @Startup annotation, which provides life-cycle methods.
Exercise 3: Timer
더보기
The Timer feature of EJB 3.1 provides an ability to declaratively create cron-like schedules to trigger EJB methods. All that is needed is to annotate an EJB method with the @Schedule annotation to implement the timer.
(3.1) Open, build, and run "timersession" sample application (from "Java EE 6 tutorial")
1. Open timersession NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/docs/javaee-tutorial/examples/ejb directory.
- Select timersession.
- Click Open Project.
- Observe that the timersession project node appears under Projects tab window.
2. Build and run timersession project.
- Right-click timersession project and select Run.
- Browser gets displayed.

Figure-3.11

Figure-3.12

Figure-3.13

Figure-3.14
- Observe in the GlassFish log that the Timers are first restored from the Timer Service.
- Then an automatic timeout occurs which denotes the scheduling start.
- Then the programmatic timeouts comes from the user's actions.
- The remaining automatic timeouts occur as long as the application is running.

Figure-3.14a
(3.2) Study code
1. timer-client.xhtml.
| <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <body> <ui:composition template="/timer.xhtml"> <ui:define name="title"> Timer page </ui:define> <ui:define name="body"> <p>The last programmatic timeout was: #{timerManager.lastProgrammaticTimeout}.</p> <p>The last automatic timeout was: #{timerManager.lastAutomaticTimeout}</p> <p>Set a programmatic timer here.</p> <h:form> <h:commandButton value="Set Timer" action="#{timerManager.setTimer}" /> <h:commandButton value="Refresh" action="timer-client"/> </h:form> </ui:define> </ui:composition> </body> </html> |
2. TimerManager.java.
| package timersession.web; import javax.ejb.EJB; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import timersession.ejb.TimerSessionBean; /** * * @author ian */ @ManagedBean @SessionScoped public class TimerManager { private String lastAutomaticTimeout; private String lastProgrammaticTimeout; @EJB private TimerSessionBean timerSession; /** Creates a new instance of TimerManager */ public TimerManager() { this.lastProgrammaticTimeout = "never"; this.lastAutomaticTimeout = "never"; } /** * @return the lastTimeout */ public String getLastProgrammaticTimeout() { lastProgrammaticTimeout = timerSession.getLastProgrammaticTimeout(); return lastProgrammaticTimeout; } /** * @param lastTimeout the lastTimeout to set */ public void setLastProgrammaticTimeout(String lastTimeout) { this.lastProgrammaticTimeout = lastTimeout; } public void setTimer() { long timeoutDuration = 8000; timerSession.setTimer(timeoutDuration); } /** * @return the lastAutomaticTimeout */ public String getLastAutomaticTimeout() { lastAutomaticTimeout = timerSession.getLastAutomaticTimeout(); return lastAutomaticTimeout; } /** * @param lastAutomaticTimeout the lastAutomaticTimeout to set */ public void setLastAutomaticTimeout(String lastAutomaticTimeout) { this.lastAutomaticTimeout = lastAutomaticTimeout; } } |
3. TimerSessionBean.java
| /* * Copyright 2009 Sun Microsystems, Inc. * All rights reserved. You may not modify, use, * reproduce, or distribute this software except in * compliance with the terms of the License at: * http://developer.sun.com/berkeley_license.html */ package timersession.ejb; import java.util.Date; import java.util.logging.Logger; import javax.annotation.Resource; import javax.ejb.Schedule; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerService; /** * TimerBean is a singleton session bean that creates a timer and prints out a * message when a timeout occurs. * Created March 3, 2009 12:38 PM PST * @author ian */ @Singleton @Startup public class TimerSessionBean { @Resource TimerService timerService; private Date lastAutomaticTimeout; private Date lastProgrammaticTimeout; private Logger logger = Logger.getLogger( "com.sun.tutorial.javaee.ejb.timersession.TimerSessionBean"); public void setTimer(long intervalDuration) { logger.info( "Setting a programmatic timeout for " + intervalDuration + " milliseconds from now."); // Create a single-action timer that expires after a specified duration. Timer timer = timerService.createTimer( intervalDuration, "Created new programmatic timer"); } // Designates a method that should receive EJB timer expiration @Timeout public void programmaticTimeout(Timer timer) { this.setLastProgrammaticTimeout(new Date()); logger.info("Programmatic timeout occurred."); } // Schedule a timer for automatic creation with a timeout schedule based // on a cron-like time expression. The annotated method is used as the // timeout callback method. // // Invoke the method every minute in every hour. @Schedule(minute = "*/1", hour = "*") public void automaticTimeout() { this.setLastAutomaticTimeout(new Date()); logger.info("Automatic timeout occured"); } /** * @return the lastTimeout */ public String getLastProgrammaticTimeout() { if (lastProgrammaticTimeout != null) { return lastProgrammaticTimeout.toString(); } else { return "never"; } } /** * @param lastTimeout the lastTimeout to set */ public void setLastProgrammaticTimeout(Date lastTimeout) { this.lastProgrammaticTimeout = lastTimeout; } /** * @return the lastAutomaticTimeout */ public String getLastAutomaticTimeout() { if (lastAutomaticTimeout != null) { return lastAutomaticTimeout.toString(); } else { return "never"; } } /** * @param lastAutomaticTimeout the lastAutomaticTimeout to set */ public void setLastAutomaticTimeout(Date lastAutomaticTimeout) { this.lastAutomaticTimeout = lastAutomaticTimeout; } } |
(3.3) Open, build, and run "automatic-timer" sample application (from "glassfish-samples")
1. Open automatic-timer NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/samples/javaee6/ejb directory.
- Select automatic-timer.
- Click Open Project.
- Observe that the automatic-timer-ejb project node appears under Projects tab window.
2. Build and run automatic-timer-ejb project.
- Right-click automatic-timer-ejb project and select Run.
- Observe the result in the Output window.

(3.4) Study the code
1. StatelessSession.java
| package enterprise.automatic_timer_ejb; import java.util.List; import javax.ejb.Remote; @Remote public interface StatelessSession { public List<String> getRecords(); } |
2. StatelessSessionBean.java
| package enterprise.automatic_timer_ejb; import java.util.Date; import java.util.List; import javax.ejb.Stateless; import javax.ejb.Schedule; import javax.ejb.Timer; import javax.persistence.EntityManager; import javax.persistence.Query; import javax.persistence.PersistenceContext; import enterprise.automatic_timer_ejb.persistence.LogRecord; @Stateless public class StatelessSessionBean implements StatelessSession { @PersistenceContext EntityManager em; @Schedule(second="*/3", minute="*", hour="*", info="Automatic Timer Test") public void test_automatic_timer(Timer t) { long count = (Long)em.createNamedQuery("LogRecord.countLoggedTimeouts").getSingleResult(); System.out.println("Call # " + (count + 1)); if (count > 10) { throw new IllegalStateException("Too many timeouts received: " + count); } else if (count == 10) { LogRecord lr = new LogRecord("Canceling timer " + t.getInfo() + " at " + new Date()); em.persist(lr); t.cancel(); System.out.println("Done"); } else { LogRecord lr = new LogRecord("" + t.getInfo() + " timeout received at " + new Date()); em.persist(lr); } } public List<String> getRecords() { return (List<String>)em.createNamedQuery("LogRecord.findAllRecords").getResultList(); } } |
3. LogRecord.java
| package enterprise.automatic_timer_ejb.persistence; import javax.persistence.*; //name defaults to the unqualified entity class name. //default access is property. @Entity @NamedQueries({ @NamedQuery(name = "LogRecord.countLoggedTimeouts", query = "select count(l) from LogRecord l where l.record NOT LIKE \"Canceling timer%\""), @NamedQuery(name = "LogRecord.findAllRecords", query = "select l.record from LogRecord l") }) public class LogRecord { @Id @GeneratedValue private int id; private String record; public LogRecord(String record) { setRecord(record); } public LogRecord() { } public String getRecord() { return record; } public void setRecord(String record) { this.record = record; } } |
Summary
In this exercise, you have learned the Timer feature of EJB 3.1, which provides an ability to declaratively create cron-like schedules to trigger EJB methods.
Exercise 4: Asynchronous method invocation using @Asynchronous
더보기
In previous version of EJB, the only way to accomplish asynchronous processing was by using Message Driven Beans. Even though writing MDBs was very trivial, configuring all the necessary server resources like connection factories, topics and queues made it a little bit of a chore, especially since all I needed was an asynchronous method invocation.
With EJB 3.1 these issues are easily solved by a simple annotation placed on the Session Bean: @Asynchronous. Under normal circumstances, a Session bean method call blocks the client for the duration of that call. With this annotation in place, the container returns control to the client and executes the method on a separate thread.
The Session bean method call which is annotated with the @ Asynchronous annotation can return a java.util.Future object that allows the client to retrieve a result value, check for exceptions, or attempt to cancel an in-progress invocation.
(4.1) Asynchronous method
In this exercise, a method, which performs a potentially long-ruuning database operration, in ItemEJB is called with @Asynchronous. The method returns void.
1. Open ejb3.1_asynch NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_ejb3.1/samples directory directory.
- Select ejb3.1_asynch.
- Click Open Project.
- Observe that the ejb3.1_asynch project node appears under Projects tab window.
2. Build and run ejb3.1_asynch project.
- Right-click ejb3.1_asynch project and select Run.
- Browser gets displayed.
- For the Title field, enter Life is good! (or whatever book title of your choice).
- Click Submit Query button.

Figure-4.11
- Observe that the name of the Book title gets displayed.

Figure-4.12
(4.2) Study code
1. index.html.
| <html> <head><title>Create a Book</title></head> <body> <h1>Create a new book</h1> <hr/> <form action="BookServlet"> <table border="0"> <tr> <td>Title :</td> <td><input type="text" name="title"/></td> </tr> </table> <input type="submit" name="Create a book"/> </form> <hr/> </body> </html> |
2. BookServlet.java.
| package mypackage; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import javax.ejb.EJB; @WebServlet(loadOnStartup = 1, urlPatterns = "/BookServlet") public class BookServlet extends HttpServlet { // Inject ItemEJB instance @EJB private ItemEJB itemEJB; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Creates an instance of book Book book = new Book(); book.setTitle(request.getParameter("title")); // Call EJB method asynchronously itemEJB.createBookAsynch(book); try { // Sleep for 2000 ms to give async. thread to finish the task Thread.sleep(2000); response.setContentType("text/html"); PrintWriter out = response.getWriter(); // Displays the books out.println("<h1>====== All books ======</h1>"); //List<Book> books = em.createNamedQuery("findAllBooks").getResultList(); List<Book> books = itemEJB.findAllBooks(); for (int i = 0; i < books.size(); i++) { Book b = books.get(i); out.println("Book title: " + b.getTitle() + "<br/>"); } } catch (Exception ie) { } } } |
3. ItemEJB.java
| package mypackage; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.List; import java.util.concurrent.Future; import javax.ejb.AsyncResult; import javax.ejb.Asynchronous; @Stateless public class ItemEJB { @PersistenceContext private EntityManager em; public Book createBook(Book book) { em.persist(book); return book; } @Asynchronous public void createBookAsynch(Book book) { em.persist(book); } @Asynchronous public Future<Book> createBookAsynchUsingFuture(Book book) { em.persist(book); return new AsyncResult<Book>(book); } public List<Book> findAllBooks() { return em.createNamedQuery("findAllBooks").getResultList(); } } |
4. Book.java
| package mypackage; import javax.persistence.*; @Entity @NamedQueries({ @NamedQuery(name = "findAllBooks", query = "SELECT b FROM Book b") }) public class Book { @Id @GeneratedValue private Long id; private String title; public Long getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } |
(4.3) Open, build, and run "ejb3.1_asynch_using_Future" sample application (from "Hands-on lab samples")
In this exercise, a method, which performs a potentially long-ruuning database operration, in ItemEJB is called with @Asynchronous. The method returns Future object.
1. Open ejb3.1_asynch_using_Future NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_ejb3.1/samples directory.
- Select ejb3.1_asynch_using_Future.
- Click Open Project.
- Observe that the ejb3.1_asynch_using_Future project node appears under Projects tab window.
2. Build and run ejb3.1_asynch_using_Future project.
- Right-click ejb3.1_asynch_using_Future project and select Run.
- Browser gets displayed.
- For the Title field, enter Life is good! (or whatever book title of your choice).
- Click Submit Query button.

Figure-4.31

Figure-4.32
(4.4) Study code
1. BookServlet.java
| package mypackage; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.Future; import javax.ejb.EJB; @WebServlet(loadOnStartup = 1, urlPatterns = "/BookServlet") public class BookServlet extends HttpServlet { // Inject ItemEJB instance @EJB private ItemEJB itemEJB; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Creates an instance of book Book book = new Book(); book.setTitle(request.getParameter("title")); // Call EJB method asynchronously Future<Book> future = itemEJB.createBookAsynchUsingFuture(book); try { // Sleep for 2000 ms to give async. thread to finish the task Thread.sleep(2000); response.setContentType("text/html"); PrintWriter out = response.getWriter(); // Display the newly created book out.println("<h1>====== Book that has been created asynchronously</h1>"); Book b = future.get(); out.println("Book title: " + b.getTitle() + "<br/>"); } catch (Exception ie) { } } } |
2. ItemEJB.java.
| package mypackage; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.List; import java.util.concurrent.Future; import javax.ejb.AsyncResult; import javax.ejb.Asynchronous; @Stateless public class ItemEJB { @PersistenceContext private EntityManager em; public Book createBook(Book book) { em.persist(book); return book; } @Asynchronous public void createBookAsynch(Book book) { em.persist(book); } @Asynchronous public Future<Book> createBookAsynchUsingFuture(Book book) { em.persist(book); return new AsyncResult<Book>(book); } public List<Book> findAllBooks() { return em.createNamedQuery("findAllBooks").getResultList(); } } |
Summary
In this exercise, you have learned how to use @Asynchronous annotation to invoke a EJB method in asynchronous manner.
Exercise 5: EJB Embedded (Building Embeddable EJB app step by step)
더보기
Testing EJBs was a herculean task all these years. It isn’t anymore with the timely and useful innovation of the embeddable container. The embeddable container allows you to use JPA and EJB 3.1 outside a container including testing.
In this exercise, you are going to build a standalone Java SE application in which you are going to test EJB-based application logic step by step.
(5.1) Create a new "Java Application" (Java SE) project

Figure-5.11

Figure-5.12
2. Give a name to the project.
- For the Project Name field, enter ejb3.1_embedded.
- Uncheck Create Main Class. (We don't need to create Main class.)
- Click Finish.

Figure-5.13
(5.2) Add EJB beans
In this step, you are going to add a simple Book entity class and ItemBook Stateless bean class.
1. Add Book entity class.
- Right click project and select New->Entity Class. (If you don't see Entity class from the pop-up menu, select Other, select Persistence on the left.)

Figure-5.21
- For the Class Name field, enter Book.
- For the Package field, enter mypackage.
- Click Finish.

Figure-5.22
2. Modify the IDE generated Book.java as shown below.
| package mypackage; import java.io.Serializable; import javax.persistence.*; @Entity @NamedQueries({ @NamedQuery(name = "findAllBooks", query = "SELECT b FROM Book b") }) public class Book implements Serializable { @Id @GeneratedValue private Long id; private String title; public Long getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } |

Figure-5.23
3. Create ItemEJB Stateless bean.

Figure-5.24
- For the Class Name field, enter ItemEJB.
- Click Finish.

Figure-5.25
| package mypackage; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.List; @Stateless public class ItemEJB { @PersistenceContext private EntityManager em; public Book createBook(Book book) { em.persist(book); return book; } public List<Book> findAllBooks() { return em.createNamedQuery("findAllBooks").getResultList(); } } |

Figure-5.26
return to top of exercise
(5.3) Add libraries
In this step you are going add the following library jar files.
- From the <GlassFish-v3-Installation-Directory>/glassfish/modules directory.
- gf-ejb-connector.jar
- glassfish-api.jar
- javax.ejb.jar
- javax.persistence.jar
- From <GlassFish-v3-Installation-Directory>/glassfish/modules/endorsed directory
- javax.annotation.jar
- From the <GlassFish-v3-Installation-Directory>/glassfish/lib/embedded directory.
- glassfish-embedded-static-shell.jar

Figure-5.31

Figure-5.32

Figure-5.33
2. Add library files from <GlassFish-v3-Installation-Directory>/glassfish/modules/endorsed directory

Figure-5.34
3. Add library files from <GlassFish-v3-Installation-Directory>/glassfish/lib/embedded directory.

Figure-5.35
4. Verify that the library files are added.

Figure-5.36
(5.4) Create persistence unit
1. Create persistence unit.

Figure-5.41
2. Set the values of the persistence unit.
- For the Persistence Unit Name field, take the value given by the IDE.
- For the Database Connection field, select jdbc:derby://localhost:1527/sample [app on APP].
- For the Table Generation Strategy, select Drop and Create.
- Click Finish.

Figure-5.42
3. Add entity class to the persistence unit.
- Click Add Class button for the Include Entity Classes section.

Figure-5.43
- Select mypackage.Book.
- Click OK.

Figure-5.44
4. Change Transaction Type to JTA.
- Select XML tab.
- Change the value of the transaction-type attribute to JTA.

Figure-5.45
(5.5) Add testing code
In this step, you are going to add testing code in which EJBContainer gets created, EJB are deployed and tested.
1. Create ItemEJBTest.java.
- Right click Test Packages and select New->Java Class.

Figure-5.51
- For the Class Name field, enter ItemEJBTest.
- For the Package field, enter testpackage.
- Click Finish.

Figure-5.52
| package testpackage; import mypackage.Book; import javax.ejb.embeddable.EJBContainer; import javax.naming.Context; import mypackage.ItemEJB; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class ItemEJBTest { private static EJBContainer ec; private static Context ctx; @BeforeClass public static void initContainer() throws Exception { System.out.println("----Creating EJBContainer..."); ec = EJBContainer.createEJBContainer(); ctx = ec.getContext(); } @AfterClass public static void closeContainer() throws Exception { if (ec != null) { System.out.println("----Closing EJBContainer..."); ec.close(); } } @Test public void createBook() throws Exception { System.out.println("----Looking up EJB..."); ItemEJB itemEJB = (ItemEJB) ctx.lookup("java:global/classes/ItemEJB"); // ItemEJB itemEJB = new ItemEJB(); // Counts all the books in the database int nbBooks = itemEJB.findAllBooks().size(); // Creates a new book Book book = new Book(); book.setTitle("Passion"); // Persists the book to the database System.out.println("----Creating a book..."); book = itemEJB.createBook(book); assertNotNull("ID should not be null", book.getId()); // Checks that there is an extra book in the database assertEquals("Should have an extra book", itemEJB.findAllBooks().size(), nbBooks + 1); } } |

Figure-5.53
(5.6) Build a jar file that contains EJB
1. Do the clean build.

Figure-5.61
2. Verify that the build was successful.

Figure-5.62
(5.7) Run the testing
1. Right click ItemEJBTest.java under Test Packages->testpackages and select either Run File or Test File.

Figure-5.71
2. Observe the debugging messages from the testing.

Figure-5.72
3. Observe the testing result.
- If you don't see the Testing Results window, select Window from the top-level menu and select Output->Test Results.

Figure-5.73
- Observe that the test passed.

Figure-5.74
- Observe the debugging messages.

Figure-5.75
Solution: The solution is available as "ready to open and build" NetBeans project as ejb3.1_embedded under <LAB_UNZIPPED_DIRECTORY>/javaee6_ejb3.1/solution directory.
(5.8) Use APP_NAME JNDI name
1. Modify the ItemEJBTest.java as shown below.
| package testpackage; import java.util.HashMap; import java.util.Map; import mypackage.Book; import javax.ejb.embeddable.EJBContainer; import javax.naming.Context; import mypackage.ItemEJB; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class ItemEJBTest { private static EJBContainer ec; private static Context ctx; @BeforeClass public static void initContainer() throws Exception { System.out.println("----Creating EJBContainer..."); Map<String, Object> map = new HashMap<String, Object>(); map.put(EJBContainer.APP_NAME, "myapp"); ec = EJBContainer.createEJBContainer(map); ctx = ec.getContext(); } @AfterClass public static void closeContainer() throws Exception { if (ec != null) { System.out.println("----Closing EJBContainer..."); ec.close(); } } @Test public void createBook() throws Exception { System.out.println("----Looking up EJB..."); ItemEJB itemEJB = (ItemEJB) ctx.lookup("java:global/myapp/ItemEJB"); // ItemEJB itemEJB = new ItemEJB(); // Counts all the books in the database int nbBooks = itemEJB.findAllBooks().size(); // Creates a new book Book book = new Book(); book.setTitle("Passion"); // Persists the book to the database System.out.println("----Creating a book..."); book = itemEJB.createBook(book); assertNotNull("ID should not be null", book.getId()); // Checks that there is an extra book in the database assertEquals("Should have an extra book", itemEJB.findAllBooks().size(), nbBooks + 1); } } |
2. Do the clean build.

Figure-5.81
3. Run the testing.
- Observe that the testing is successful.
Solution: The solution is available as "ready to open and build" NetBeans project as ejb3.1_embedded_jndi_APP_NAME under <LAB_UNZIPPED_DIRECTORY>/javaee6_ejb3.1/solutions directory.
Summary
In this exercise, you have learned how to test EJB through "Embeddable EJB container" feature of EJB 3.1, in which EJB container can be created programmatically and EJB are deployed and tested.
Exercise 6: EJB and RESTful service
더보기
In JAX-RS 1.1, EJB can be exposed as RESTful web service.
(6.1) Verify a simple EJB application is working
In this step, you are going to verify a simple EJB application is working as expected. We are going to expose Session bean as RESTful services.
1. Open ejb3.1_rest_base NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_ejb3.1/samples directory directory.
- Select ejb3.1_rest_base.
- Click Open Project.
- Observe that the ejb3.1_rest_base project node appears under Projects tab window.
2. Build and run ejb3.1_rest_base project.
- Right-click ejb3.1_rest_base project and select Run.
- Browser gets displayed.

Figure-6.11
- Observe that the newly created book title is displayed. This verifies the sample app is a working EJB application.

Figure-6.12
(6.2) Make the Session bean as RESTful service
| package mypackage; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.List; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @Stateless @Path("/items") public class ItemEJB { @PersistenceContext private EntityManager em; public Book createBook(Book book) { em.persist(book); return book; } @GET @Path("{bookKey}") @Produces({"application/xml", "application/json"}) public Book getBook(@PathParam("bookKey") String key) { Book theBook = em.find(Book.class, new Long(key)); return theBook; } @GET public List<Book> findAllBooks() { return em.createNamedQuery("findAllBooks").getResultList(); } } |

Figure-6.21
2. Modify Book.java as shown below.
| package mypackage; import java.io.Serializable; import javax.persistence.*; import javax.xml.bind.annotation.XmlRootElement; @Entity @NamedQueries({ @NamedQuery(name = "findAllBooks", query = "SELECT b FROM Book b") }) @XmlRootElement public class Book implements Serializable { @Id @GeneratedValue private Long id; private String title; public Long getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } |

Figure-6.22
3. Build and run the application and add two Book items into Book table.

Figure-6.23

Figure-6.24

Figure-6.25

Figure-6.26
4. Verify that the BOOK table has two entries.

5. Test the ItemEJB RESTful web service.

- Observe that the browser gets displayed.

6. Access ItemEJB as RESTful web services using browser.
- From your browser, go to http://localhost:8080/ejb3.1_rest_base/resources/items
- Observe that the two books you added are displayed in XML format.

Figure-6.27
Trouble-shooting: If you are using Safari over MacOS, the response might not be prorperly formated in XML. Please use Firefox instead..- From your browser, go to http://localhost:8080/ejb3.1_rest_base/resources/items/1
- Observe that the book item whose ID is 1 is displayed in XML format.

Figure-6.28
(6.3) Use "Curl" utility
0. Install "Curl" utility only if you are running Windows or OpenSolaris. For MacOS or other Linux OS'es, "Curl" utility comes with the OS. Reinstallation of "Curl" might cause some mal-functioning behavior on Mac OS X or other Linux OS'es.
- From your browser, go to http://curl.haxx.se/
- Download and install it.

1. Retrieve the response in JSON format.
The command to type in the terminal is highlighted in red color, the answer in blue color.
| curl -H "Accept:application/json" http://localhost:8080/ejb3.1_rest_base/resources/items {"book":[{"title":"Life is passion!"},{"title":"2nd book title"}]} |

Figure-6.31
2. Retrieve the response in XML format
The command to type in the terminal is highlighted in red color, the answer in blue color.
| curl -H "Accept:application/xml" http://localhost:8080/ejb3.1_rest_base/resources/items <?xml version="1.0" encoding="UTF-8" standalone="yes"?><books><book><title>Life is passion!</title></book><book><title>2nd book title</title></book></books> |

Figure-6.32
Solution: The solution is available as "ready to open and build" NetBeans project as ejb3.1_rest under <LAB_UNZIPPED_DIRECTORY>/javaee6_ejb3.1/solutions directory. (You will have to use ejb3.1_rest rather than ejb3.1_rest_base as application context.)
(6.4) Use @ApplicationPath annotation
1. Add ApplicationConfig.java. Note that the value of the Application path is et to resources1.
| package mypackage; @javax.ws.rs.ApplicationPath("resources1") public class ApplicationConfig extends javax.ws.rs.core.Application { } |

Figure-6.41
2. Build and run the application and add two Book items into Book table.
3. Now observe that you can use resources1 application path.

Figure-6.42

Figure-6.43
Summary
In this exercise, you have learned how to use JAX-RS annotations to expose EJB as RESTful web service.
Homework Exercise
- Exercise point: EJB in a war packaging
- Add another stateless bean called YourSessionBean with the following two methods.
- add(int x, int y)
- multiply(int x, int y)
- From the HelloServlet, call these two methods using x value 10 and y value 6 and display the result
- Add another stateless bean called YourSessionBean with the following two methods.
- Exercise point: Singleton
- Create a Singleton EJB which has the following two variables, which are used as a total values of the addition and multiplication
- int total_addition
- int total_multiplication
- Create a Singleton EJB which has the following two variables, which are used as a total values of the addition and multiplication
- Exercise point: Timer
- Use timer to display the value of total_addition and total_multiplication every hour of the day at the GlassFish v3 server log. (Basically use System.out.println(..) method.)
- Use timer to display the value of total_addition and total_multiplication every hour of the day at the GlassFish v3 server log. (Basically use System.out.println(..) method.)
- Exercise point: EJB embedded
- Create Java SE application in which the add(..) and multiply(..) methods are tested
- Create Java SE application in which the add(..) and multiply(..) methods are tested
- Zip file of the the my_ejb3.1 and my_ejb3.1_embedded NetBeans projects. (Someone else should be able to open and runthem as NetBeans projects.) You can use your favorite zip utility or you can use "jar" utility that comes with JDK as following.
- cd <parent directory that contains my_ejb3.1 directory> (assuming you named your project as my_ejb3.1)
- jar cvf my_ejb3.1.zip my_ejb3.1 (my_ejb3.1 should contain nbproject directory)
- cd <parent directory that contains my_ejb3.1 directory> (assuming you named your project as my_ejb3.1)
- Captured output screen - name it as homework_javaee6_ejb3.1.gif or homework_javaee6_ejb3.1_embedded.jpg (or homework_javaee6_ejb3.1.<whatever graphics format>) and as homework_javaee6_ejb3.1_embedded.gif or homework_javaee6_ejb3.1_embedded.jpg (or homework_javaee6_ejb3.1_embedded.<whatever graphics format>)
- Any screen capture that shows that your program is working is good enough.
'BOOK Study > J2EE' 카테고리의 다른 글
| 1. 서문 & 언터프라이즈 환경의 서블릿 (0) | 2010/01/25 |
|---|---|
| 세번째 자바 이야기 - Professional Java Sservlets 2.3 (0) | 2010/01/25 |
| 06. Java EE 6 - EJB 3.1 (0) | 2010/01/17 |
| 05. Java EE 6 - JPA 2.0 (0) | 2010/01/16 |
| 04. Java EE 6: DI (JSR 330) and CDI (JSR 299) (0) | 2010/01/14 |
| 02. Servlet 3.0 (0) | 2010/01/12 |
- 29. J2SE 5.0 Concurrency
- BOOK Study/JAVA
- 2010/01/17 20:59
- Posted by 들기름왕자
Lab Exercises
- Exercise 1: ThreadPool (30 minutes)
- Exercise 2: Executors (30 minutes)
- Exercise 3: Callable and Future (30 minutes)
- Exercise 4: Semaphore(30 minutes)
- Exercise 5: Blocking queue (30 minutes)
- Homework Exercise (for people who are taking Sang Shin's "Java Programming online course")
Exercise 1: ThreadPoolExecutor
더보기
In this exercise, you will learn how to create a pool of threads using the ThreadPoolExecutor class. You also will learn how these pool of threads are used to execute tasks.
- Build and run a server that receives connection request (using ThreadPoolExecutor)
- Build and run two instances of clients
(1.1) Build and run a server that receives connection request (using ThreadPoolExecutor)
0. Start NetBeans IDE if you have not done so yet.
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in ServerUsingThreadPoolExecutor as project name.
- For Create Main Class field, type in ServerUsingThreadPoolExecutor. (Figure-1.10 below)
- Click Finish.

Figure-1.10: Create a new project
- Observe that ServerUsingThreadPoolExecutor project appears and IDE generated ServerUsingThreadPoolExecutor.java is displayed in the source editor window of NetBeans IDE.
This class acts as a listener on an IP port and echo characters sent to it when a connection is made. This is similar in functionality to a web server type application. Since we want to be able to handle lots of short living connections simultaneously, we would create a separate thread of execution for each connection. Since thread creation is a costly operation to the JVM, the best way to achieve this is to create and use a pool of threads. A thread in this pool then can be re-used by a new connection when a previous connection is done with it.
For this example, we use an implementation of the Executor interface, ThreadPoolExecutor. To create a new instance of this, we must also first create a Queue to be used for the pool, which in this example is an ArrayBlockingQueue which provides a fixed sized, queue which is protected to ensure multiple threads can add items without contention problems.
| import java.net.*; import java.io.*; import java.util.concurrent.*; public class ServerUsingThreadPoolExecutor { private final static int MAX_THREADS = 2; private final ServerSocket serverSocket; private final ThreadPoolExecutor pool; private final ArrayBlockingQueue<Runnable> workQueue; /** * Constructor **/ public ServerUsingThreadPoolExecutor(int port, int poolSize) throws IOException { /* Create a new ServerSocket to listen for incoming connections */ serverSocket = new ServerSocket(port); /* In order to create a pool of threads, we must first have a queue * that will be used to hold the work tasks before they are executed * For this example we use a ArrayBlockingQueue that can hold the * same number of tasks as we have maximum threads */ workQueue = new ArrayBlockingQueue<Runnable>(MAX_THREADS); /* Now create a ThreadPool. The initial and maximum number of * threads are the same in this example. Please note that the * MAX_THREADS is set to 2. */ pool = new ThreadPoolExecutor(MAX_THREADS, MAX_THREADS, 60, TimeUnit.SECONDS, workQueue); } /** * Service requests **/ public void serviceRequests() { int count = 1; int qLength = 0; try { for (;;) { if ((qLength = workQueue.size()) > 0) System.out.println("Queue length is " + qLength); pool.execute(new ConnectionHandler(serverSocket.accept(), count++)); } } catch (IOException ioe) { System.out.println("IO Error in ConnectionHandler: " + ioe.getMessage()); pool.shutdown(); } } /** * Main entry point * * @param args Command line arguments **/ public static void main(String[] args) { System.out.println("Listening for connections..."); ServerUsingThreadPoolExecutor ce = null; try { ce = new ServerUsingThreadPoolExecutor(8100, 4); /* * Serve incoming connection request until interrupted. */ ce.serviceRequests(); } catch (IOException ioe) { System.out.println("IO Error creating listener: " + ioe.getMessage()); } } } |
3. Write ConnectionHandler.java as shown in Code-1.12 below.

| import java.io.*; import java.net.*; import java.util.concurrent.*; public class ConnectionHandler implements Runnable { private final Socket socket; private final int connectionID; /** * Constructor * * @param socket The socket on which incoming data will arrive **/ public ConnectionHandler(Socket socket, int connectionID) { this.socket = socket; this.connectionID = connectionID; } /** * run method to do the work of the handler **/ public void run() { System.out.println("Connection " + connectionID + ", started"); try { InputStream is = socket.getInputStream(); // Loop to do something with the socket here while (true) { byte[] inData = new byte[100]; /* If the number of bytes read is less than zero then the connection * has been terminated so we end the thread */ if (is.read(inData) < 0) break; System.out.println("[" + connectionID + "]: " + new String(inData)); } } catch (IOException ioe) { // Ignore } System.out.println("Connection " + connectionID + ", ended"); } } |
4. Build and run the project
- Right click ServerUsingThreadPoolExecutor project and select Run.
- Observe the result in the Output window. (Figure-1.13 below) The server is waiting for connection request from clients.
| Listening for connections... |

Trouble-shooting: If you see the following error condition, it is highly likely due to the fact that you have not terminate the server process that uses the same port - port 8100 in this example.
| IO Error creating listener: Address already in use: JVM_Bind |
Solution: Terminate the previously started process that uses the same port. Click Runtime tab window and expand Processes node and then right click the process and select Terminate Process. Or as a brutal method, exiting the NetBeans IDE will do it as well. Also you can use the different port number other than 8100. In this case, you will also need to change the hard-coded port number of the client.
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/ServerUsingThreadPoolExecutor. You can just open it and run it.
(1.2) Build and run two instances of ConnectionClient
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in ConnectionClient as project name.
- For Create Main Class field, type in ConnectionClient.
- Click Finish.

- Observe that ConnectionClient project appears and IDE generated ConnectionClient.java is displayed in the source editor window of NetBeans IDE.
| import java.net.*; import java.io.*; import java.util.concurrent.*; /** * ConnectionClient pass characters from the keyboard to a socket. Simplified version of * telnet */ public class ConnectionClient { /** * Main entry point * * @param args Command line arguments **/ public static void main(String[] args) { String host = null; int port = 0; if (args.length < 2) { host = "127.0.0.1"; port = 8100; } OutputStream os = null; try { // The Socket() call returns only when the connection // request from this client is accepted by the server. Socket s = new Socket(host, port); os = s.getOutputStream(); System.out.println("Connection established to server. Type characters and press <ENTER> to send"); System.out.println("Type EXIT and press <RETURN> to exit"); /* Read data from the standard input and send it to the remote socket */ while (true) { byte[] inData = new byte[100]; System.in.read(inData); String inString = new String(inData); if (inString.substring(0, 4).compareTo("EXIT") == 0) System.exit(1); os.write(inData); } } catch (Exception e) { System.out.println("Failed to connect to remote host: " + e.getMessage()); } } } |
3. Build and run the project
- Right click ConnectionClient project and select Run.
- Observe the result in the Output window. (Figure-1.23 below)
| Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |

- Enter some value into the Input field and press Enter key. (Figure-1.25 below) In this example below, "This is a message from ConnectionClient instance 1" is entered.

Figure-1.25: Enter a message
Trouble-shooting: If you see the following error condition, it is highly likely due to the fact that you have not started the server or firewall blocks the connection request.
| Failed to connect to remote host: Connection refused: connect |
Solution: Start the server. Also disable firewall on your computer,
4. Observe the output on the server side.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received from ConnectionClient is displayed. (Figure-1.26 below)

Figure-1.26: Connection request from ConnectionClient is received and message from ConnectionClient is displayed
5. Build and run another instance of ConnectionClient.
- Right click ConnectionClient project and select Run. This will start the 2nd instance of the ConnectionClient.

- Observe the result in the Output window has a ConnectionClient (run) #2 tab. (Figure-1.23 below)
| Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |

- Enter some value and press Enter key. (Figure-1.27 below) In this example, "Message from the 2nd instance of ConnectionClient by Sang Shin" is entered.

Figure-1.27: Enter data from the 2nd instance of ConnectionClient
6. Observe the output on the server side.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received fromthe 2nd instance ConnectionClient is displayed. (Figure-1.28 below)

Figure-1.28: Connection request from ConnectionClient is received and message from ConnectionClient is displayed
7. Close NetBeans in order to terminate the ServerUsingThreadPoolExecutor and ConnectionClient processes for subsequent exercises. If you skip this, you will get IO Error creating listener: Address already in use: JVM_Bind later on when you run a server program that shares the same port number.

Figure-1.29: Exit NetBeans IDE to terminate the processes
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/ConnectionClient. You can just open it and run it.
Summary
In this exercise, you learned how to create a pool of threads using the ThreadPoolExecutor class. You also will learn how these pool of threads are used to execute tasks.
Exercise 2: Implement Runnable interface
더보기
In the previous exercise, you created your own instance of ThreadPoolExecutor. There is a utility method in the Executors class that can be used to get a ThreadPoolExecutor more easily than by instantiating your own.
In this exercise, you are going to rewrite the ServerUsingThreadPoolExecutor code to use the Executors utility class. We will rename the file to ServerUsingExecutors.
(2.1) Build and run a server that receives connection requests (using Executors)
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in ServerUsingExecutors as project name.
- For Create Main Class field, type in ServerUsingExecutors.
- Click Finish.

- Observe that ServerUsingExecutors project appears and IDE generated ServerUsingExecutors.java is displayed in the source editor window of NetBeans IDE.
| import java.net.*; import java.io.*; import java.util.concurrent.*; public class ServerUsingExecutors { private final static int MAX_THREADS = 3; private final ServerSocket serverSocket; private final ExecutorService pool; public ServerUsingExecutors(int port, int poolSize) throws IOException { /* Create a new ServerSocket to listen for incoming connections */ serverSocket = new ServerSocket(port); /* Use the Exectors factory method to get a ThreadPool */ pool = Executors.newFixedThreadPool(MAX_THREADS); } /** * Service requests **/ public void serviceRequests() { int count = 1; int qLength = 0; try { for (;;) { pool.execute(new ConnectionHandler(serverSocket.accept(), count++)); } } catch (IOException ioe) { System.out.println("IO Error in ConnectionHandler: " + ioe.getMessage()); pool.shutdown(); } } public static void main(String[] args) { System.out.println("Listening for connections..."); ServerUsingExecutors ce = null; try { ce = new ServerUsingExecutors(8100, 4); ce.serviceRequests(); } catch (IOException ioe) { System.out.println("IO Error creating listener: " + ioe.getMessage()); } } } |
3. Write ConnectionHandler.java as shown in Code-2.12 below. This is the same code you've created in the Exercise 1 above.
| import java.io.*; import java.net.*; import java.util.concurrent.*; public class ConnectionHandler implements Runnable { private final Socket socket; private final int connectionID; /** * Constructor * * @param socket The socket on which incoming data will arrive **/ public ConnectionHandler(Socket socket, int connectionID) { this.socket = socket; this.connectionID = connectionID; } /** * run method to do the work of the handler **/ public void run() { System.out.println("Connection " + connectionID + ", started"); try { InputStream is = socket.getInputStream(); // Loop to do something with the socket here while (true) { byte[] inData = new byte[100]; /* If the number of bytes read is less than zero then the connection * has been terminated so we end the thread */ if (is.read(inData) < 0) break; System.out.println("[" + connectionID + "]: " + new String(inData)); } } catch (IOException ioe) { // Ignore } System.out.println("Connection " + connectionID + ", ended"); } } |
4. Build and run the project
- Right click ServerUsingExecutors project and select Run.
- Observe the result in the Output window. (Figure-1.13 below) The server is waiting for connection request from clients.
| Listening for connections... |
Trouble-shooting: If you see the following error condition, it is highly likely due to the fact that you have not terminate the server process that uses the same port - port 8100 in this example.
| IO Error creating listener: Address already in use: JVM_Bind |
Solution: Terminate the previously started process that uses the same port. Exit the NetBeans IDE will do it. Also you can use the different port number other than 8100. In this case, you will also need to change the hard-coded port number of the client.
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/ServerUsingExecutors. You can just open it and run it.
(2.2) Create and start a thread by implementing Runnable interface - start() method is in the constructor
- Right click ConnectionClient project and select Run. This will start the 1st instance of the ConnectionClient.
- Observe the result in the Output window. (Figure-2.21 below)
| Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |
- Enter some value into the Input field and press Enter key.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received from the 1st instance ConnectionClient is displayed.
- Right click ConnectionClient project and select Run. This will start the 2nd instance of the ConnectionClient.
- Observe the result in the Output window. (Figure-2.22 below)
| Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |
4. Observe the output on the server side.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received from the 2nd instance ConnectionClient is displayed.
Summary
In this exercise, you learned how to use Executors utility class to create a pool of threads.
Exercise 3: Callable and Future
더보기
The Executors class contains utility methods to convert from other common forms to Callable classes.
(3.1) Callable and Future
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in CallableAndFuture as project name.
- For Create Main Class field, type in CallableAndFuture.
- Click Finish.

- Observe that CallableAndFuture project appears and IDE generated CallableAndFuture.java is displayed in the source editor window of NetBeans IDE.
| import java.util.concurrent.*; /** * Demonstration of the use of a Future to return the results from a * Callable. This shows the simplicity of synchronising two concurrent * threads **/ public class CallableAndFuture { /** * Constructor **/ public CallableAndFuture() { } /** * Run the test **/ public void runTest() { /* Use the Executors utility method to get an ExecutorService for a * separate thread of execution */ ExecutorService threadExecutor = Executors.newSingleThreadExecutor(); System.out.println("Starting test in first thread"); /* Now attempt to run a task in the second thread */ try { Future<String> future = threadExecutor.submit(new CallableExample()); /* Set this sleep to either 100 0r 1000 to see the synchronisation * effects */ Thread.sleep(1000); System.out.println("First thread work complete. Asking future for result"); String result = future.get(); System.out.println("Result from Future is " + result); } catch (Exception e) { System.out.println("Got an exception executing the test"); System.out.println(e.getMessage()); } /* Shutdown the second thread so the program terminates gracefully */ threadExecutor.shutdown(); } /** * Main entry point * * @param args The command line arguments **/ public static void main(String[] args) { CallableAndFuture fe = new CallableAndFuture(); fe.runTest(); } } |
3. Write CallableExample.java as shown in Code-3.12 below. Study the code by paying special attention to the bold fonted parts.
| import java.net.*; import java.io.*; import java.util.concurrent.*; /** * A simple implementation of the Callable interface that can return a value * to the thread that started it **/ public class CallableExample implements Callable<String> { /** * The entry point called when this object is invoked as a new thread * of execution * * @returns A String as a simple result **/ public String call() { System.out.println("Starting call() method in second thread"); try { Thread.sleep(500); } catch (InterruptedException ie) { // Ignore } System.out.println("Completed call() method in second thread"); return "Finished"; } } |
4. Build and run the project
- Right click CallableAndFuture project and select Run.
- Observe the result in the Output window. (Figure-3.13 below)
| Starting test in first thread Starting call() method in second thread Completed call() method in second thread First thread work complete. Asking future for result Result from Future is Finished |
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/CallableAndFuture. You can just open it and run it.
Summary
In this exercise, you looked at the use of the Callable interface and a Future object so that a child thread can return a result to a parent thread.
Exercise 4: Semaphore
더보기
"Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource."
(4.1) Semaphore
In this step, you are going to build an application that displays a result that is not desirable since threads are not synchronized.
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in SemaphoreExample as project name.
- For Create Main Class field, type in ResourseUser.
- Click Finish.

- Observe that SemaphoreExample project appears and IDE generated ResourseUser.java is displayed in the source editor window of NetBeans IDE.
This class creates three threads that try to access the two reources in the pool. By using a semaphore to restrict access to the resources, this demonstrates that one of the three threads will always block when trying to aquire a resource. The threads hold a resource for different lengths of time to illustrate this more clearly.
| /** * * Concurrency utilities (JSR-166) example **/ import java.net.*; import java.io.*; import java.util.concurrent.*; /** * Use resources from a pool and return them at random times **/ public class ResourceUser implements Runnable { private ResourcePool pool; private int threadId; private int runCount; private long hold; private long pause; /** * Constructor * * @param pool The pool to get the resource from * @param threadId The id number of this thread * @param runCount The number of times to run the test loop * @param hold How long to hold the resource before releasing it * @param pause How long to wait before trying to re-aquire the resource **/ public ResourceUser(ResourcePool pool, int threadId, int runCount, long hold, long pause) { this.pool = pool; this.threadId = threadId; this.runCount = runCount; this.hold = hold; this.pause = pause; } /** * Request a resource from the pool and * return them after a random time period **/ public void run() { for (int i = 0; i < runCount; i++) { try { /* Get the resource from the pool */ System.out.println("[" + threadId + "] trying to get resource"); Integer resource = pool.getResource(); System.out.println("[" + threadId + "] aquired resource"); Thread.sleep(hold); System.out.println("[" + threadId + "] releasing resource"); pool.putResource(resource); Thread.sleep(pause); } catch (InterruptedException ie) { // Silently ignore } } } /** * Main entry point * * @param args The command line arguments **/ public static void main(String[] args) { /* Create a resource pool with two resources in it */ ResourcePool pool = new ResourcePool(2); /* Use the Executors utility class to get a new FixedThreadPool. */ ExecutorService threadExecutor = Executors.newFixedThreadPool(3); /* Create three new resource users and start them using the previously * initialised thread pool */ ResourceUser r1 = new ResourceUser(pool, 1, 5, 400, 500); ResourceUser r2 = new ResourceUser(pool, 2, 5, 800, 500); ResourceUser r3 = new ResourceUser(pool, 3, 5, 1200, 500); threadExecutor.execute(r1); threadExecutor.execute(r2); threadExecutor.execute(r3); /* Clean up the thread pool so the program terminates cleanly */ threadExecutor.shutdown(); } } |
3. Write ResourcePool.java as shown in Code-4.12 below.
| import java.net.*; import java.io.*; import java.util.concurrent.*; /** * Use a Semaphore to control the usage of a pool of resources. If a * consumer requests a resource when all are being used the consumer * will block until a resource is returned and made available. **/ public class ResourcePool { private int poolSize; private Semaphore available; private Integer[] resources; private boolean[] used; /** * Constructor * * @param poolSize Size of fixed pool of resources **/ public ResourcePool(int poolSize) { this.poolSize = poolSize; /* Create a pool of resources (for this example just a set of Integer * objects. Create a new semaphore to control access to the resources */ available = new Semaphore(poolSize); used = new boolean[poolSize]; resources = new Integer[poolSize]; for (int i = 0; i < poolSize; i++) resources[i] = new Integer(i); } /** * Get a resource. If all are currently being used this will block * until one is returned to the pool. This is a synchronised method * to make the code fully thread safe. * * @return The resource to use **/ public Integer getResource() { try { available.acquire(); } catch (InterruptedException ie) { // Ignore } for (int i = 0; i < poolSize; i++) { if (used[i] == false) { used[i] = true; return resources[i]; } } return null; } /** * Return a resource to the pool * * @param resource The resource being returned to the pool **/ public void putResource(Integer resource) { /* Note use of auto-unboxing */ used[resource] = false; available.release(); } } |
4. Build and run the project
- Right click SemaphoreExample project and select Run.
- Observe the result in the Output window. (Figure-4.14 below)
| [1] trying to get resource [1] aquired resource [2] trying to get resource [2] aquired resource [3] trying to get resource [1] releasing resource [3] aquired resource [2] releasing resource [1] trying to get resource [1] aquired resource [2] trying to get resource [1] releasing resource [2] aquired resource [3] releasing resource [1] trying to get resource [1] aquired resource [3] trying to get resource [2] releasing resource [3] aquired resource [1] releasing resource [2] trying to get resource [2] aquired resource [1] trying to get resource [3] releasing resource [1] aquired resource [2] releasing resource [1] releasing resource [3] trying to get resource [3] aquired resource [2] trying to get resource [2] aquired resource [1] trying to get resource [2] releasing resource [1] aquired resource [3] releasing resource [1] releasing resource [2] trying to get resource [2] aquired resource [3] trying to get resource [3] aquired resource [2] releasing resource [3] releasing resource [3] trying to get resource [3] aquired resource [3] releasing resource |
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javathreads/samples/SemaphoreExample. You can just open it and run it.
5. For your own exercise, do the following.
Change the values used when creating the ResourceUser objects. For example make each ResourceUser hold the resource for the same duration. Recompile and run the application and see if the application behaves differently.
| ResourceUser r1 = new ResourceUser(pool, 1, 5, 1000, 500); ResourceUser r2 = new ResourceUser(pool, 2, 5, 1000, 500); ResourceUser r3 = new ResourceUser(pool, 3, 5, 1000, 500); |
Summary
Exercise 5: Blocking queue
더보기
(5.1) Blocking queue example
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in BlockingQueueExample as project name.
- For Create Main Class field, type in BlockingQueueExample.
- Click Finish.

- Observe that BlockingQueueExample project appears and IDE generated BlockingQueueExample.java is displayed in the source editor window of NetBeans IDE.
The BlockingQueueExample class creates an ArrayBlockingQueue, which is the simplest concrete implementation of the BlockingQueue interface. It uses this to send messages to the Logger object.
| import java.net.*; import java.io.*; import java.util.concurrent.*; /** * Send messages to a Logger via a BlockingQueue **/ public class BlockingQueueExample implements Runnable { private BlockingQueue<String> messageQueue; private int id; private int count; private long pause; /** * Constructor * * @param messageQueue The quese to send messages to * @param id The ID number of this sender * @param count The number of messages to send * @param pause The pause between sending each message **/ public BlockingQueueExample(BlockingQueue<String> messageQueue, int id, int count, long pause) { this.messageQueue = messageQueue; this.id = id; this.count = count; this.pause = pause; } /** * Run method to send the messages **/ public void run() { try { for (int i = 0; i < count; i++) { messageQueue.put("ID " + id + ": log message number " + i); Thread.sleep(pause); } } catch (InterruptedException ie) { // Ignore } } /** * Main entry point for running test scenario * * @param args The command line arguments **/ public static void main(String[] args) { /* For the test we will need a BlockingQueue to be used by both threads * Initially use an ArrayBlockingQueue which is the simplest concrete * implementation of the BlockingQueue interface. The constructor takes * the size of the queue as a parameter */ ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(10); /* Use the utility method from the Executors class to get an * ExcutorService reference that will allow us to execute a single * thread */ ExecutorService loggerExecutor = Executors.newSingleThreadExecutor(); loggerExecutor.execute(new Logger(queue)); /* Again use the utility Executors class to get a new ExecutorService * for a second new thread and pass a BlockingQueueExample instance to it to run */ ExecutorService senderExecutor = Executors.newSingleThreadExecutor(); senderExecutor.execute(new BlockingQueueExample(queue, 1, 10, 500)); } } |
3. Write Logger.java as shown in Code-5.12 below. Study the code by paying special attention to the bold fonted parts.
The Logger class takes a BlockingQueue as an argument to the constructor to use as a queue to hold messages that need to be logged. The BlockingQueue will ensure thread safe operations when multiple threads are trying to add elements to the list.
| import java.net.*; import java.io.*; import java.util.concurrent.*; /** * Runnable that consumes information placed in a blocking queue. This * demonstrates the simple synchonisation that can be achieved with the * new BlockingQueue class. **/ public class Logger implements Runnable { private BlockingQueue<String> messageQueue; /** * Constructor * * @param messageQueue The queue that will be used to pass messages * between the two threads **/ public Logger(BlockingQueue<String> messageQueue) { this.messageQueue = messageQueue; } /** * Run method simply takes messages from the queue when they're there * and pushes them to the stdout **/ public void run() { try { while (true) { System.out.println("LOG MSG: " + messageQueue.take()); } } catch (InterruptedException ie) { // Ignore } } } |
4. Build and run the project
- Right click BlockingQueueExample project and select Run.
- Observe the result in the Output window. (Figure-5.15 below)
| LOG MSG: ID 1: log message number 0 LOG MSG: ID 1: log message number 1 LOG MSG: ID 1: log message number 2 LOG MSG: ID 1: log message number 3 LOG MSG: ID 1: log message number 4 LOG MSG: ID 1: log message number 5 LOG MSG: ID 1: log message number 6 LOG MSG: ID 1: log message number 7 LOG MSG: ID 1: log message number 8 LOG MSG: ID 1: log message number 9 |
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javathreads/samples/BlockingQueueExample. You can just open it and run it.
(5.2) Blocking queue example using multiple senders
- Create multiple instances of the MsgSender class with different identifiers and pause times
- Change the Executor to a ThreadPoolExecutor to support the right number of threads.
- Have the threads use different pauses between sending messages so you can see the interleaving of the different threads of execution.
2. Modify the BlockingQueueExample.java as shown in Code-5.21 below.
| import java.net.*; import java.io.*; import java.util.concurrent.*; /** * Send messages to a Logger via a BlockingQueue **/ public class BlockingQueueExample implements Runnable { private BlockingQueue<String> messageQueue; private int id; private int count; private long pause; /** * Constructor * * @param messageQueue The quese to send messages to * @param id The ID number of this sender * @param count The number of messages to send * @param pause The pause between sending each message **/ public BlockingQueueExample(BlockingQueue<String> messageQueue, int id, int count, long pause) { this.messageQueue = messageQueue; this.id = id; this.count = count; this.pause = pause; } /** * Run method to send the messages **/ public void run() { try { for (int i = 0; i < count; i++) { messageQueue.put("ID " + id + ": log message number " + i); Thread.sleep(pause); } } catch (InterruptedException ie) { // Ignore } } /** * Main entry point for running test scenario * * @param args The command line arguments **/ public static void main(String[] args) { /* For the test we will need a BlockingQueue to be used by both threads * Initially use an ArrayBlockingQueue which is the simplest concrete * implementation of the BlockingQueue interface. The constructor takes * the size of the queue as a parameter */ ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(10); /* Use the utility method from the Executors class to get an * ExcutorService reference that will allow us to execute a single * thread */ ExecutorService loggerExecutor = Executors.newSingleThreadExecutor(); loggerExecutor.execute(new Logger(queue)); /* Now create a new fixed size thread pool to allow us to run * (in this case) three sender threads */ ExecutorService senderExecutor = Executors.newFixedThreadPool(3); senderExecutor.execute(new BlockingQueueExample(queue, 1, 5, 400)); senderExecutor.execute(new BlockingQueueExample(queue, 2, 5, 800)); senderExecutor.execute(new BlockingQueueExample(queue, 3, 5, 1200)); } } |
3. Build and run the project
- Right click BlockingQueueExample project and select Run.
- Observe the result in the Output window. (Figure-5.23 below)
| LOG MSG: ID 1: log message number 0 LOG MSG: ID 1: log message number 1 LOG MSG: ID 1: log message number 2 LOG MSG: ID 1: log message number 3 LOG MSG: ID 1: log message number 4 LOG MSG: ID 1: log message number 5 LOG MSG: ID 1: log message number 6 LOG MSG: ID 1: log message number 7 LOG MSG: ID 1: log message number 8 LOG MSG: ID 1: log message number 9 |
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javathreads/samples/BlockingQueueExample2. You can just open it and run it.
Summary
Homework exercise (for people who are taking Sang Shin's "Java Programming online course")
- Increase the maximum thread size to 3 (instead of 2)
- Build and run 3 client instances (instead of 2)
- Zip file of the the MyServerUsingThreadPoolExecutor NetBeans project. (Someone else should be able to open and run it as a NetBeans project.) You can use your favorite zip utility or you can use "jar" utility that comes with JDK as following.
- cd <parent directory that contains MyServerUsingThreadPoolExecutor directory> (assuming you named your project as MyServerUsingThreadPoolExecutor)
- jar cvf MyServerUsingThreadPoolExecutor.zip MyServerUsingThreadPoolExecutor (MyServerUsingThreadPoolExecutor directory should contain nbproject directory)
- cd <parent directory that contains MyServerUsingThreadPoolExecutor directory> (assuming you named your project as MyServerUsingThreadPoolExecutor)
- Captured output screen - name it as JavaIntro-javase5concurrency.gif orJavaIntro-javase5concurrency.jpg (or JavaIntro-javase5concurrency.<whatver graphics format>)
- Any screen capture that shows that your program is working is good enough. No cosmetic polishment is required.
- If you decide to use different IDE other than NetBeans, the zip file should contain all the files that are needed for rebuilding the project - war file with necessary source files is OK.
'BOOK Study > JAVA' 카테고리의 다른 글
| 29. J2SE 5.0 Concurrency (0) | 2010/01/17 |
|---|---|
| 28. J2SE 5.0 Annotations (0) | 2010/01/17 |
| 27. J2SE 5.0 Generics (0) | 2010/01/17 |
| 26. J2SE 5.0 Language Features Enhancements (0) | 2010/01/17 |
| Java SE 5 Language Feature Enhancements (0) | 2010/01/13 |
| 25. Java Threads (0) | 2010/01/11 |
- 28. J2SE 5.0 Annotations
- BOOK Study/JAVA
- 2010/01/17 20:49
- Posted by 들기름왕자
Lab Exercises
- Exercise 1: Override annotation (20 minutes)
- Exercise 2: Single member annotation (20 minutes)
- Exercise 3: Multiple member annotation (20 minutes)
- Exercise 4: Complex annotation (20 minutes)
- Exercise 5: Meta annotation (20 minutes)
- Exercise 6: Reading annotations at runtime (20 minutes)
- Homework Exercise (for people who are taking Sang Shin's "Java Programming online course")
Exercise 1: Override annotation
더보기
| public boolean equals(String otherName) { int comparisson = name.compareTo(otherName); return (comparisson == 0); } |
The programmer thinks that they are overriding the equals() method from the Object class, but since that takes an Object as a parameter the result (which is perfectly correct Java) is an overloaded method instead. This could, potentially cause some very subtle and therefore hard to debug runtime errors. Adding a standard annotation type to this can identify these problems at compile time.
(1.1) Override annotation
0. Start NetBeans IDE if you have not done so yet.
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in OverrideAnnotation as project name.
- For Create Main Class field, type in OverrideAnnotation.
- Click Finish.

- Observe that OverrideAnnotation project appears and IDE generated OverrideAnnotation.java is displayed in the source editor window of NetBeans IDE.
| public class OverrideAnnotation { private String name; private int id; /** * Constructor **/ public OverrideAnnotation() { name = "Java Passion!"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } /** * Test of equals method overriding vs. overloading * For exercise 1 change this method **/ public boolean equals(String otherName) { int comparisson = name.compareTo(otherName); return (comparisson == 0); } public static void main(String[] args) { // TODO code application logic here } } |
3. Build and run the project
- Right click ExtendThreadClassTest0 project and select Run.
- Observe the compilation of the code succeeds. (Figure-1.13 below) This is not desirable. What we want is compile time detection of a problem.
| run: BUILD SUCCESSFUL (total time: 1 second) |
5. Modify the ExtendThreadClassTest0.java as shown in Code-1.15 below. The code fragments that need to be added are highlighted in bold and blue-colored font.
| public class OverrideAnnotation { private String name; private int id; /** * Constructor **/ public OverrideAnnotation() { name = "Java Passion!"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } /** * Test of equals method overriding vs. overloading * For exercise 1 change this method **/ @Override public boolean equals(String otherName) { int comparisson = name.compareTo(otherName); return (comparisson == 0); } public static void main(String[] args) { // TODO code application logic here } } |
6. Observe that the compiler now detects a problem. This is a desired behavior.

Figure-1.16: Result
7. Modify the ExtendThreadClassTest0.java as shown in Code-1.17 below. The code fragments that need to be added are highlighted in bold and blue-colored font.
| public class OverrideAnnotation { private String name; private int id; /** * Constructor **/ public OverrideAnnotation() { name = "Java Passion!"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } /** * Test of equals method overriding vs. overloading * For exercise 1 change this method **/ @Override public boolean equals(Object otherName) { String newName = (String) otherName; int comparison = name.compareTo(newName); return (comparison == 0); } public static void main(String[] args) { // TODO code application logic here } } |
8. Build the project. Observe that there is no compile error anymore.
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5annotation/samples/OverrideAnnotation. You can just open it and run it.
Summary
In this exercise, you learned how to use a simple marker annotation called @Override to detect an unintentional overloading at the compile time.
Exercise 2: Single-member annotation
더보기
Many annotations will only require a single value to be associated with them. Examine the Mutator.java file which contains the definition of a single membered annotation. The goal of this exercise is to edit the AnnotatedClass.java file and add a Mutator annotation to the setName method.
There are two approaches you can do this. The first approach is to modify the code as following:
| @Mutator(variable = "name") public void setName(String name) |
The second approach is as following. This is possible since this is a single member annotation we do not need to specify the name of the member to assign the value. However, if you try to compile this code, you will get a compiler error. Why? The answer is that for single member annotations the identifier used for the member must be called value. You will modify Mutator.java to correct this.
| @Mutator("name") public void setName(String name) |
(2.1) Create and start a thread by implementing Runnable interface - start() method is not in the constructor
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in MutatorAnnotation as project name.
- For Create Main Class field, type in MutatorAnnotation.
- Click Finish.

- Observe that MutatorAnnotation project appears and IDE generated RunnableThreadTest1.java is displayed in the source editor window of NetBeans IDE.
| public class MutatorAnnotation { private String name; private int id; /** * Constructor **/ public MutatorAnnotation() { name = "Java Passion!"; } public String getName() { return name; } @Mutator(variable = "name") public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } /** * Test of equals method overriding vs. overloading * For exercise 1 change this method **/ @Override public boolean equals(Object otherName) { String newName = (String) otherName; int comparison = name.compareTo(newName); return (comparison == 0); } public static void main(String[] args) { // TODO code application logic here } } |
3. Write Mutator.java.

- Modify the IDE generated Mutator.java as shown below.
| public @interface Mutator { String variable(); } |
4. Build (Compile) the project
- Right click MutatorAnnotation project and select Build or Run.
- Observe that compilation succeeds.

5. Modify the IDE generated MutatorAnnotation.java as shown in Code-2.13 below.
| public class MutatorAnnotation { private String name; private int id; /** * Constructor **/ public MutatorAnnotation() { name = "Java Passion!"; } public String getName() { return name; } @Mutator("name") public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } /** * Test of equals method overriding vs. overloading * For exercise 1 change this method **/ @Override public boolean equals(Object otherName) { String newName = (String) otherName; int comparison = name.compareTo(newName); return (comparison == 0); } public static void main(String[] args) { // TODO code application logic here } } |
6. Observe the compile error. (Figure-2.13 and Figure-2.14 below) As mentioned earlier, for single member annotations, the identifier used for the member must be called value.
| Compiling 2 source files to C:\handson2\development\javase5generics\samples(2)\MutatorAnnotation\build\classes C:\handson2\development\javase5generics\samples(2)\MutatorAnnotation\src\MutatorAnnotation.java:18: cannot find symbol symbol : method value() location: @interface Mutator @Mutator("name") 1 error BUILD FAILED (total time: 0 seconds) |

Figure-2.14: Compile error
6. Modify the Mutator.java as shown in Code-2.15 below.
| public @interface Mutator { String value(); } |
7. Build (Compile) the project
- Right click MutatorAnnotation project and select Run or Build.
- Observe that compilation succeeds.
Summary
In this exercise, you learned how to add a single-member annotation using two diffferent approaches.
Exercise 3:Multiple member annotation
더보기
(3.1) Multiple member annotation
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in MultipleMemberAnnotation as project name.
- For Create Main Class field, type in MultipleMemberAnnotation.
- Click Finish.

- Observe that MultipleMemberAnnotation project appears and IDE generated MultipleMemberAnnotation.java is displayed in the source editor window of NetBeans IDE.
| public class MultipleMemberAnnotation { private String name; private int id; public MultipleMemberAnnotation() { name = "Java Passion!"; } @Accessor(variableName = "name") public String getName() { return name; } @Accessor(variableName = "name", variableType = "int") public int getId() { return id; } public void setId(int id) { this.id = id; } /** * Test of equals method overriding v. overloading * For exercise 1 change this method **/ @Override public boolean equals(Object otherName) { String newName = (String) otherName; int comparison = name.compareTo(newName); return (comparison == 0); } public static void main(String[] args) { // TODO code application logic here } } |
3. Write Accessor.java as shown in Code-3.12 below. This file defines an annotation for accessor methods. (Accessor methods are the methods that accesses value of fields and takes the form of getXXX().) This has both the name and the type of the variable defined as members of the annotation. It also shows how to set a default value to one of its members.Study the code by paying special attention to the bold fonted parts.
| /** * Annotation definition for an accessor method. This shows the use of * multiple members. **/ public @interface Accessor { String variableName(); String variableType() default "String"; } |
4. Build and run the project
- Right click MultipleMemberAnnotation project and select Build.
- Observe that the compilation succeeds.
| compile: Building jar: C:\handson2\development\javase5generics\samples(2)\MultipleMemberAnnotation\dist\MultipleMemberAnnotation.jar To run this application from the command line without Ant, try: java -jar "C:\handson2\development\javase5generics\samples(2)\MultipleMemberAnnotation\dist\MultipleMemberAnnotation.jar" jar: BUILD SUCCESSFUL (total time: 0 seconds) |
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5annotation/samples/MultipleMemberAnnotation. You can just open it and run it.
Summary
In this exercise, you learned how to define an annotation that contains multiple members.
Exercise 4: Complex annotation types
더보기
(4.1) Complex annotation types
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in ComplexAnnotation as project name.
- For Create Main Class field, type in ComplexAnnotation.
- Click Finish.

- Observe that ComplexAnnotation project appears and IDE generated ComplexAnnotation.java is displayed in the source editor window of NetBeans IDE.
| @Reviewer(@Name(first = "James", last = "Gosling")) public class ComplexAnnotation { public static void main(String[] args) { // TODO code application logic here } } |
3. Write Name.java as shown in Code-4.12 below.
| import java.lang.annotation.*; public @interface Name { String first(); String last(); } |
4. Write Reviewer.java as shown in Code-4.13 below. Study the code by paying special attention to the bold fonted parts.
| import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) public @interface Reviewer { Name value(); } |
5. Build and run the project
- Right click ComplexAnnotation project and select Build.
- Observe the compilationresult in the Output window. (Figure-4.14 below)
| compile: run: BUILD SUCCESSFUL (total time: 0 seconds) |
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5annotation/samples/ComplexAnnotation. You can just open it and run it.
Summary
In this exercise, you will learn how to define an annotation that uses another annotation.
Exercise 5: Meta annotation
더보기
- @Target(ElementType.FIELD)
- @Retention(RetentionPolicy.RUNTIME)
- FIELD
- TYPE (Class, interface or enum definition)
- METHOD
- PARAMETER
- CONSTRUCTOR
- LOCAL_VARIABLE
- ANNOTATION_TYPE
- PACKAGE
- SOURCE: This annotation information is only retained in the source code and is not recorded in the generated class file.
- CLASS: This annotation is recorded in the class file by the compiler, but need not be retained by the virtual machine at runtime. This is the default if @Retention is not specified.
- RUNTIME: Annotations are recorded in the class file by the compiler and retained by the virtual machine at runtime and can be read reflectively.
(5.1) Producer-Consumer without inter-thread communication
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in MetaAnnotation as project name.
- For Create Main Class field, type in MetaAnnotation.
- Click Finish.

- Observe that MetaAnnotation project appears and IDE generated MetaAnnotation.java is displayed in the source editor window of NetBeans IDE.
| public class MetaAnnotation { private String name; @Exposed("name") public void setName(String name) { this.name = name; } public static void main(String[] args) { // TODO code application logic here } } |
3. Build and run the project
- Right click MetaAnnotation project and select Build.
- Observe the compile error. (Figure-5.12 below)
| Compiling 2 source files to C:\handson2\development\javase5annotation\samples\MetaAnnotation\build\classes C:\handson2\development\javase5annotation\samples\MetaAnnotation\src\MetaAnnotation.java:6: annotation type not applicable to this kind of declaration @Exposed("name") 1 error BUILD FAILED (total time: 0 seconds) |
4. Modify the MetaAnnotation.java as shown in Code-5.14 below. The modification is to use the @Expose annotation to a field instead of a method as specified.
| public class MetaAnnotation { @Exposed("name") private String name; // @Exposed("name") public void setName(String name) { this.name = name; } public static void main(String[] args) { // TODO code application logic here } } |
4. Build and run the project
- Right click MetaAnnotation project and select Build.
- Observe that compilation succeeds.
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5annotation/samples/MetaAnnotation. You can just open it and run it.
5. For your own exercise, use annotation applicable to multiple places by using an array mechanism as shown in Code-5.15 below
| @Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) |
Summary
Exercise 6: Reading annotations at runtime
더보기
The Class class now has two additional methods:
- getAnnotations() which returns an array of all annotations for the class
- getAnnotation(Class c) which returns the information about the annotation of type c passed as a parameter.
- getAnnotation(Class c) which is the same as for Class
- getDeclaredAnnotations() which returns an array of annotations declared for the Method, Constructor or Field.
(6.1) Schedule one-time task
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in RuntimeAnnotation as project name.
- For Create Main Class field, type in RuntimeAnnotation.
- Click Finish.

- Observe that RuntimeAnnotation project appears and IDE generated RuntimeAnnotation.java is displayed in the source editor window of NetBeans IDE.
| import java.lang.annotation.*; public class RuntimeAnnotation { AnnotatedClass ac; public RuntimeAnnotation() { ac = new AnnotatedClass(); } public void printAnnotations() { Class c = ac.getClass(); Annotation[] annotations = c.getAnnotations(); int numberOfAnnotations = annotations.length; System.out.println("Class " + c.getName() + " has " + numberOfAnnotations + " annotations"); for (int i = 0 ; i < numberOfAnnotations; i++) { System.out.println("Annotation " + i + ": " + annotations[i] + ", type" + annotations[i].annotationType().getName()); } } public static void main(String[] args) { RuntimeAnnotation ar = new RuntimeAnnotation(); ar.printAnnotations(); } } |
3. Write AnnotatedClass.java.
| @Reviewer(@Name(first = "James", last = "Gosling")) public class AnnotatedClass { private String name; private int id; public AnnotatedClass() { name = "Java Passion!"; } @Accessor(variableName = "name") public String getName() { return name; } @Mutator(variable ="name") public void setName(String name) { this.name = name; } @Accessor(variableName = "name", variableType = "int") public int getId() { return id; } public void setId(int id) { this.id = id; } public boolean equals(String otherName) { int comparisson = name.compareTo(otherName); return (comparisson == 0); } } |
4. Write Reviewer.java. This is the same code you've written above.
| import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) public @interface Reviewer { Name value(); } |
5. Write Name.java. This is the same code you've written above.
| import java.lang.annotation.*; public @interface Name { String first(); String last(); } |
6. Write Mutator.java. This is the same code you've written above.
| import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) public @interface Mutator { String variable(); } |
7. Write Accessor.java. This is the same code you've written above.
| import java.lang.annotation.*; /** * Annotation definition for an accessor method. This shows the use of * multiple members. **/ @Retention(RetentionPolicy.RUNTIME) public @interface Accessor { String variableName(); String variableType() default "String"; } |
8. Build and run the project
- Right click RuntimeAnnotation project and select Build.
- Observe the result in the Output window. (Figure-6.17 below)
| Class AnnotatedClass has 1 annotations Annotation 0: @Reviewer(value=@Name(first=James, last=Gosling)), typeReviewer |
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5annotation/samples/RuntimeAnnotation. You can just open it and run it.
Summary
In this exercise, you learned how to retrieve annotation information during runtime.
Homework exercise (for people who are taking Sang Shin's "Java Programming online course")
- Create a new annotation called RequestForEnhancement as following
| public @interface RequestForEnhancement { int id(); String synopsis(); String engineer() default "[unassigned]"; String date(); default "[unimplemented]"; } |
- Use the above annotation in your MyOwnAnnotationExample project to a method of your choice - in other words, you are using the above annotation to annotate a method of your choice - by providing appropriate values.
- Use Runtime annotation API to retrieve the values of the annotation (as you've done in Exercise 6 above) and display them.
- Zip file of the the MyOwnAnnotationExample NetBeans project. (Someone else should be able to open and run it as a NetBeans project.) You can use your favorite zip utility or you can use "jar" utility that comes with JDK as following.
- cd <parent directory that contains MyOwnAnnotationExample directory> (assuming you named your project as MyOwnAnnotationExample)
- jar cvf MyOwnAnnotationExample.zip MyOwnAnnotationExample (MyOwnAnnotationExample directory should contain nbproject directory)
- cd <parent directory that contains MyOwnAnnotationExample directory> (assuming you named your project as MyOwnAnnotationExample)
- Captured output screen - name it as JavaIntro-javase5annotation.gif orJavaIntro-javase5annotation.jpg (or JavaIntro-javase5annotation.<whatver graphics format>)
- Any screen capture that shows that your program is working is good enough. No cosmetic polishment is required.
- If you decide to use different IDE other than NetBeans, the zip file should contain all the files that are needed for rebuilding the project - war file with necessary source files is OK.
'BOOK Study > JAVA' 카테고리의 다른 글
| 29. J2SE 5.0 Concurrency (0) | 2010/01/17 |
|---|---|
| 28. J2SE 5.0 Annotations (0) | 2010/01/17 |
| 27. J2SE 5.0 Generics (0) | 2010/01/17 |
| 26. J2SE 5.0 Language Features Enhancements (0) | 2010/01/17 |
| Java SE 5 Language Feature Enhancements (0) | 2010/01/13 |
| 25. Java Threads (0) | 2010/01/11 |
- 27. J2SE 5.0 Generics
- BOOK Study/JAVA
- 2010/01/17 20:38
- Posted by 들기름왕자
Lab Exercises
- Exercise 1: Use Generic classes (20 minutes)
- Exercise 2: Generics and Subtyping (20 minutes)
- Exercise 3: Wild card (20 minutes)
- Exercise 4: Define your own generic class (20 minutes)
- Exercise 5: Type erasure (20 minutes)
- Exercise 6: Interoperating with non-generic code (20 minutes)
- Homework Exercise (for people who are taking Sang Shin's "Java Programming online course")
Exercise 1: Use Generic classes with type parameters
더보기
(1.1) Compile time type checking through Generics
0. Start NetBeans IDE if you have not done so yet.
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in GenericsExample1 as project name.
- For Create Main Class field, type in GenericsExample1. (Figure-1.10 below)
- Click Finish.

Figure-1.10: Create a new project
- Observe that GenericsExample1 project appears and IDE generated GenericsExample1.java is displayed in the source editor window of NetBeans IDE.
| import java.util.ArrayList; import java.util.Date; import java.util.List; public class GenericsExample1 { public static void main(String[] args) { // Notice the type declaration <Integer> for the variable ai. // It specifies that this is not just an arbitrary ArrayList, // but a ArrayList of Integer, denoted as ArrayList<Integer>. ArrayList<Integer> ai = new ArrayList<Integer>(10); ai.add(0, new Integer(20)); ai.add(1, new Long(1234)); ai.add(2, new String("xyz")); ai.add(3, new Object()); Integer i = ai.get(0); String s = ai.get(0); Object o = ai.get(0); List<String> ls = new ArrayList<String>(10); ls.add(0, new String("abc")); ls.add(1, new Integer(2)); ls.add(2, new Date()); List<Object> lo = new ArrayList<Object>(10); lo.add(0, new Integer(20)); lo.add(1, new Long(1234)); lo.add(2, new String("xyz")); lo.add(3, new Object()); } } |
3. Observe that some lines have compile errors as shown in Figure-1.12 below.

Figure-1.12: Compile errors
4. Understand why some lines have compile errors and while others don't by reading the following explanations.
Line #15, #16, #17 (lines that have red x boxes): These three lines of code result in compilation error - cannot find symbol, symbol: method add(..). The compilation errors are generated because Long, String, and Object types are not Integer type nor sub-type of it. In pre-J2SE 5.0, a ClassCastException would have occurred during runtime (if you are casting the extracted object to a incompatible type) not compile time. Here by using generics, you are detecting a problem during compile time.
Line #18: Note that you do not have to cast Integer type as you would have done in pre-J2SE 5.0. This is because compiler knows that ArrayList<Integer> contains only Integer's, it is not necessary to cast an element retrieved from the ArrayList of Integer to Integer type.
Line #19 (line that has red x box): Compiler generates compile error since String is not Integer type.
Line #20: This code works since the Integer type is Object type (meaning Integer type is a sub-class of Object type).
Line #22: When you create an instance of an ArrayList class, you also specify a type argument, <String>, to tell the compiler that the ArrayList is only to be used to hold objects of type String. (String is a final class so there should not be any sub-type of it.)
Line #23: Adding an entry of String to an ArrayList of String should work fine.
Line #24, #25 (lines that have red x boxes): These two lines of code result in compilation error - cannot find symbol, symbol: method add(..). The compilation errors are generated because Integer and Date types are not String type nor subtype of it.
Line #27: When you create an instance of an ArrayList class, you also specify a type argument, <Object>, to tell the compiler that the ArrayList is only to be used to hold objects of type Object or sub-type of it.
Line #28, #29, #30, #31: Because Integer, Long, String, and Object types are all Object type of subtype of it, adding an entry of these types to an ArrayList of Object should work fine.
5. For your own exercise, do some experimentation by improvising your own code and see if they behave as you expect. A sample code is provided in Code-1.14 below.
| // // Invoke various methods of a collection // List<Number> ln2 = new Vector<Number>(20); // Right click this line and select Fix Imports (Alt+Shift+F) ln2.add(0, new Integer(3)); ln2.add(1, new Long(1000L)); String s2 = new String("passion"); ln2.add(s2); Number n2 = ln2.get(0); Integer i2 = ln2.get(0); Boolean b2 = ln2.contains(new Integer(3)); Boolean b3 = ln2.contains(s2); System.out.println("b2="+b2); System.out.println("b3="+b3); // // Try to add an ArrayList of Integer to an ArrayList of Number // ArrayList<Integer> ai2 = new ArrayList<Integer> (10); ai2.add(new Integer(5)); ln2.addAll(ai2); // // Try to add an ArrayList of String to an ArrayList of Number // ArrayList<String> as2 = new ArrayList<String>(10); as2.add(new String("adventure")); ln2.addAll(as2); for (Number n: ln2){ System.out.println("number "+ n); } |
Summary
IIn this exercise, you got a exposure to a generic definition of a collection class, ArrayList<E>. You also learned, <E>, specifies the formal type parameter of the generic'ized ArrayList class. You also learned how to invoke the generic version of ArrayList class by replacing the formal type parameter, <E>, by concrete type argument such as <Integer>, <String>, or <Object>.
Exercise 2: Generics and subtyping
더보기
In this exercise, you will learn about a distinct behavior of Generics that might take you a while to get used to. Basically you will learn why Java compiler does not allow the following code, thus generates compilation error.
| ArrayList<Object> ao = new ArrayList<Integer>(); |
(2.1) Experiment with sub-typing
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in GenericsSubtyping as project name.
- For Create Main Class field, type in GenericsSubtyping.
- Click Finish.

- Observe that GenericsSubtyping project appears and IDE generated GenericsSubtyping.java is displayed in the source editor window of NetBeans IDE.
| import java.util.ArrayList; import java.util.List; import java.util.Vector; public class GenericsSubtyping { public static void main(String[] args) { // These should work ArrayList<Integer> ai = new ArrayList<Integer>(); ArrayList<String> as = new ArrayList<String>(); ArrayList<Object> ao1 = new ArrayList<Object>(); // There is no inheritance relationship between type arguments ArrayList<Object> ao2 = new ArrayList<String>(); ArrayList<Object> ao3 = new ArrayList<Integer>(); // There is still inheritance relationship between classes List<String> ls = new ArrayList<String>(); List<Object> lo = new ArrayList<String>(); // There is still inheritance relationship between elements in a collection object List<Number> ln1 = new Vector<Number>(); List<Number> ln2 = new Vector<Integer>(); List<Number> ln3 = new ArrayList<Long>(); } } |
3. Observe that some lines have compile errors as shown in Figure-2.12 below.

Figure-2.12
4. Understand why some lines have compile errors and while others don't by reading the following explanations.
Line #9, #10, #11: As we have learned in Exercise 2, when you create an instance of an ArrayList<E> class, you also specify a type argument, for example, ArrayList<Integer> in Line #9, ArrayList<String> in Line #10, and ArrayList<Object> in Line #11, to tell the compiler that the ArrayList is only to be used to hold objects of a particular type or sub-type of it. In other words, ArrayList<Object> can hold objects of Object type or sub-type of it.
Line #12, #13: (lines that have red x box): These two lines of code result in compilation error, for example, incompatible types, found: java.util.ArrayList<java.lang.String> required: java.util.ArrayList<java.lang.Object> for Line #12.
<Learning point> As it clearly indicates, you cannot assign an instance of ArrayList<String> to a variable of ArrayList<Object> type. Nor you can assign an instance of ArrayList<Integer> to a varaible of ArrayList<Object> type. In other words, an ArrayList of String is not an ArrayList of Object and an ArrayList of Integer is not an ArrayList of Object. This is very counter-intuitive to our understanding of OO concept but it is a very important aspect to remember in Generics.
Gilad Bracha (JSR-14 specification lead) explained why this assignment is not allowed in Generics in his Java Programming Language (Chapter 3: Generics and Subtyping) [2]. Basically if it had been allowed, then there would be a possibility of ClassCastException being thrown during runtime, which goes against the "type-safety" principle of Generics. Let's take a look an example code.
| List<String> ls = new ArrayList<String>(); //1 List<Object> lo = ls; //2 lo.add(new Object()); // 3 String s = ls.get(0); // 4: attempts to assign an Object to a String! ClassCastException would have to be thrown! |
Line 1 is certainly legal. But Line 2 is not legal in Generics. If it has been allowed, then during runtime, ClassCastException would have to be thrown in Line 4. [2]
5. For your own exercise, do some experimentation by improvising your own code and see if they behave as you expect. A sample code is provided in Code-1.14 below.
| // // Assignment of collection with parameter types // List<Object> lo5 = new ArrayList<Integer>(); List<Object> lo6 = new Vector<Integer>(5); Collection<Object> co1 = new Vector<String>(); // Right-click this line and select Fix Imports first Collection<Object> co2 = new ArrayList<Integer> (10); Collection<Integer> ci1 = new ArrayList<Integer> (10); |
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/GenericsSubtyping. You can just open it and run it.
Summary
In this exercise, you learned that ArrayList<String> is not an ArrayList<Object> and why that is the case.
Exercise 3:Wild card
더보기
(3.1) Wild card
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in GenericsWildcard as project name.
- For Create Main Class field, type in GenericsWildcard.
- Click Finish.

- Observe that GenericsWildcard project appears and IDE generated GenericsWildcard.java is displayed in the source editor window of NetBeans IDE.
| import java.util.ArrayList; import java.util.Collection; public class GenericsWildcard { static void printCollection(Collection<Object> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args) { // TODO code application logic here ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); } } |
3. Observe that some lines have compile errors as shown in Figure-3.12 below.

Figure-3.12: Compile error
4. Understand why some lines have compile errors and while others don't by reading the following explanations.
Line#15 (line that has red x box): Again, the reason the compilation error occurs on this line is because you are passing an instance of ArrayList<Integer> into where Collection<Object> is expected. By now, you should be well aware that ArrayList<Integer> is not sub-type of ArrayList<Object> and ArrayList<Integer> is not a sub-type of Collection<Object>. This is the same compilation error you have experienced in exercise 2. The compilation error you experienced in Figure-40 above has the same effect as the code in Code-41 below.
| Collection<Object> c = new ArrayList<Integer> (10); // Compilation error |
5. One way to fix this is to change the printCollection(..) method as following. Note that type, Integer, is matching between the caller and callee.
| import java.util.ArrayList; import java.util.Collection; public class GenericsWildcard { static void printCollection(Collection<Integer> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args) { ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); } } |
6. Now supposed you want to pass not only a collection of Integer but also a collection of any type such as Long, Float, or String etc. How would you change the printCollection()? You know you can't use Collection<Object> as you've seen in previous steps. Here is where the unknown type <?> (or it is called wildcard) comes into the picture. In order to accommodate a collection of any type, you can use unknown type <?> as shown in Code-3.15 below.
| import java.util.ArrayList; import java.util.Collection; public class GenericsWildcard { static void printCollection(Collection<?> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args) { // TODO code application logic here ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); ArrayList<Long> l = new ArrayList<Long>(10); printCollection(l); ArrayList<String> s = new ArrayList<String>(10); printCollection(s); } } |
The code in Code-3.15 above has the same effect as the one shown in Code-3.16 below.
| Collection<?> c = new ArrayList<Integer> (10); // This code works c = new ArrayList<Long> (10); // This code works c = new ArrayList<String> (10); // This code works |
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/GenericsWildcard. You can just open it and run it.
(3.2) Bounded wild card
Now we are ready to learn Bounded Wildcards. There may well be situations where we want to be able to define a type argument so that it is restricted to a particular class or sub-type of that class. Let's say you want to constrain the printCollection() method to receive only the Number type and its sub-types instead of any type. In other words, you want compiler to generate a compilation error when the printCollection() method receive a Collection of String type while it receives a Collection of Number, Integer, or Long without compilation errors. This is where you can use a Collection of bounded Wildcards, <? extends Number>.
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in GenericsBoundedWildcard as project name.
- For Create Main Class field, type in GenericsBoundedWildcard.
- Click Finish.

- Observe that GenericsBoundedWildcard project appears and IDE generated GenericsBoundedWildcard.java is displayed in the source editor window of NetBeans IDE.
| import java.util.ArrayList; import java.util.Collection; public class GenericsBoundedWildcard { static void printCollection(Collection<? extends Number> c){ // Bounded wildcard for (Object o: c) System.out.println(o); } public static void main(String[] args) { ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); ArrayList<Long> l = new ArrayList<Long>(10); printCollection(l); ArrayList<String> s = new ArrayList<String>(10); printCollection(s); // Now compile error should occur } } |
3. Observe that some lines have compile errors as shown in Figure-3.22 below.

Figure-3.22: Compile error
The code above has the same effect as the one shown in Code-3.23 below.
| Collection<? extends Number> c = new ArrayList<Integer> (10); // This code works c = new ArrayList<Long> (10); // This code works c = new ArrayList<String> (10); // Compilation error |
4. Now is the time you are going to your own experimentation. Improvise your own code and see if they behave as you expect. Code-3.24 below contains sample code you can experiment with.
| Collection<? extends Number> c3; c3 = new Vector<Integer>(); c3.add(new Integer(3)); c3.add(new Long(4L)); c3 = new Vector<String>(); c3 = new Vector<Long>(); c3 = new ArrayList<Date>(); Collection<? extends Object> c4; c4 = new Vector<Integer>(); c4 = new Vector<String>(); c4 = new Vector<Long>(); c4 = new ArrayList<Date>(); Collection<?> c5; c5 = new Vector<Integer>(); c5 = new Vector<String>(); c5 = new Vector<Long>(); c5 = new ArrayList<Date>(); |
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/GenericsBoundedWildcard. You can just open it and run it.
Summary
In this exercise, you have learned how to retrieve information on a ThreadGroup.
Exercise 4: Define your own Generic class
더보기
So far, you have worked with generic classes that are already provided by J2SE 5.0 SDK. In this exercise, you are going to create your own Generic class and then use the class in your code.
- Create a generic class, Pair<F, S>
- Use wild card
- Create another generic class, PairExtended<F, S, T>
- Use another generic type as a parameter
(4.1) Create a generic class, Pair<F, S>
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in MyOwnGenericClass as project name.
- For Create Main Class field, type in MyOwnGenericClass.
- Click Finish.

- Observe that MyOwnGenericClass project appears and IDE generated MyOwnGenericClass.java is displayed in the source editor window of NetBeans IDE.
| public class MyOwnGenericClass { public static void main(String[] args) { // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); // The following line of code should generate compile error // Pair<Number,String> p2 = new Pair<Number,String>(new Integer(4), new Integer(3)); System.out.println("first of p1 (right after creation) = " + p1.getFirst()); System.out.println("second of p2 (right after creation) = " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values) = " + p1.getFirst()); System.out.println("second of p1 (after setting values) = " + p1.getSecond()); } } |
3. Write Pair.java as shown in Code-4.12 below.
| public class Pair<F, S> { F first; S second; public Pair(F f, S s) { first = f; second = s; } public void setFirst(F f){ first = f; } public F getFirst(){ return first; } public void setSecond(S s){ second = s; } public S getSecond(){ return second; } } |
4. Build and run the project
- Right click MyOwnGenericClass project and select Run Project.
- Observe the result in the Output window. (Figure-4.14 below)
| first of p1 (right after creation) = 5 second of p2 (right after creation) = Sun first of p1(after setting values) = 6 second of p1 (after setting values) = rises |
(4.2) Use wild card
1. Modify the MyOwnGenericClass.java as shown in Code-4.21 below. The code fragments that need to be added are highlighted in bold and blue-colored font.
| public class MyOwnGenericClass { public static void main(String[] args) { // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); System.out.println("first of p1 (right after creation) = " + p1.getFirst()); System.out.println("second of p2 (right after creation) = " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values) = " + p1.getFirst()); System.out.println("second of p1 (after setting values) = " + p1.getSecond()); // Create an instance of Pair <F, S> class using wildcard type arguments. Number n2 = new Integer(15); String s2 = new String("again"); Pair<?, ?> p2 = new Pair<Number, String>(n2, s2); System.out.println("first of p2 = " + p2.getFirst()); System.out.println("second of p2 = " + p2.getSecond()); // Create an instance of Pair <F, S> class using wildcard with bounded type arguments. Number n3 = new Integer(25); String s3 = new String("and again!"); Pair<? extends String, ?> p3 = new Pair<String, String>(s3, s3); System.out.println("first of p3 = " + p3.getFirst()); System.out.println("second of p3 = " + p3.getSecond()); } } |
2. Build and run the project
- Right click MyOwnGenericClass project and select Run Project.
- Observe the result in the Output window. (Figure-4.24 below)
| first of p1 (right after creation) = 5 second of p2 (right after creation) = Sun first of p1(after setting values) = 6 second of p1 (after setting values) = rises first of p2 = 15 second of p2 = again first of p3 = and again! second of p3 = and again! |
(4.3) Create another Generic class, PairExtended<F, S, T>
Now you are going to create a definition of another generic class, PairExtended<F, S, T>, which extends Pair<F, S> you created in previous step.
1. Write PairExtended.java as shown in Code-4.32 below. Study the code by paying special attention to the bold fonted parts.
| public class PairExtended <F, S, T> extends Pair<F, S> { T third; /** Creates a new instance of PairExtended */ PairExtended(F f, S s, T t){ super(f, s); third = t; } public T getThird(){ return third; } } |
2. Modify the MyOwnGenericClass.java as shown in Code-4.33 below. The code fragments that need to be added are highlighted in bold and blue-colored font.
| public class MyOwnGenericClass { public static void main(String[] args) { // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); System.out.println("first of p1 (right after creation) = " + p1.getFirst()); System.out.println("second of p2 (right after creation) = " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values) = " + p1.getFirst()); System.out.println("second of p1 (after setting values) = " + p1.getSecond()); // Create an instance of Pair <F, S> class using wildcard type arguments. Number n2 = new Integer(15); String s2 = new String("again"); Pair<?, ?> p2 = new Pair<Number, String>(n2, s2); System.out.println("first of p2 = " + p2.getFirst()); System.out.println("second of p2 = " + p2.getSecond()); // Create an instance of Pair <F, S> class using wildcard with bounded type arguments. Number n3 = new Integer(25); String s3 = new String("and again!"); Pair<? extends String, ?> p3 = new Pair<String, String>(s3, s3); System.out.println("first of p3 = " + p3.getFirst()); System.out.println("second of p3 = " + p3.getSecond()); // Create an instance of PairExtended<F, S, T> class with concrete type arguments, // <Number, String, Integer> Number n4 = new Long(3000L); String s4 = new String("james"); Integer i4 = new Integer(7); PairExtended<Number, String, Integer> pe4 = new PairExtended<Number, String, Integer>(n4, s4, i4); System.out.println("first of PairExtended = " + pe4.getFirst()); System.out.println("second of PairExtended = " + pe4.getSecond()); System.out.println("third of PairExtended = " + pe4.getThird()); } } |
3. Build and run the project
- Right click MyOwnGenericClass project and select Run Project.
- Observe the result in the Output window. (Figure-4.34 below)
| first of p1 (right after creation) = 5 second of p2 (right after creation) = Sun first of p1(after setting values) = 6 second of p1 (after setting values) = rises first of p2 = 15 second of p2 = again first of p3 = and again! second of p3 = and again! first of PairExtended = 3000 second of PairExtended = james third of PairExtended = 7 |
(4.4) Use another generic type as a parameter
Add new code fragment to Main.java as shown in Code-54 below. The code fragment that needs to be added is highlighted with bold font. This code fragment contains lines of code in which invocation of PairExtended<F,S,T> generic class with concrete type arguments. This time, the third type argument is set to an instance of another collection class, ArrayList<Integer>.
1. Modify MyOwnGenericClass.java as shown in Code-4.41 below. The code fragments that need to be added are highlighted in bold and blue-colored font.
| import java.util.ArrayList; public class MyOwnGenericClass { public static void main(String[] args) { // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); System.out.println("first of p1 (right after creation) = " + p1.getFirst()); System.out.println("second of p2 (right after creation) = " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values) = " + p1.getFirst()); System.out.println("second of p1 (after setting values) = " + p1.getSecond()); // Create an instance of Pair <F, S> class using wildcard type arguments. Number n2 = new Integer(15); String s2 = new String("again"); Pair<?, ?> p2 = new Pair<Number, String>(n2, s2); System.out.println("first of p2 = " + p2.getFirst()); System.out.println("second of p2 = " + p2.getSecond()); // Create an instance of Pair <F, S> class using wildcard with bounded type arguments. Number n3 = new Integer(25); String s3 = new String("and again!"); Pair<? extends String, ?> p3 = new Pair<String, String>(s3, s3); System.out.println("first of p3 = " + p3.getFirst()); System.out.println("second of p3 = " + p3.getSecond()); // Create an instance of PairExtended<F, S, T> class with concrete type arguments, // <Number, String, Integer> Number n4 = new Long(3000L); String s4 = new String("james"); Integer i4 = new Integer(7); PairExtended<Number, String, Integer> pe4 = new PairExtended<Number, String, Integer>(n4, s4, i4); System.out.println("first of PairExtended = " + pe4.getFirst()); System.out.println("second of PairExtended = " + pe4.getSecond()); System.out.println("third of PairExtended = " + pe4.getThird()); // Create an instance of PairExtended<F. S, T> class with // with ArrayList<E> as a third type argument. ArrayList<Integer> ar4 = new ArrayList<Integer>(); // Right-click this line and select Fix Imports first ar4.add(6000); ar4.add(7000); PairExtended<Number, String, ArrayList<Integer>> pe5 = new PairExtended<Number, String, ArrayList<Integer>>(n4, s4, ar4); System.out.println("first of PairExtended with ArrayList = " + pe5.getFirst()); System.out.println("second of PairExtended with ArrayList = " + pe5.getSecond()); System.out.println("third of PairExtended with ArrayList = " + pe5.getThird()); } } |
2. Build and run the project
- Right click MyOwnGenericClass project and select Run Project.
- Observe the result in the Output window. (Figure-4.34 below)
| first of p1 (right after creation) = 5 second of p2 (right after creation) = Sun first of p1(after setting values) = 6 second of p1 (after setting values) = rises first of p2 = 15 second of p2 = again first of p3 = and again! second of p3 = and again! first of PairExtended = 3000 second of PairExtended = james third of PairExtended = 7 first of PairExtended with ArrayList = 3000 second of PairExtended with ArrayList = james third of PairExtended with ArrayList = [6000, 7000] |
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/MyOwnGenericClass. You can just open it and run it.
Summary
In this exercise, you learned how to create your own generic class and how to use it.
Exercise 5: Type erasure
더보기
The two important things about type erasure are
- Assuming all code is compiled under 5.0 and uses parameterized types you can guarantee that you won't get a ClassCastException at runtime
- There is full backwards compatibility with existing compiled code that was generated with pre-J2SE 5.0 compilers
(5.1) Type erasure example 1
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects. Click Next.
- Under Name and Location pane, for the Project Name field, type in TypeErasure as project name.
- For Create Main Class field, type in TypeErasure.
- Click Finish.
- Observe that TypeErasure project appears and IDE generated TypeErasure.java is displayed in the source editor window of NetBeans IDE.
| import java.util.ArrayList; import java.util.Collection; import java.util.List; public class TypeErasure { static void printCollection(Collection<? extends Number> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args) { // Display class information of the various ArrayList instances ArrayList<Integer> ai = new ArrayList<Integer>(); System.out.println("Class of ArrayList<Integer> = " + ai.getClass()); List<Integer> li = new ArrayList<Integer>(); System.out.println("Class of List<Integer> = " + li.getClass()); ArrayList<String> as = new ArrayList<String>(); System.out.println("Class of ArrayList<String> = " + as.getClass()); ArrayList ar = new ArrayList(); System.out.println("Class of ArrayList = " + ar.getClass()); // Check if two ArrayList instances with different type parameters // (one with Integer and the other with String) share the same class (bytecode). // Boolean b1 = (ai.getClass() == as.getClass()); System.out.println("Do ArrayList<Integer> and ArrayList<String> share same class? " + b1); // Check if two ArrayList instances with different type parameters // (one with Integer and the other with raw type) share the same class (bytecode). // Boolean b2 = (ai.getClass() == ar.getClass()); System.out.println("Do ArrayList<Integer> and ArrayList (raw type) share same class? " + b2); } } |
3. Build and run the project
- Right click TypeErasure project and select Run Project.
- Observe the result in the Output window. (Figure-5.15 below)
| Class of ArrayList<Integer> = class java.util.ArrayList Class of List<Integer> = class java.util.ArrayList Class of ArrayList<String> = class java.util.ArrayList Class of ArrayList = class java.util.ArrayList Do ArrayList<Integer> and ArrayList<String> share same class? true Do ArrayList<Integer> and ArrayList (raw type) share same class? true |
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/TypeErasure. You can just open it and run it.
(5.2) Type erasure example 2
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects. Click Next.
- Under Name and Location pane, for the Project Name field, type in TypeErasure2 as project name.
- For Create Main Class field, type in TypeErasure2.
- Click Finish.
- Observe that TypeErasure2 project appears and IDE generated TypeErasure2.java is displayed in the source editor window of NetBeans IDE.
| import java.util.List; import java.util.Vector; public class TypeErasure2 { public static void main(String[] args) { // // Get class and type information of a collection class // List<Number> ln5 = new Vector<Number>(20); Class c3 = ln5.getClass(); // Right-click this line and select Fix Imports first System.out.println("Class of List<Number> =" + c3); Class [] c4 = c3.getInterfaces(); // Right-click this line and select Fix Imports first for (Class c: c4){ System.out.println("Interface = " + c); } Class c5 = c3.getSuperclass(); System.out.println("Superclass = " + c5); } } |
3. Build and run the project
- Right click TypeErasure2 project and select Run Project.
- Observe the result in the Output window. (Figure-5.25 below)
| Class of List<Number> =class java.util.Vector Interface = interface java.util.List Interface = interface java.util.RandomAccess Interface = interface java.lang.Cloneable Interface = interface java.io.Serializable Superclass = class java.util.AbstractList |
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/TypeErasure2. You can just open it and run it.
Summary
Exercise 6: Interoperating with non-generic code
더보기
(6.1) Schedule one-time task
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects. Click Next.
- Under Name and Location pane, for the Project Name field, type in GenericsInteroperability as project name.
- For Create Main Class field, type in GenericsInteroperability.
- Click Finish.
- Observe that GenericsInteroperability project appears and IDE generated GenericsInteroperability.java is displayed in the source editor window of NetBeans IDE.
| import java.util.LinkedList; import java.util.List; public class GenericsInteroperability { public static void main(String[] args) { List<String> ls = new LinkedList<String>(); List lraw = ls; lraw.add(new Integer(4)); String s = ls.iterator().next(); } } |
3. Compile the file.
- Right click GenericsInteroperability.java and select Compile file. (Or Right click GenericsInteroperability project and select Build Project.)
- Observe the waring message below. Note that the compiler warns unchecked or unsafe operation.
| Compiling 1 source file to C:\javase5generics\samples\GenericsInteroperability\build\classes Note: C:\javase5generics\samples\GenericsInteroperability\src\GenericsInteroperability.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. |
4. Run the project
- Right click GenericsInteroperability project and select Run Project.
- Observe the runtime ClassCastException. (Figure-6.13 below) This is highly undesirable. (This is not type-safe.) Because of this reason, it is highly recommended that you do not invoke non-Generic code whenever possible.

Figure-6.13: Result of running UnGenericsInteroperability application
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/GenericsInteroperabilityWarning. You can just open it and run it.
4. Modify the GenericsInteroperability.java as shown in Code-6.14 below. The code fragment that needs to be removed (or commented out) is highlighted in bold and red-colored font while the code fragment that needs to be added is highlighted in bold and blue-colored font.
| import java.util.LinkedList; import java.util.List; public class GenericsInteroperability { public static void main(String[] args) { List<String> ls = new LinkedList<String>(); //List lraw = ls; //lraw.add(new Integer(4)); List<String> ls2 = ls; ls2.add(new Integer(4)); // Compile error String s = ls.iterator().next(); } } |
5. You should experience the compile error, which means you were able to detect type mismatch problem during the compile time rather than during runtime. (Figure-6.15 below)

Figure-6.15: Compile time type mismatch detection
NetBeans project: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5generics/samples/GenericsInteroperabilityCompileError.
Summary
In this exercise, you learned how generic and non-generic code are used together. You alo learned when unchecked exception would occur.
Homework exercise (for people who are taking Sang Shin's "Java Programming online course")
- Create PairExtendedAgain(F, S, T, F1) generic class by extending PairExtended(F, S, T)
- Modify Main.java class to invoke PairExtendedAgain(F, S, T, F1) class with concrete type arguments <Integer, Long, Object, Boolean>
- Build and run the project
- Zip file of the the MyMyOwnGenericClass NetBeans project. (Someone else should be able to open and run it as a NetBeans project.) You can use your favorite zip utility or you can use "jar" utility that comes with JDK as following.
- cd <parent directory that contains MyMyOwnGenericClass directory> (assuming you named your project as MyMyOwnGenericClass)
- jar cvf MyMyOwnGenericClass.zip MyMyOwnGenericClass (MyMyOwnGenericClass should contain nbproject directory)
- cd <parent directory that contains MyMyOwnGenericClass directory> (assuming you named your project as MyMyOwnGenericClass)
- Captured output screen - name it as JavaIntro-javase5generics.gif or JavaIntro-javase5generics.jpg (or JavaIntro-javase5generics.<whatver graphics format>)
- Any screen capture that shows that your program is working is good enough. No cosmetic polishment is required.
- If you decide to use different IDE other than NetBeans, the zip file should contain all the files that are needed for rebuilding the project.
'BOOK Study > JAVA' 카테고리의 다른 글
| 29. J2SE 5.0 Concurrency (0) | 2010/01/17 |
|---|---|
| 28. J2SE 5.0 Annotations (0) | 2010/01/17 |
| 27. J2SE 5.0 Generics (0) | 2010/01/17 |
| 26. J2SE 5.0 Language Features Enhancements (0) | 2010/01/17 |
| Java SE 5 Language Feature Enhancements (0) | 2010/01/13 |
| 25. Java Threads (0) | 2010/01/11 |
- 26. J2SE 5.0 Language Features Enhancements
- BOOK Study/JAVA
- 2010/01/17 20:31
- Posted by 들기름왕자
Lab Exercises
- Exercise 1: Autoboxing (20 minutes)
- Exercise 2: Enhanced For loop (20 minutes)
- Exercise 3: Static imports (20 minutes)
- Exercise 4: Variable arguments (20 minutes)
- Exercise 5: Type-safe enumerations (20 minutes)
- Homework Exercise (for people who are taking Sang Shin's "Java Programming online course")
Exercise 1: Autoboxing
더보기
The Autoboxing and Unboxing feature of J2SE 5.0 eliminates the drudgery of manual conversion between primitive types (such as int or long) and wrapper types (such as Integer or Long).
(1.1) Example without autoboxing
0. Start NetBeans IDE if you have not done so yet.
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in NotUsingAutoBoxing as project name.
- For Create Main Class field, type in NotUsingAutoBoxing. (Figure-1.10 below)
- Click Finish.

Figure-1.10: Create a new project
- Observe that NotUsingAutoBoxing project appears and IDE generated NotUsingAutoBoxing.java is displayed in the source editor window of NetBeans IDE.
| public class NotUsingAutoBoxing{ // Suppose the internal variables are in Wrapper types Integer iObj; Float fObj; Long lObj; Double dObj; public NotUsingAutoBoxing() { } public static void main( String[] args ) { NotUsingAutoBoxing a = new NotUsingAutoBoxing(); // You have to create instances of Wrapper classes first // before you save them into the internal variables. This // is called boxing. a.iObj = new Integer( 22 ); a.fObj = new Float( 22.0 ); a.lObj = new Long( 22L ); a.dObj = new Double( 22 ); // In the following code, you are unboxing in order to // get primitive types. System.out.println( " int Value of iObj is: " + a.iObj.intValue() ); System.out.println( " float Value of iObj is: " + a.fObj.floatValue() ); System.out.println( " long Value of iObj is: " + a.lObj.longValue() ); System.out.println( " double Value of iObj is: " + a.dObj.doubleValue() ); } } |
3. Build and run the project
- Right click NotUsingAutoBoxing project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-1.13 below)
| int Value of iObj is: 22 float Value of iObj is: 22.0 long Value of iObj is: 22 double Value of iObj is: 22.0 |
(1.2) Example with autoboxing
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects. Click Next.
- Under Name and Location pane, for the Project Name field, type in UsingAutoboxing as project name.
- For Create Main Class field, type in UsingAutoboxing.
- Click Finish.
- Observe that UsingAutoboxing project appears and IDE generated UsingAutoboxing.java is displayed in the source editor window of NetBeans IDE.
| public class UsingAutoBoxing{ // Suppose the internal variables are in Wrapper types Integer iObj; Float fObj; Long lObj; Double dObj; public UsingAutoBoxing() { } public static void main( String[] args ) { UsingAutoBoxing a = new UsingAutoBoxing(); // a.iObj = new Integer( 22 ); a.iObj = 22; // Using AutoBoxing // a.fObj = new Float( 22.0 ); a.fObj = 22.0f ; // Using AutoBoxing // a.lObj = new Long ( 22L ); a.lObj = 22L; // Using AutoBoxing // a.dObj = new Double( 22 ); a.dObj = 22d; // Using AutoBoxing // System.out.println( " int Value of iObj is: " + a.iObj.intValue() ); System.out.println( " int Value of iObj is: " + a.iObj ); // Using UnBoxing // System.out.println( " float Value of iObj is: " + a.fObj.floatValue() ); System.out.println( " float Value of iObj is: " + a.fObj ); // Using UnBoxing // System.out.println( " long Value of iObj is: " + a.lObj.longValue() ); System.out.println( " long Value of iObj is: " + a.lObj ); // Using UnBoxing // System.out.println( " double Value of iObj is: " + a.dObj.doubleValue() ); System.out.println( " double Value of iObj is: " + a.dObj ); // Using UnBoxing } } |
3. Build and run the project
- Right click UsingAutoBoxing project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-1.23 below)
| int Value of iObj is: 22 float Value of iObj is: 22.0 long Value of iObj is: 22 double Value of iObj is: 22.0 |
Summary
In this exercise, you learned how to use the Autoboxing/Unboxing functionality in J2SE 5.0, which eliminates the drudgery of manual conversion between primitive types and wrapper types.
Exercise 2: Enhanced For loop
더보기
(2.1) Example wihtout using enhanced For loop
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in NotUsingEnhancedForLoop as project name.
- For Create Main Class field, type in NotUsingEnhancedForLoop.
- Click Finish.

- Observe that NotUsingEnhancedForLoop project appears and IDE generated NotUsingEnhancedForLoop.java is displayed in the source editor window of NetBeans IDE.
| import java.util.*; public class NotUsingEnhancedForLoop { public static void main( String[] args ) { Vector<Object> v = new Vector<Object>(); v.add( new String( "Hello World" ) ); v.add( new Integer( 10 ) ); v.add( new Double( 11.0 ) ); v.add( new Long( 12 ) ); for ( Iterator i = v.iterator(); i.hasNext(); ) { System.out.println( " Vector element is: " + i.next() ); } String [] s = { "Java 2", "Platform", "Standard", "Edition", "1.5", "is", "the", "latest", "release", "of", "the", "Java", "Platform" }; for ( int i = 0; i < s.length; ++i ) { System.out.println( "String array element is: " + s[i] ); } } } |
3. Build and run the project
- Right click NotUsingEnhancedForLoop project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-2.13 below)
| Vector element is: Hello World Vector element is: 10 Vector element is: 11.0 Vector element is: 12 String array element is: Java 2 String array element is: Platform String array element is: Standard String array element is: Edition String array element is: 1.5 String array element is: is String array element is: the String array element is: latest String array element is: release String array element is: of String array element is: the String array element is: Java String array element is: Platform |
(2.2) Example with using enhanced For loop
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in UsingEnhancedForLoop as project name.
- For Create Main Class field, type in UsingEnhancedForLoop.
- Click Finish.

- Observe that UsingEnhancedForLoop project appears and IDE generated UsingEnhancedForLoop.java is displayed in the source editor window of NetBeans IDE.
| import java.util.*; public class UsingEnhancedForLoop { public static void main( String[] args ) { Vector<Object> v = new Vector<Object>(); v.add( new String( "Hello World" ) ); v.add( new Integer( 10 ) ); v.add( new Double( 11.0 ) ); v.add( new Long( 12 ) ); for ( Object o : v ) { System.out.println( " Vector element is: " + o ); } String [] s = { "Java 2", "Platform", "Standard", "Edition", "1.5", "is", "the", "latest", "release", "of", "the", "Java", "Platform" }; for ( String i : s ) { System.out.println( " String Array element is: " + i ); } } } |
3. Build and run the project
- Right click UsingEnhancedForLoop project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-2.23 below)
| Vector element is: Hello World Vector element is: 10 Vector element is: 11.0 Vector element is: 12 String array element is: Java 2 String array element is: Platform String array element is: Standard String array element is: Edition String array element is: 1.5 String array element is: is String array element is: the String array element is: latest String array element is: release String array element is: of String array element is: the String array element is: Java String array element is: Platform |
Summary
In this lab exercise, you learned how to use the Enhanced For Loops of J2SE 5.0.
Exercise 3: Static imports
더보기
(3.1) Example without using static imports
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in NotUsingStaticImport as project name.
- For Create Main Class field, type in testpackage.NotUsingStaticImport.
- Click Finish.

- Observe that NotUsingStaticImport project appears and IDE generated NotUsingStaticImport.java is displayed in the source editor window of NetBeans IDE.
| package testpackage; public class NotUsingStaticImport{ public static void main( String[] args ) { System.out.println( "Here are the attributes of a employee who will be hired: " ); System.out.println( "Minimum Salary is: " + EmpAttributes.MINSALARY ); System.out.println( "Maximum Salary is: " + EmpAttributes.MAXSALARY ); System.out.println( "Max Vacation Days: " + EmpAttributes.MAXVACATION ); System.out.println( "Max Raise Percentage: " + EmpAttributes.MAXANNUALRAISEPERCENTAGE ); } } |
3. Write EmpAttributes.java under testpackage package.
| package testpackage; public class EmpAttributes { public static final int MINSALARY = 50000; public static final int MAXSALARY = 70000; public static final int MAXVACATION = 15; public static final int MAXANNUALRAISEPERCENTAGE = 10; } |
4. Build and run the project
- Right click NotUsingStaticImport project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-3.13 below)
| Here are the attributes of a employee who will be hired: Minimum Salary is: 50000 Maximum Salary is: 70000 Max Vacation Days: 15 Max Raise Percentage: 10 |
(3.2) Example with using static imports
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects. Click Next.
- Under Name and Location pane, for the Project Name field, type in UsingStaticImport as project name.
- For Create Main Class field, type in testpackage.UsingStaticImport.
- Click Finish.
- Observe that UsingStaticImport project appears and IDE generated UsingStaticImport.java is displayed in the source editor window of NetBeans IDE.
The static import construct allows unqualified access to static members without inheriting from the type containing the static members. For example, you can say just MINSALARY instead of EmpAttribs.MINSALARY.
| package testpackage; import static testpackage.EmpAttributes.*; public class UsingStaticImport { public static void main( String[] args ) { System.out.println( "Here are the attributes of a employee who will be hired: " ); System.out.println( "Minimum Salary is: " + MINSALARY ); System.out.println( "Maximum Salary is: " + MAXSALARY ); System.out.println( "Max Vacation Days: " + MAXVACATION ); System.out.println( "Max Raise Percentage: " + MAXANNUALRAISEPERCENTAGE ); } } |
3. Write EmpAttributes.java under testpackage package. This is the same code as you have written in the previous step.
| package testpackage; public class EmpAttributes { public static final int MINSALARY = 50000; public static final int MAXSALARY = 70000; public static final int MAXVACATION = 15; public static final int MAXANNUALRAISEPERCENTAGE = 10; } |
4. Build and run the project
- Right click UsingStaticImport project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-3.23 below)
| Here are the attributes of a employee who will be hired: Minimum Salary is: 50000 Maximum Salary is: 70000 Max Vacation Days: 15 Max Raise Percentage: 10 |
Summary
Exercise 4: Variable arguments
더보기
| Object[] arguments = { new Integer(7), new Date(), "a disturbance in the Force" }; String result = MessageFormat.format( "At {1,time} on {1,date}, there was {2} on planet " + "{0,number,integer}.", arguments); // arguments is an array |
It is still true that multiple arguments must be passed in an array, but the varargs feature automates and hides the process. Furthermore, it is upward compatible with preexisting APIs. So, for example, the MessageFormat.format method now has this declaration:
| public static String format(String pattern, Object... arguments); |
The three periods after the final parameter's type indicate that the final argument may be passed as an array or as a sequence of arguments. Varargs can be used only in the final argument position. Given the new varargs declaration for MessageFormat.format, the above invocation may be replaced by the following shorter and sweeter invocation:
| String result = MessageFormat.format( "At {1,time} on {1,date}, there was {2} on planet " + "{0,number,integer}.", 7, new Date(), "a disturbance in the Force"); // varargs |
(4.1) Example wihtout using variable arguments
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects. Click Next.
- Under Name and Location pane, for the Project Name field, type in NotUsingVarArgs as project name.
- For Create Main Class field, type in NotUsingVarArgs.
- Click Finish.
- Observe that NotUsingVarArgs project appears and IDE generated NotUsingVarArgs.java is displayed in the source editor window of NetBeans IDE.
| import java.util.Date; import java.text.MessageFormat; import java.util.*; public class NotUsingVarArgs { public String formatThis() { Object[] args = { "Hurricane", new Integer( 99 ), new GregorianCalendar( 1999, 0, 1).getTime(), new Double( 10E7 ) }; return MessageFormat.format( "On {2}, a {0} destroyed {1} houses and caused {3} of damage", args ); } public static void main( String[] args ) { NotUsingVarArgs v = new NotUsingVarArgs(); System.out.println( v.formatThis()); } } |
3. Build and run the project
- Right click NotUsingVarArgs project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-4.13 below)
| On 1/1/99 12:00 AM, a Hurricane destroyed 99 houses and caused 100,000,000 of damage |
(4.2) Example with using variable arguments
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in UsingVarArgs as project name.
- For Create Main Class field, type in UsingVarArgs.
- Click Finish.

- Observe that UsingVarArgs project appears and IDE generated UsingVarArgs.java is displayed in the source editor window of NetBeans IDE.
| import java.util.Date; import java.text.MessageFormat; import java.util.*; public class UsingVarArgs { public UsingVarArgs() { } public String formatThis() { return( MessageFormat.format( "On {2}, a {0} destroyed {1} houses and caused {3} of damage", "Hurricane", new Integer( 99 ), new GregorianCalendar( 1999, 0, 1).getTime(), new Double( 10E7 ) ) ); } public static void main( String[] args ) { UsingVarArgs v = new UsingVarArgs(); System.out.println( v.formatThis()); } } |
3. Build and run the project
- Right click UsingVarArgs project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-4.23 below)
| On 1/1/99 12:00 AM, a Hurricane destroyed 99 houses and caused 100,000,000 of damage |
Summary
Exercise 5: Type-safe enumerations
더보기
| // int Enum Pattern - has severe problems! public static final int SEASON_WINTER = 0; public static final int SEASON_SPRING = 1; public static final int SEASON_SUMMER = 2; public static final int SEASON_FALL = 3; |
This pattern has several problems as following:
- Not typesafe - Since a season is just an int type, you can pass in any other int value where a season is required, or add two seasons together (which makes no sense).
- No namespace - You must prefix constants of an "int enum" with a string (in this case SEASON_) to avoid collisions with other int enum types.
- Brittleness - Because int enums are compile-time constants, they are compiled into an application that use them. If a new constant is added between two existing constants or the order is changed, the application must be recompiled. If it is not, it will still run, but its behavior will be undefined.
- Printed values are uninformative - Because they are just ints, if you print one out, all you get is a number, which tells you nothing about what it represents, or even what type it is.
Type-safe Enumeration (enum) allows you to create enumerated types with arbitrary methods and fields. It provides all the benefits of the Typesafe Enum pattern ("Effective Java", Item 21) without the verbosity and the error-proneness.
(5.1) Example "without" using Type-safe enumerations
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in NotUsingTypeSafeEnum as project name.
- For Create Main Class field, type in NotUsingTypeSafeEnum.
- Click Finish.

- Observe that NotUsingTypeSafeEnum project appears and IDE generated NotUsingTypeSafeEnum.java is displayed in the source editor window of NetBeans IDE.
| class FootballScore { public static final int EXTRAPOINT = 1; public static final int TWOPOINTS = 2; public static final int SAFETY = 2; public static final int FIELDGOAL = 3; public static final int TOUCHDOWN = 6; private int score; public FootballScore( int score ) { this.score = score; } public FootballScore() { this.score = 0; } public int getScore() { return this.score; } } public class NotUsingTypeSafeEnum { public static void main( String[] args ) { FootballScore[] myScores = { new FootballScore( FootballScore.TOUCHDOWN ), new FootballScore( FootballScore.EXTRAPOINT ), new FootballScore( FootballScore.FIELDGOAL ), new FootballScore( FootballScore.TOUCHDOWN ), new FootballScore( FootballScore.SAFETY ), new FootballScore( FootballScore.TOUCHDOWN ), new FootballScore( FootballScore.TWOPOINTS ) }; FootballScore[] yourScores = { new FootballScore( FootballScore.FIELDGOAL ), new FootballScore( FootballScore.TOUCHDOWN ), new FootballScore( FootballScore.FIELDGOAL ) }; int mytotal = calcTotal( myScores ); int yourtotal = calcTotal( yourScores ); System.out.println( " My football team scored " + mytotal ); System.out.println( " Your football team scored " + yourtotal ); if ( mytotal > yourtotal ) { System.out.println( " My Team Won! " ); } else if ( mytotal < yourtotal ) { System.out.println( " Your Team Won! " ); } else System.out.println( "What do you know? It is a Tie !! " ); } public static int calcTotal( FootballScore[] f ) { int total = 0; for ( int i = 0; i < f.length; ++i ) { total += f[i].getScore(); } return total; } } |
3. Build and run the project
- Right click NotUsingTypeSafeEnum project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-5.13 below)
| My football team scored 26 Your football team scored 12 My Team Won! |
(5.2) Example "with" using type-safe enumerations
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select Java under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in UsingTypeSafeEnum as project name.
- For Create Main Class field, type in UsingTypeSafeEnum.
- Click Finish.

- Observe that UsingTypeSafeEnum project appears and IDE generated UsingTypeSafeEnum.java is displayed in the source editor window of NetBeans IDE.
| public class UsingTypeSafeEnum { // Note that FootballScore is now enum type public enum FootballScore { TOUCHDOWN( 6 ), FIELDGOAL( 3 ), TWOPOINTS( 2 ), SAFETY( 2 ), EXTRAPOINT( 1 ); FootballScore( int value ) { this.score = value; } private final int score; public int score() { return score; } } public static void main( String[] args ) { FootballScore[] myScores = { FootballScore.TOUCHDOWN, FootballScore.EXTRAPOINT, FootballScore.FIELDGOAL, FootballScore.TOUCHDOWN, FootballScore.SAFETY, FootballScore.TOUCHDOWN, FootballScore.TWOPOINTS }; FootballScore[] yourScores = { FootballScore.FIELDGOAL, FootballScore.TOUCHDOWN, FootballScore.FIELDGOAL }; int mytotal = calcTotal( myScores ); int yourtotal = calcTotal( yourScores ); System.out.println( " My football team scored " + mytotal ); System.out.println( " Your football team scored " + yourtotal ); if ( mytotal > yourtotal ) { System.out.println( " My Team Won! " ); } else if ( mytotal < yourtotal ) { System.out.println( " Your Team Won! " ); } else System.out.println( "What do you know? It is a Tie !! " ); } public static int calcTotal( FootballScore[] f ) { int total = 0; for ( int i = 0; i < f.length; ++i ) { total += f[i].score(); } return total; } } |
3. Build and run the project
- Right click UsingTypeSafeEnum project and select Run Project.
- Observe the result in the Output window of the IDE. (Figure-5.23 below)
| My football team scored 26 Your football team scored 12 My Team Won! |
Summary
Homework exercise (for people who are taking Sang Shin's "Java Programming online course")
- Modify UsingTypeSafeEnum.java so that FootballScore enum type has extrapoint field (in addition to score field). Take a suggested code change as shown in H-01 below
| public class UsingTypeSafeEnum { // Note that FootballScore is now enum type public enum FootballScore { TOUCHDOWN( 6, 2 ), FIELDGOAL( 3, 2 ), TWOPOINTS( 2, 2 ), SAFETY( 2, 1 ), EXTRAPOINT( 1, 0 ); FootballScore( int value, int extrapoint ) { this.score = value; this.extrapoint = extrapoint; } // More code |
- Modify the logic of finding who wins between myScores and youScores by considering the values of both score and extrapoint fields (instead of just score field.)
- Zip file of the the MyUsingTypeSafeEnum NetBeans project. (Someone else should be able to open and run it as a NetBeans project.) You can use your favorite zip utility or you can use "jar" utility that comes with JDK as following.
- cd <parent directory that contains MyUsingTypeSafeEnum directory> (assuming you named your project as MyUsingTypeSafeEnum)
- jar cvf MyUsingTypeSafeEnum.zip MyUsingTypeSafeEnum (MyUsingTypeSafeEnum should contain nbproject directory)
- cd <parent directory that contains MyUsingTypeSafeEnum directory> (assuming you named your project as MyUsingTypeSafeEnum)
- Captured output screen - name it as JavaIntro-javase5language.gif or JavaIntro-javase5language.jpg (or JavaIntro-javase5language.<whatver graphics format>)
- Any screen capture that shows that your program is working is good enough. No cosmetic polishment is required.
- If you decide to use different IDE other than NetBeans, the zip file should contain all the files that are needed for rebuilding the project.
'BOOK Study > JAVA' 카테고리의 다른 글
| 28. J2SE 5.0 Annotations (0) | 2010/01/17 |
|---|---|
| 27. J2SE 5.0 Generics (0) | 2010/01/17 |
| 26. J2SE 5.0 Language Features Enhancements (0) | 2010/01/17 |
| Java SE 5 Language Feature Enhancements (0) | 2010/01/13 |
| 25. Java Threads (0) | 2010/01/11 |
| 24. Java Networking (0) | 2010/01/11 |
- 05. Java EE 6 - JPA 2.0
- BOOK Study/J2EE
- 2010/01/16 17:10
- Posted by 들기름왕자
Lab Exercises
For the sake of the simplicity of the lab, most exercises are provided in the form of "ready-to-open-and-run" NetBeans projects. (Many of them are borrowed from "glassfish-samples" and "Java EE 6 tutorial".) Please feel free to create them from scratch if you want to.
It is strongly encouraged, leveraging what is provided in this lab, you do your own experimentation meaning creating/adding your own code as much as you can.
If you have written some code that might help everyone else, please feel free to share them on this codecamp email alias or directly send them to the instructors. Your name will be recognized in this lab if your sample code is chosen to be included. For the tasks that need to be done, please see the "Things to be done" section above.)
- Exercise 0: Build standalone JPA application step by step (30 minutes)
- Exercise 1: Mapping with @ElementCollection (30 minutes)
- Exercise 2: Mapping with @OrderColumn (30 minutes)
- Exercise 3: Map (30 minutes)
- Exercise 4: JPQL Improvements (20 minutes)
- Exercise 5: Criteria API without using Metamodel (30 minutes)
- Exercise 6: Criteria API using Metamodel (30 minutes)
- Exercise 7: Locking (30 minutes)
- Exercise 8: Caching API (10 minutes)
- Exercise 9: Build and run "order" sample application (30 minutes)
- Exercise 10: Build and run "roster" sample application (30 minutes)
- Homework Exercise
Before you start this lab, you have to get sample applications from "glassfish-samples" and "Java EE tutorial" as described in LAB-4530: Java EE 6 - Examples.Exercise 0: Build standalone JPA application step by step
더보기
In this exercise, you are going to build a simple standalone (Java SE) JPA application step by step. Since many of the sample applications you are going to build and run in this lab are "ready to open and run" standalone applications, it would be useful for you to know how those applications were built.
(0.1) Start Java DB database server
0. Start NetBeans IDE.
1. Start Java DB database server.
- Select Services tab.
- Expand Databases.
- Right click Java DB and select Start Server.

Figure-0.11
(0.2) Build a simple "helloworld" standalone JPA application
1. Create a new Java Application project.
- Select File from top-level menu and select New Project.

Figure-0.21
- Select Java under Categories on the left and Java Application under Projects on the right.
- Click Next.

Figure-0.22
- For the Project Name field, enter jpa2.0_helloworld (or whatever project name of your choice).
- Click Finish.

Figure-0.23
2. Create Person Entity class.
- Right click jpa20_helloworld package and select New->Java Class. (Or you can select Entity Class if it is in the pop-up menu.)

Figure-0.24
- For the Class Name field, enter Person.
- Click Finish.

Figure-0.25
- Modify IDE generated Person.java with the one below. Note that Person class is POJO class annotated with @Entity.
| /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package jpa20_helloworld; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; /** * * @author sang */ @Entity public class Person { @Id @GeneratedValue private int id; private String name; private long salary; /** * @return the id */ public int getId() { return id; } /** * @param id the id to set */ public void setId(int id) { this.id = id; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the salary */ public long getSalary() { return salary; } /** * @param salary the salary to set */ public void setSalary(long salary) { this.salary = salary; } } |
- Observe that there are compile errors. This is expected because the libraries are not added yet to the project.

Figure-0.26
3. Add libraries.
- Right click Libraries of the project and select Add Library.

Figure-0.27
- Observe that Add Library dialog box appears.
- Select EclipseLink(JPA2.0), EclipseLink-GlassFish-v3, Java DB Driver, Java-EE-GlassFish-v3 and click Add Library button.

Figure-0.28
- Observe that the compile errors are gone.
Trouble-shooting: If you don't see Java DB Driver somehow, please add derbyclient.jar instead. (The Java DB Driver library is made of derbyclient.jar file.) The derbyclient.jar is available under GLASSFISH_HOME/javadb/lib directory. For your convenience, it is also provided under <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/clientdrivers directory. The step to take is right clicking Libraries and select Add JAR/Folder.4. Create persistence unit (persistence.xml).
- Click Save all files... button so that the Person class be known to the persistence unit you are going to create.
- Right click project and select New->Other.

Figure-0.29
- Select Persistence under Categories on the left and select Persistence Unit under File Types on the right.
- Click Next.

Figure-0.30
- For Database Collection field, select jdbc:derby://localhost:1527/sample [app on APP]. This is to select sample database as an actual database for persistence operation. (The sample database is a built-in database that comes with GlassFish.)
- For Table Generation Strategy, select Drop and Create. When chosen, this strategy lets you drop existing tables and create new ones. Given that you are going to run this application multiple times, this is the most convenient table generation strategy.
- Click Finish.

Figure-0.31
5. Add Entity class to persistence unit.
- Click Add Class button on the section of Include Entity Classes section at the bottom.

Figure-0.32
- Select jpa20_helloworld.Person and click OK.

Figure-0.33
6. Modify Main.java as shown below. It creates two Person instances and persists them into the PERSON table in the sample database.
| package jpa20_helloworld; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; /** * * @author sang */ public class Main { /** * @param args the command line arguments */ public static void main(String[] args) { // Create EntityManager EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa2.0_helloworldPU"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Person p1 = new Person(); p1.setName("Sang Shin"); p1.setSalary(10000); em.persist(p1); Person p2 = new Person(); p2.setName("Annie Song"); p2.setSalary(50000); em.persist(p2); tx.commit(); em.close(); emf.close(); } } |
6. Build and run the application.
- Right click project and select Run.

Figure-0.34
- Make sure the build has been successful.

Figure-0.35
Trouble-shooting: If you experience "..Person... is not a known entity type" error condition as shown below, it is because you have not added the Person class as entity class to the persistence.xml as described above.
Figure-0.36
Trouble-shooting: You will see the following [EL Warning] condition overtime you run the application - and the rest of the sample applications in this hands-on lab. This is expected and benign warning message. The reason you get this warning is because the ID generation strategy of the Person entity class is set with @GeneratedValue. What this means is you are asking the persistence provider to generate an ID for each newly created entry in the PERSON table. And the persistence provider is internally using SEQUENCE table for computing the next ID value. Now the persistence provider will try to create a new SEQUENCE table whenever the application is run but found that it already exists and displays a warning. If you delete SEQUENCE table manually, you will not see this warning, by the way, just as an experimentation.| [EL Warning]: 2010-01-14 10:57:09.204--ServerSession(27653945)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLException: Table/View 'SEQUENCE' already exists in Schema 'APP'. Error Code: -1 Call: CREATE TABLE SEQUENCE (SEQ_NAME VARCHAR(50) NOT NULL, SEQ_COUNT DECIMAL(15), PRIMARY KEY (SEQ_NAME)) |

Figure-0.37
7. Verify the PERSON table has been created.
- Click Services tab.
- Expand Databases.
- Right click jdbc:derby://localhost:1527/sample [app on APP] and select Connect.

Figure-0.38
- Expand App->Tables.
- Right click PERSON and select View Data.

Figure-0.39
- Verify that the PERSON table now has two entries.

Figure-0.40
8. Add JPAUtil class under jpa20_helloworld.util package. JPAUtil class is a collection of utility classes including checkData() method that displays the entries of a table.
| package jpa20_helloworld.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.Statement; public class JPAUtil { // Database configuration public static String url = "jdbc:derby://localhost:1527/sample"; public static String dbdriver = "org.apache.derby.jdbc.ClientDriver"; public static String username = "app"; public static String password = "app"; static Statement st; static Connection conn; static { try { Class.forName(dbdriver); conn = DriverManager.getConnection(url, username, password); st = conn.createStatement(); } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static void setup(String sql) { try { createStatement(); st.executeUpdate(sql); } catch (Exception e) { System.err.println("Got an exception! "); e.printStackTrace(); System.exit(0); } } public static void createStatement() { try { Class.forName(dbdriver); conn = DriverManager.getConnection(url, username, password); st = conn.createStatement(); } catch (Exception e) { System.err.println("Got an exception! "); e.printStackTrace(); System.exit(0); } } // Drop table if exists public static void droptable(String sql) { try { createStatement(); st.executeUpdate(sql); } catch (Exception e) { } } public void executeSQLCommand(String sql) throws Exception { st.executeUpdate(sql); } public static void checkData(String sql) { String[] starray = sql.split(" "); System.out.println("\n******** Table: " + starray[starray.length - 1] + " *******"); try { createStatement(); ResultSet rs = st.executeQuery(sql); outputResultSet(rs); conn.close(); } catch (Exception e) { e.printStackTrace(); } } public static void outputResultSet(ResultSet rs) throws Exception { ResultSetMetaData metadata = rs.getMetaData(); int numcols = metadata.getColumnCount(); String[] labels = new String[numcols]; int[] colwidths = new int[numcols]; int[] colpos = new int[numcols]; int linewidth; linewidth = 1; for (int i = 0; i < numcols; i++) { colpos[i] = linewidth; labels[i] = metadata.getColumnLabel(i + 1); // get its label int size = metadata.getColumnDisplaySize(i + 1); if (size > 30 || size == -1) { size = 30; } int labelsize = labels[i].length(); if (labelsize > size) { size = labelsize; } colwidths[i] = size + 1; // save the column the size linewidth += colwidths[i] + 2; // increment total size } StringBuffer divider = new StringBuffer(linewidth); StringBuffer blankline = new StringBuffer(linewidth); for (int i = 0; i < linewidth; i++) { divider.insert(i, '-'); blankline.insert(i, " "); } // Put special marks in the divider line at the column positions for (int i = 0; i < numcols; i++) { divider.setCharAt(colpos[i] - 1, '+'); } divider.setCharAt(linewidth - 1, '+'); // Begin the table output with a divider line System.out.println(divider); // The next line of the table contains the column labels. // Begin with a blank line, and put the column names and column // divider characters "|" into it. overwrite() is defined below. StringBuffer line = new StringBuffer(blankline.toString()); line.setCharAt(0, '|'); for (int i = 0; i < numcols; i++) { int pos = colpos[i] + 1 + (colwidths[i] - labels[i].length()) / 2; overwrite(line, pos, labels[i]); overwrite(line, colpos[i] + colwidths[i], " |"); } System.out.println(line); System.out.println(divider); while (rs.next()) { line = new StringBuffer(blankline.toString()); line.setCharAt(0, '|'); for (int i = 0; i < numcols; i++) { Object value = rs.getObject(i + 1); if (value != null) { overwrite(line, colpos[i] + 1, value.toString().trim()); overwrite(line, colpos[i] + colwidths[i], " |"); } } System.out.println(line); } System.out.println(divider); } static void overwrite(StringBuffer b, int pos, String s) { int len = s.length(); for (int i = 0; i < len; i++) { b.setCharAt(pos + i, s.charAt(i)); } } } |

Figure-0.41
9. Modify Main.java to use checkData() method to display the entries of the table.
| package jpa20_helloworld; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import jpa20_helloworld.util.JPAUtil; /** * * @author sang */ public class Main { /** * @param args the command line arguments */ public static void main(String[] args) { // Create EntityManager EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa2.0_helloworldPU"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Person p1 = new Person(); p1.setName("Sang Shin"); p1.setSalary(10000); em.persist(p1); Person p2 = new Person(); p2.setName("Annie Song"); p2.setSalary(50000); em.persist(p2); tx.commit(); // Display the table JPAUtil.checkData("select * from PERSON"); em.close(); emf.close(); } } |
10. Run the application again.
- Observe that the entries of the PERSON table gets displayed in the Output window.

Figure-0.42
11. Display context sensitive Javadoc on any JPA classes. Please use context sensitive Javadoc for any JPA classes you want to learn about moving forward.
- Right click the @Entity in the editor window and select Show Javadoc.

Figure-0.43
- Observe that Javadoc of the @Entity class appears in the browser.

Figure-0.44
Solution: The solution of this exercise is available as jpa2.0_helloworld project under <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/solutions. You can just open it and run it.
Summary
In this exercise, you have built a simple standalone Java SE application which uses persistence step by step.
Exercise 1: Mapping with @ElementCollection
더보기
In JPA 2.0, rich mapping capabilities are added. For example, an entity can have a collection of basic types or Embeddable's. (In JPA 1.0, an entity can have a collection of only entity type.) An Embeddable can have another Embeddable and Embeddable can have a one-to-many relationship with entity type. In this exercise, you are going to exercise these new mapping features.
- Start Java DB database server
- Collection of basic type
- Study code
- Collection of Embeddable
- Study code
- Multi-level Embeddables
- Study code
- Embeddable with relation
- Study code
(1.1) Collection of basic type
In this example, you are going to see how an Employee entity can have a collection of a Skill, which is String type, through the usage of @ElementCollection annotation. You are going to build and run the application and then explore the code next.
1. Open jpa2.0_mapping_collection_basictypes NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Windows: If you unzipped the 4537_javaee6_jpa2.0.zip file under C:\handsonlabs directory, the directory to which you want to browse down should be C:\handsonlabs\javaee6_jpa2.0\samples.
- Solaris/Linux/Mac: If you unzipped the 4537_javaee6_jpa2.0.zip file under $HOME/handsonlabs directory, the directory to which you want to browse down should be $HOME/handsonlabs/javaee6_jpa2.0/samples.
- Select jpa2.0_mapping_collection_basictypes.
- Click Open Project.
- Observe that the jpa2.0_mapping_collection_basictypes project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_collection_basictypes project.
- Right-click jpa2.0_mapping_collection_basictypes project and select Run.
- Observe the result in the Output window.

Figure-1.11
Trouble-shooting: If you experience the following error condition, it is because you have not started Java DB database server. Start the Java DB server as shown above.
Figure-1.12
(1.2) Study code
- Observe that the Employee entity has a set of String basic type through the usage of @ElementCollection annotation.

Figure-1.21
| package examples.model; import java.util.Set; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Employee { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int id; private String name; private long salary; // Collection of basic type - String type in this case @ElementCollection // Name the table as "expertise" @CollectionTable(name = "expertise") private Set<String> javaskills; public Employee() { } public Employee(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Override; public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the javaskills */ public Set<String> geJavaskills() { return javaskills; } /** * @param javaskills the javaskills to set */ public void seJavaskills(Set<String> javaskills) { this.javaskills = javaskills; } } |
2. persistence.xml.
- Note that the properties are now standardized in JPA 2.0. For example, instead of toplink.jdbc.driver for the Toplink or another name for another persistence provider, you are going to use standardized javax.persistence.jdbc.driver.
- Note that we are using drop-and-create-tables (Drop and Create tables) strategy, which means the persistence provider will drop existing EMPLOYEE and EXPERTISE tables and recreate them everytime you run the application.

Figure-1.22
| <?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="EmployeeService" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>examples.model.Employee</class> <properties> <property name="eclipselink.target-database" value="DERBY"/> <!--<property name="eclipselink.ddl-generation" value="create-tables"/>--> <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> <property name="eclipselink.logging.level" value="INFO"/> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/> <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/sample"/> <property name="javax.persistence.jdbc.user" value="app"/> <property name="javax.persistence.jdbc.password" value="app"/> <property name="" value="app"/> </properties> </persistence-unit> </persistence> |
3. Main.java.
- The Main class provides a testing code, in which a couple of Employee entities with a collection of String type are created. The contents of the database tables are then displayed so that you can tell if the tables are created and correct data are persisted.
| package mypackage; import examples.model.Employee; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.EmployeeService; import java.util.HashSet; import java.util.Set; import javax.persistence.EntityTransaction; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { // Create EntityManager EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); // EmployeeService is a utility class EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); Employee emp = es.createEmployee("Sang Shin", 10000); Set<String> javaskills = new HashSet<String>(); javaskills.add("servlet 3.0"); javaskills.add("ejb 3.1"); javaskills.add("jsf 2.0"); javaskills.add("jpa 2.0"); es.setJavaskills(emp, javaskills); emp = es.createEmployee("Bill Clinton", 8000); javaskills = new HashSet<String>(); javaskills.add("jsf"); javaskills.add("ejb"); es.setJavaskills(emp, javaskills); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Lannie", 7500); es.createEmployee("Shelley Nichole", 8500); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from EXPERTISE"); em.close(); emf.close(); } } |
4. EmployeeService.java. The EmployeeService class is utility class which provide a few convenience methods.
| package examples.model; import java.util.Collection; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.Query; public class EmployeeService { protected EntityManager em; public EmployeeService(EntityManager em) { this.em = em; } public Employee createEmployee(String name, long salary) { Employee emp = new Employee(); emp.setName(name); emp.setSalary(salary); em.persist(emp); return emp; } public Employee updateEmployee(Employee emp) { em.persist(emp); return emp; } public void setJavaskills(Employee emp, Set<String> javaskills) { if (emp != null) { emp.seJavaskills(javaskills); } } public void removeEmployee(int id) { Employee emp = findEmployee(id); if (emp != null) { em.remove(emp); } } public Employee raiseEmployeeSalary(int id, long raise) { Employee emp = em.find(Employee.class, id); if (emp != null) { emp.setSalary(emp.getSalary() + raise); } return emp; } public Employee findEmployee(int id) { return em.find(Employee.class, id); } public Collection<Employee> findAllEmployees() { Query query = em.createQuery("SELECT e FROM Employee e"); return (Collection<Employee>) query.getResultList(); } } |
(1.3) Collection of Embeddable
더보기
In JPA 2.0, an entity class can also have a collection of Embeddable's. In this example, an Employee entity has a collection of Address class, which is Embeddable type.
1. Open jpa2.0_mapping_collection_embeddables NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_collection_embeddables.
- Click Open Project.
- Observe that the jpa2.0_mapping_collection_embeddables project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_collection_embeddables project.
- Right-click jpa2.0_mapping_collection_embeddables project and select Run.
- Observe the result in the Output window.

Figure-1.31
(1.4) Study code
| package examples.model; import java.util.Set; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Employee { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int id; private String name; private long salary; // Collection of basic type - String type in this case @ElementCollection // Name the table as "expertise" @CollectionTable(name = "expertise") private Set<String> javaskills; // Collection of embeddable type @ElementCollection // Name the table as "expertise" @CollectionTable(name = "vacationhomes") private Set<Address> vacationHomes; public Employee() { } public Employee(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Override; public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the javaskills */ public Set<String> geJavaskills() { return javaskills; } /** * @param javaskills the javaskills to set */ public void seJavaskills(Set<String> javaskills) { this.javaskills = javaskills; } /** * @return the vacationHomes */ public Set<Address> getVacationHomes() { return vacationHomes; } /** * @param vacationHomes the vacationHomes to set */ public void setVacationHomes(Set<Address> vacationHomes) { this.vacationHomes = vacationHomes; } } |
2. Address.java. Note that Address class is an Embeddable type.
| package examples.model; import java.io.Serializable; import javax.persistence.Embeddable; @Embeddable public class Address implements Serializable{ private String street; private String city; private String state; public Address(){ } public Address(String street, String city, String state) { this.street = street; this.city = city; this.state = state; } /** * @return the street */ public String getStreet() { return street; } /** * @param street the street to set */ public void setStreet(String street) { this.street = street; } /** * @return the city */ public String getCity() { return city; } /** * @param city the city to set */ public void setCity(String city) { this.city = city; } /** * @return the state */ public String getState() { return state; } /** * @param state the state to set */ public void setState(String state) { this.state = state; } } |
3. Main.java
| package mypackage; import examples.model.Address; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.EmployeeService; import java.util.HashSet; import java.util.Set; import javax.persistence.EntityTransaction; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); es.createEmployee("Sang Shin", 10000); Set<String> javaskills = new HashSet<String>(); javaskills.add("servlet"); javaskills.add("ejb"); es.setJavaskills(1, javaskills); Set<Address> vacationHomes = new HashSet<Address>(); vacationHomes.add(new Address("1 dreamland st", "newton", "MA")); vacationHomes.add(new Address("22 marthas vineyard", "cape cod", "MA")); es.setVacationHomes(1, vacationHomes); es.createEmployee("Bill Clinton", 8000); javaskills = new HashSet<String>(); javaskills.add("jsf"); javaskills.add("ejb"); es.setJavaskills(2, javaskills); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Lannie", 7500); es.createEmployee("Shelley Nichole", 8500); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from EXPERTISE"); JPAUtil.checkData("select * from VACATIONHOMES"); em.close(); emf.close(); } } |
(1.5) Multi-level Embeddables
더보기
In JPA 2.0, an Embeddable class can have child Embedable class, thus constructing multi-level Embeddable sructure. In this example, ContactInfo Embeddable has Address Embeddable as an attribute.
1. Open jpa2.0_mapping_collection_embeddables_multilevels NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_collection_embeddables_multilevels.
- Click Open Project.
- Observe that the jpa2.0_mapping_collection_embeddables_multilevels project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_collection_embeddables_multilevels project.
- Right-click jpa2.0_mapping_collection_embeddables_multilevels project and select Run.
- Observe the result in the Output window.

Figure-1.51
(1.6) Study code
| package examples.model; import java.util.Set; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Employee { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int id; private String name; private long salary; // Collection of basic type - Stting type in this case @ElementCollection // Name the table as "expertise" @CollectionTable(name = "expertise") private Set<String> javaskills; // Collection of embeddable type @ElementCollection @CollectionTable(name = "vacationhomes") private Set<Address> vacationHomes; // Multi-levels of Embeddable private ContactInfo contactInfo; public Employee() { } public Employee(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Override; public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the javaskills */ public Set<String> geJavaskills() { return javaskills; } /** * @param javaskills the javaskills to set */ public void seJavaskills(Set<String> javaskills) { this.javaskills = javaskills; } /** * @return the vacationHomes */ public Set<Address> getVacationHomes() { return vacationHomes; } /** * @param vacationHomes the vacationHomes to set */ public void setVacationHomes(Set<Address> vacationHomes) { this.vacationHomes = vacationHomes; } /** * @return the contactInfo */ public ContactInfo getContactInfo() { return contactInfo; } /** * @param contactInfo the contactInfo to set */ public void setContactInfo(ContactInfo contactInfo) { this.contactInfo = contactInfo; } } |
2. ContactInfo.java.
| package examples.model; import java.io.Serializable; import javax.persistence.Embeddable; import javax.persistence.Embedded; @Embeddable public class ContactInfo implements Serializable{ @Embedded private Address address; public ContactInfo(){ } public ContactInfo(Address address) { this.address = address; } /** * @return the address */ public Address getAddress() { return address; } /** * @param address the address to set */ public void setAddress(Address address) { this.address = address; } } |
3. Address.java
| package examples.model; import java.io.Serializable; import javax.persistence.Embeddable; @Embeddable public class Address implements Serializable{ private String street; private String city; private String state; public Address(){ } public Address(String street, String city, String state) { this.street = street; this.city = city; this.state = state; } /** * @return the street */ public String getStreet() { return street; } /** * @param street the street to set */ public void setStreet(String street) { this.street = street; } /** * @return the city */ public String getCity() { return city; } /** * @param city the city to set */ public void setCity(String city) { this.city = city; } /** * @return the state */ public String getState() { return state; } /** * @param state the state to set */ public void setState(String state) { this.state = state; } } |
4. Main.java.
| package mypackage; import examples.model.Address; import examples.model.ContactInfo; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.EmployeeService; import java.util.HashSet; import java.util.Set; import javax.persistence.EntityTransaction; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); // First employee es.createEmployee("Sang Shin", 10000); Set<String> javaskills = new HashSet<String>(); javaskills.add("servlet"); javaskills.add("ejb"); es.setJavaskills(1, javaskills); Set<Address> vacationHomes = new HashSet<Address>(); vacationHomes.add(new Address("1 dreamland st", "newton", "MA")); vacationHomes.add(new Address("22 marthas vineyard", "cape cod", "MA")); es.setVacationHomes(1, vacationHomes); ContactInfo contactInfo = new ContactInfo(new Address("1 dreamland road", "Newton", "MA")); es.setContactInfo(1, contactInfo); // 2nd employee es.createEmployee("Bill Clinton", 8000); javaskills = new HashSet<String>(); javaskills.add("jsf"); javaskills.add("ejb"); es.setJavaskills(2, javaskills); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Lannie", 7500); es.createEmployee("Shelley Nichole", 8500); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from EXPERTISE"); JPAUtil.checkData("select * from VACATIONHOMES"); em.close(); emf.close(); } } |
(1.7) Embeddable with its own relationship
더보기
An Embeddable can have one-to-many or many-to-many relationship with other entities. In this example, ContactInfo Embeddable class has one-to-many relationship with Phone entities.
1. Open jpa2.0_mapping_collection_embeddables_relation NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_collection_embeddables_relation.
- Click Open Project.
- Observe that the jpa2.0_mapping_collection_embeddables_relation project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_collection_embeddables_relation project.
- Right-click jpa2.0_mapping_collection_embeddables_relation project and select Run.
- Observe the result in the Output window.

Figure-1.71
(1.8) Study code
| package examples.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Employee implements Serializable { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int id; private String name; private long salary; // Multi-levels of Embeddable private ContactInfo contactInfo; public Employee() { } public Employee(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Override; public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the contactInfo */ public ContactInfo getContactInfo() { return contactInfo; } /** * @param contactInfo the contactInfo to set */ public void setContactInfo(ContactInfo contactInfo) { this.contactInfo = contactInfo; } } |
2. ContactInfo.java. Note that the ContactInfo class, which is@Embeddable type, has one-to-many bidirectional relationship with Phone entity class.
| package examples.model; import java.io.Serializable; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Embeddable; import javax.persistence.Embedded; import javax.persistence.OneToMany; @Embeddable public class ContactInfo implements Serializable{ @Embedded private Address address; // One-to-many bidirectional relationship between // ContactInfo and Phone. // The "employee" is a field in the Phone. @OneToMany(cascade=CascadeType.ALL, mappedBy="employee") private Set<Phone> phones; public ContactInfo(){ } public ContactInfo(Address address) { this.address = address; } /** * @return the address */ public Address getAddress() { return address; } /** * @param address the address to set */ public void setAddress(Address address) { this.address = address; } /** * @return the phones */ public Set<Phone> getPhones() { return phones; } /** * @param phones the phones to set */ public void setPhones(Set<Phone> phones) { this.phones = phones; } } |
3. Phone.java
| import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "PHONE_TABLE") public class Phone implements Serializable { @Id @Column(name = "PHONE_ID") @GeneratedValue private int id; private String phoneNumber; // Bi-directional one-to-many relationship @ManyToOne(optional = true) private Employee employee; public int getId() { return id; } public void setId(int id) { this.id = id; } public Phone() { } public Phone(String phoneNumber, Employee emp) { this.phoneNumber = phoneNumber; this.employee = emp; } public Phone(int id, String phoneNumber) { this.id = id; this.phoneNumber = phoneNumber; } public String getPhoneNumber() { return phoneNumber; } /** * @param phoneNumber the phoneNumber to set */ public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } /** * @return the employee */ public Employee getEmployee() { return employee; } /** * @param employee the employee to set */ public void setEmployee(Employee employee) { this.employee = employee; } } |
4. Main.java
| package mypackage; import examples.model.Address; import examples.model.ContactInfo; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import examples.model.Phone; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.EntityTransaction; import javax.persistence.Query; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); // First employee Employee emp = es.createEmployee("Sang Shin", 10000); Set<Phone> phones = new HashSet<Phone>(); phones.add(new Phone("111-3333-3333", emp)); phones.add(new Phone("111-1233-6666", emp)); ContactInfo contactInfo = new ContactInfo(new Address("1 dreamland road", "Newton", "MA")); contactInfo.setPhones(phones); es.setContactInfo(emp, contactInfo); es.updateEmployee(emp); // Second employee emp = es.createEmployee("Bill Clinton", 8000); phones = new HashSet<Phone>(); phones.add(new Phone("222-3333-3333", emp)); phones.add(new Phone("222-1233-6666", emp)); contactInfo = new ContactInfo(new Address("7 Green St", "Ohmygodgown", "PA")); contactInfo.setPhones(phones); es.setContactInfo(emp, contactInfo); es.updateEmployee(emp); // Perform query - Retrieve all employees whose street is // "1 dteamland road". String jpql = "SELECT e FROM Employee e WHERE e.contactInfo.address.street = ?1"; Query query = em.createQuery(jpql); query.setParameter(1, "1 dreamland road"); List<Employee> emps = query.getResultList(); displayQueryResult(jpql, emps); // Perform query - Retrieve all employees who have a specific phone number // in their contactinfo jpql = "SELECT e FROM Employee e " + "JOIN e.contactInfo.phones p WHERE p.phoneNumber = ?1"; query = em.createQuery(jpql); query.setParameter(1, "222-3333-3333"); emps = query.getResultList(); displayQueryResult(jpql, emps); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from PHONE_TABLE"); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
Summary
In this exercise, you have explored richer mapping capabilities of JPA 2.0 through use of @ElementCollection.
Exercise 2: Mapping with @OrderColumn
더보기
JPA 2.0 adds support for an OrderColumn. An OrderColumn can be used to define an order List on any collection mapping. It is defined through the @OrderColumn annotation or <order-column> XML element.
The OrderColumn is maintained by the mapping and should not be an attribute of the target object. The table for the OrderColumn depends on the mapping. For a OneToMany mapping it will be in the target object's table. For a ManyToMany mapping or a OneToMany using a JoinTable it will be in the join table. For an ElementCollection mapping it will be in the target table.
(2.0) Delete PHONE_TABLE manually (only if it exists)
The PHONE_TABLE has been created as a result of previous exercise. In running jpa2.0_mapping_ordercolumn_ElementCollection project, which you about to run, the persistence provider will try to delete and create EMPLOYEE table as instructed in the persistence.xml but will fail because the EMPLOYEE table has a dependency on the PHONE_TABLE table, hence the reason you will have to manually delete PHONE_TABLE first.
1. If you do not see the PHONE_TABLE, right-click on APP and select Refresh before deleting it.
- Right click Services tab.
- Right click APP and select Refresh.

Figure-2.01 - Refreshing the APP database to see the PHONE_TABLE
2. Delete PHONE_TABLE if it exists.
- Right click PHONE_TABLE and select Delete.

(2.1) @OrderColumn with a collection of basic type
1. Open jpa2.0_mapping_ordercolumn_ElementCollection NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_ordercolumn_ElementCollection.
- Click Open Project.
- Observe that the jpa2.0_mapping_ordercolumn_ElementCollection project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_ordercolumn_ElementCollection project.
- Right-click jpa2.0_mapping_ordercolumn_ElementCollection project and select Run.
- Observe the result in the Output window.

Figure-2.11
(2.2) Study the code
| package examples.model; import java.util.List; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OrderColumn; @Entity public class Employee { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int id; private String name; private long salary; // Collection of basic type - Stting type in this case @ElementCollection // Specifies a column that is used to maintain the persistent order of a list. @OrderColumn(name="INDEX") // Name the table as "phones" @CollectionTable(name = "phones") private List<String> phones; public Employee() { } public Employee(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Overrride public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the phones */ public List<String> getPhones() { return phones; } /** * @param phones the phones to set */ public void sePhones(List<String> phones) { this.phones = phones; } } |
2. Main.java
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityTransaction; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); Employee emp = es.createEmployee("Sang Shin", 10000); List<String> phones = new ArrayList<String>(); phones.add("111-111-1234"); phones.add("111-111-2345"); phones.add("111-111-2341"); phones.add("111-111-3455"); es.setPhones(emp, phones); emp = es.createEmployee("Bill Clinton", 8000); phones = new ArrayList<String>(); phones.add("222-222-4252"); phones.add("222-222-2452"); es.setPhones(emp, phones); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Lannie", 7500); es.createEmployee("Shelley Nichole", 8500); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from PHONES"); em.close(); emf.close(); } } |
(2.3) @OrderColumn with one-to-many Unidirectional relationship
더보기
1. Open jpa2.0_mapping_ordercolumn_OneToMany_Unidirection NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_ordercolumn_OneToMany_Unidirection.
- Click Open Project.
- Observe that the jpa2.0_mapping_ordercolumn_OneToMany_Unidirection project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_ordercolumn_OneToMany_Unidirection project.
- Right-click jpa2.0_mapping_ordercolumn_OneToMany_Unidirection project and select Run.
- Observe the result in the Output window.

Figure-2.31
(2.4) Study the code
1. Employee.java.
| package examples.model; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OrderColumn; @Entity public class Employee { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int id; private String name; private long salary; // Unidirectional One-to-Many association using a foreign key mapping @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true) // The join column is in table for Phone (for Unidirectional relationship) @JoinColumn(name="EMPLOYEE_ID") // Specifies a column that is used to maintain the persistent order of a list. @OrderColumn(name = "INDEX") private List<Phone> phones; public Employee() { } public Employee(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the phones */ public List<Phone> getPhones() { return phones; } /** * @param phones the phones to set */ public void sePhones(List<Phone> phones) { this.phones = phones; } } |
(2.5) @OrderColumn with one-to-many Bidirectional relationship
더보기
1. Open jpa2.0_mapping_ordercolumn_OneToMany_Bidirection NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_ordercolumn_OneToMany_Bidirection.
- Click Open Project.
- Observe that the jpa2.0_mapping_ordercolumn_OneToMany_Bidirection project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_ordercolumn_OneToMany_Bidirection project.
- Right-click jpa2.0_mapping_ordercolumn_OneToMany_Bidirection project and select Run.
- Observe the result in the Output window.

Figure-2.51
(2.6) Study the code
| package examples.model; import java.io.Serializable; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.OrderColumn; @Entity public class Employee implements Serializable { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int eid; private String name; private long salary; // Bidirectional one to many relationship through "mappedBy". // The value of "mappedBy" is a field of Phone entity class. @OneToMany(cascade=CascadeType.ALL, mappedBy="employee") // Specifies a column that is used to maintain the persistent order of a list. @OrderColumn(name = "INDEX") private List<Phone> phones; public Employee() { } public Employee(int id) { this.eid = id; } public int getId() { return eid; } public void setId(int id) { this.eid = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Override public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the phones */ public List<Phone> getPhones() { return phones; } /** * @param phones the phones to set */ public void sePhones(List<Phone> phones) { this.phones = phones; } } |
2. Phone.java
| package examples.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "PHONE_TABLE") public class Phone implements Serializable { @Id @Column(name = "PHONE_ID") @GeneratedValue private int id; private String phoneNumber; // Bi-directional one-to-many relationship @ManyToOne(optional = false) private Employee employee; public int getId() { return id; } public void setId(int id) { this.id = id; } public Phone() { } public Phone(String phoneNumber, Employee emp) { this.phoneNumber = phoneNumber; this.employee = emp; } public Phone(int id, String phoneNumber) { this.id = id; this.phoneNumber = phoneNumber; } public String getPhoneNumber() { return phoneNumber; } /** * @param phoneNumber the phoneNumber to set */ public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } /** * @return the employee */ public Employee getEmployee() { return employee; } /** * @param employee the employee to set */ public void setEmployee(Employee employee) { this.employee = employee; } } |
3. Main.java
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import examples.model.Phone; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityTransaction; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { // Perform JPA operations EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); // Create some employees EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); Employee emp = es.createEmployee("Sang Shin", 10000); List<Phone> phones = new ArrayList<Phone>(); phones.add(new Phone("111-111-1234", emp)); phones.add(new Phone("111-111-2345", emp)); phones.add(new Phone("111-111-2341", emp)); phones.add(new Phone("111-111-3455", emp)); es.setPhones(emp, phones); es.updateEmployee(emp); emp = es.createEmployee("Bill Clinton", 8000); phones = new ArrayList<Phone>(); phones.add(new Phone("222-222-4252", emp)); phones.add(new Phone("222-222-2452", emp)); es.setPhones(emp, phones); es.updateEmployee(emp); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from PHONE_TABLE"); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
Summary
In this exercise, you have explored how @OrderColumn is used to define an order List on any collection mapping.
Exercise 3: Map key
더보기
JPA 2.0 allows for a Map where the key is not part of the target object to be persisted. The Map key can be any of the following:
* A Basic value, stored in the target's table or join table.
* An Embedded object, stored in the target's table or join table.
* A foreign key to another Entity, stored in the target's table or join table.
Map columns can be used for any collection mapping including, OneToMany, ManyToMany and ElementCollection.
(3.1) @MapKeyColumn
1. Open jpa2.0_mapping_MapKeyColumn NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_MapKeyColumn.
- Click Open Project.
- Observe that the jpa2.0_mapping_MapKeyColumn project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_MapKeyColumn project.
- Right-click jpa2.0_mapping_MapKeyColumn project and select Run.
- Observe the result in the Output window.

Figure-3.11
(3.2) Study the code
| package examples.model; import java.io.Serializable; import java.util.Map; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; @Entity public class Employee implements Serializable { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int eid; private String name; private long salary; // Bidirectional one to many relationship through "mappedBy". // The value of "mappedBy" is a field of Phone entity class. @OneToMany(cascade=CascadeType.ALL, mappedBy="employee") // The @MapKeyColumn annotation is used to define a map // relationship where the key is a Basic value @MapKeyColumn(name="PHONE_TYPE") private Map<String, Phone> phones; public Employee() { } public Employee(int id) { this.eid = id; } public int getId() { return eid; } public void setId(int id) { this.eid = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Override public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the phones */ public Map<String, Phone> getPhones() { return phones; } /** * @param phones the phones to set */ public void setPhones(Map<String, Phone> phones) { this.phones = phones; } } |
2. Phone.java
| package examples.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "PHONE_TABLE") public class Phone implements Serializable { @Id @Column(name = "PHONE_ID") @GeneratedValue private int id; private String phoneNumber; // Bi-directional one-to-many relationship @ManyToOne(optional = false) private Employee employee; public int getId() { return id; } public void setId(int id) { this.id = id; } public Phone() { } public Phone(String phoneNumber, Employee emp) { this.phoneNumber = phoneNumber; this.employee = emp; } public Phone(int id, String phoneNumber) { this.id = id; this.phoneNumber = phoneNumber; } public String getPhoneNumber() { return phoneNumber; } /** * @param phoneNumber the phoneNumber to set */ public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } /** * @return the employee */ public Employee getEmployee() { return employee; } /** * @param employee the employee to set */ public void setEmployee(Employee employee) { this.employee = employee; } } |
3. Main.java
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import examples.model.Phone; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.EntityTransaction; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { // Perform JPA operations EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); // Create some employees EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); Employee emp = es.createEmployee("Sang Shin", 10000); Map<String, Phone> phones = new HashMap<String, Phone>(); phones.put("cell", new Phone("111-111-1234", emp)); phones.put("home", new Phone("111-111-2345", emp)); phones.put("fax", new Phone("111-111-2341", emp)); phones.put("cell2", new Phone("111-111-3455", emp)); es.setPhones(emp, phones); es.updateEmployee(emp); emp = es.createEmployee("Bill Clinton", 8000); phones = new HashMap<String, Phone>(); phones.put("home", new Phone("222-222-4252", emp)); phones.put("cell", new Phone("222-222-2452", emp)); es.setPhones(emp, phones); es.updateEmployee(emp); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from PHONE_TABLE"); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
(3.3) @MapKeyClass
더보기
1. Open jpa2.0_mapping_MapKeyClass NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_mapping_MapKeyClass.
- Click Open Project.
- Observe that the jpa2.0_mapping_MapKeyClass project node appears under Projects tab window.
2. Build and run jpa2.0_mapping_MapKeyClass project.
- Right-click jpa2.0_mapping_MapKeyClass project and select Run.
- Observe the result in the Output window.

Figure-3.31
(3.4) Study the code
| package examples.model; import java.io.Serializable; import java.util.Map; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.MapKeyClass; import javax.persistence.OneToMany; @Entity public class Employee implements Serializable { @Id @GeneratedValue @Column(name = "EMPLOYEE_ID") private int eid; private String name; private long salary; // Bidirectional one to many relationship through "mappedBy". // The value of "mappedBy" is a field of Phone entity class. @OneToMany(cascade=CascadeType.ALL) // Specifies the type of the map key for associations of type // java.util.Map. The map key can be a basic type, an embeddable // class, or an entity. If the map is specified using Java generics, // the MapKeyClass annotation and associated type need not be // specified; otherwise they must be specified. // @MapKeyClass(PhoneType.class) // Not needed in this case private Map<PhoneType, Phone> phones; public Employee() { } public Employee(int id) { this.eid = id; } public int getId() { return eid; } public void setId(int id) { this.eid = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Override public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } /** * @return the phones */ public Map<PhoneType, Phone> getPhones() { return phones; } /** * @param phones the phones to set */ public void setPhones(Map<PhoneType, Phone> phones) { this.phones = phones; } } |
2. Phone.java
| package examples.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "PHONE_TABLE") public class Phone implements Serializable { @Id @Column(name = "PHONE_ID") @GeneratedValue private int id; private String phoneNumber; // Bi-directional one-to-many relationship @ManyToOne(optional = false) private Employee employee; public int getId() { return id; } public void setId(int id) { this.id = id; } public Phone() { } public Phone(String phoneNumber) { this.phoneNumber = phoneNumber; } public Phone(int id, String phoneNumber) { this.id = id; this.phoneNumber = phoneNumber; } public String getPhoneNumber() { return phoneNumber; } /** * @param phoneNumber the phoneNumber to set */ public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } /** * @return the employee */ public Employee getEmployee() { return employee; } /** * @param employee the employee to set */ public void setEmployee(Employee employee) { this.employee = employee; } } |
3. PhoneType.java
| package examples.model; import java.io.Serializable; import javax.persistence.Basic; import javax.persistence.Embeddable; @Embeddable public class PhoneType implements Serializable { @Basic private String type; public PhoneType() { } public PhoneType(String type) { this.type = type; } /** * @return the type */ public String getType() { return type; } /** * @param type the type to set */ public void setType(String type) { this.type = type; } } |
4. Main.java
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import examples.model.Phone; import examples.model.PhoneType; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.EntityTransaction; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { // Perform JPA operations EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); // Create some employees EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); Employee emp = es.createEmployee("Sang Shin", 10000); Map<PhoneType, Phone> phones = new HashMap<PhoneType, Phone>(); phones.put(new PhoneType("cell"), new Phone("111-111-1234", emp)); phones.put(new PhoneType("home"), new Phone("111-111-2345", emp)); phones.put(new PhoneType("fax"), new Phone("111-111-2341", emp)); phones.put(new PhoneType("cell2"), new Phone("111-111-3455", emp)); es.setPhones(emp, phones); es.updateEmployee(emp); emp = es.createEmployee("Bill Clinton", 8000); phones = new HashMap<PhoneType, Phone>(); phones.put(new PhoneType("home"), new Phone("222-222-4252", emp)); phones.put(new PhoneType("cell"), new Phone("222-222-2452", emp)); es.setPhones(emp, phones); es.updateEmployee(emp); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from PHONE_TABLE"); JPAUtil.checkData("select * from EMPLOYEE_PHONE_TABLE"); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
Summary
In this exercise, you have explored how to use different kinds of Map key.
Exercise 4: JPQL Impovements
더보기
JPA 2.0 have added a few new keywords such as INDEX and CASE. The INDEX function returns an integer value corresponding to the position of its argument in an ordered list. The INDEX function can only be applied to identification variables denoting types for which an order column has been specified.
(4.1) INDEX
0. Delete EMPLOYEE_PHONE_TABLE manually.
The EMPLOYEE_PHONE_TABLE has been created as a result of previous exercise. In running jpa2.0_jpql_index project, the persistence provider will try to delete and create EMPLOYEE table as instructed in the persistence.xml but will fail because it has a dependency on the EMPLOYEE_PHONE_TABLE, hence the reason you will have to manually delete PHONE_TABLE first.
If you do not see the EMPLOYEE_PHONE_TABLE, right-click on APP and select Refresh before deleting it.
1. Open jpa2.0_jpql_index NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_jpql_index.
- Click Open Project.
- Observe that the jpa2.0_jpql_index project node appears under Projects tab window.
2. Build and run jpa2.0_jpql_index project.
- Right-click jpa2.0_jpql_index project and select Run.
- Observe the result in the Output window.

Figure-4.11
| ------ Query result of "SELECT e FROM Employee e INNER JOIN e.phones p WHERE e.name = 'Sang Shin' AND INDEX(p) < 3 " Employee 1, Sang Shin, 10000 Employee 1, Sang Shin, 10000 Employee 1, Sang Shin, 10000 ------ Query result of "SELECT DISTINCT e FROM Employee e INNER JOIN e.phones p WHERE e.name = 'Sang Shin' AND INDEX(p) < 3 " Employee 1, Sang Shin, 10000 ------ Query result of "SELECT e FROM Employee e INNER JOIN e.phones p WHERE e.name = 'Sang Shin' AND INDEX(p) < 1 " Employee 1, Sang Shin, 10000 ------ Query result of "SELECT DISTINCT e FROM Employee e INNER JOIN e.phones p WHERE INDEX(p) BETWEEN 0 AND 4 " Employee 1, Sang Shin, 10000 Employee 2, Bill Clinton, 8000 |
(4.2) Study the code
| @package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import examples.model.Phone; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityTransaction; import javax.persistence.Query; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { // Perform JPA operations EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); // Create some employees EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); Employee emp = es.createEmployee("Sang Shin", 10000); List<Phone> phones = new ArrayList<Phone>(); phones.add(new Phone("111-111-1234")); phones.add(new Phone("111-111-2345")); phones.add(new Phone("111-111-2341")); phones.add(new Phone("111-111-3455")); es.setPhones(emp, phones); emp = es.createEmployee("Bill Clinton", 8000); phones = new ArrayList<Phone>(); phones.add(new Phone("222-222-4252")); phones.add(new Phone("222-222-2452")); es.setPhones(emp, phones); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); JPAUtil.checkData("select * from PHONE_TABLE"); // Usage of INDEX example String jpql = "SELECT e " + "FROM Employee e INNER JOIN e.phones p " + "WHERE e.name = 'Sang Shin' " + "AND INDEX(p) < 3 "; Query query = em.createQuery(jpql); List<Employee> emps = query.getResultList(); displayQueryResult(jpql, emps); // Usage of INDEX example jpql = "SELECT DISTINCT e " + "FROM Employee e INNER JOIN e.phones p " + "WHERE e.name = 'Sang Shin' " + "AND INDEX(p) < 3 "; query = em.createQuery(jpql); emps = query.getResultList(); displayQueryResult(jpql, emps); // Usage of INDEX example jpql = "SELECT e " + "FROM Employee e INNER JOIN e.phones p " + "WHERE e.name = 'Sang Shin' " + "AND INDEX(p) < 1 "; query = em.createQuery(jpql); emps = query.getResultList(); displayQueryResult(jpql, emps); // Usage of INDEX example jpql = "SELECT DISTINCT e " + "FROM Employee e INNER JOIN e.phones p " + "WHERE INDEX(p) BETWEEN 0 AND 4 "; query = em.createQuery(jpql); emps = query.getResultList(); displayQueryResult(jpql, emps); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
(4.3) CASE
더보기
1. Open jpa2.0_jpql_case NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_jpql_case.
- Click Open Project.
- Observe that the jpa2.0_jpql_case project node appears under Projects tab window.
2. Build and run jpa2.0_jpql_case project.
- Right-click jpa2.0_jpql_case project and select Run.
- Observe the result in the Output window.

Figure-4.31
(4.4) Study the code
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.EmployeeService; import javax.persistence.Query; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); em.getTransaction().begin(); es.createEmployee("Sang Shin", 10000); es.createEmployee("Bill Clinton", 8000); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); em.getTransaction().commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); // Use CASE String jpql = "UPDATE Employee e SET e.salary = " + "CASE WHEN e.salary > 9000 THEN e.salary * 1.10 " + " WHEN e.salary > 7500 THEN e.salary * 1.08 " + " ELSE e.salary * 0.95 " + "END" ; Query q = em.createQuery(jpql); em.getTransaction().begin(); int updated = q.executeUpdate(); em.getTransaction().commit(); displayQueryResult(jpql, updated); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, int deleted) { System.out.println("\n------ Query result of \"" + jpql + "\""); System.out.println("Number of updated records " + deleted); } } |
Summary
In this exercise, you have explored some new keywords that are added to JPQL, especially INDEX and CASE.
Exercise 5: Criteria API (without using Metamodel)
더보기
The Java Persistence Criteria API is used to define queries through the construction of object-based query definition objects, rather than use of the string-based approach of the Java Persistence query language, thus providing type-safe, and portable queries that work regardless of the underlying data store.
The Criteria API and JPQL are closely related, and designed to allow similar operations in their queries. Developers familiar with JPQL syntax will find equivalent object-level operations in the Criteria API.
The basic semantics of a Criteria query consists of a select clause, a from clause, and an optional where clause, similar to a JPQL query. Criteria queries set these clauses using Java programming language objects, so the query can be created in a type-safe manner.
Please read Basic Type-Safe Queries Using the Criteria API and Metamodel API section of the Java EE 6 tutorial before you do this exercise.
- Criteria API with "where" method
- Study code
- Criteria API with "orderBy" method
- Study code
- Criteria API with relationship traversal
- Study code
- Criteria API with inner join operation
- Study code
(5.1) Criteria API with "where" method
0. Delete PHONE_TABLE and EMPLOYEE tables.
1. Open jpa2.0_criteria_where NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_criteria_where.
- Click Open Project.
- Observe that the jpa2.0_criteria_where project node appears under Projects tab window.
2. Build and run jpa2.0_criteria_where project.
- Right-click jpa2.0_criteria_where project and select Run.
- Observe the result in the Output window.

Figure-5.11
| ------ Query result of "SELECT e FROM Employee e" Employee 3, Angela Caicedo, 6000 Employee 5, Charles Song, 4500 Employee 1, Sang Shin, 10000 Employee 4, Annie Song, 5000 Employee 2, Bill Clinton, 8000 ******* Query result using Criteria API Employee 3, Angela Caicedo, 6000 Employee 5, Charles Song, 4500 Employee 1, Sang Shin, 10000 Employee 4, Annie Song, 5000 Employee 2, Bill Clinton, 8000 ------ Query result of "SELECT e FROM Employee e where e.name = 'Sang Shin'" Employee 1, Sang Shin, 10000 ******* Query result using Criteria API Employee 1, Sang Shin, 10000 ------ Query result of "SELECT e FROM Employee e where e.name = 'Sang Shin' OR e.salary > 7000" Employee 1, Sang Shin, 10000 Employee 2, Bill Clinton, 8000 ******* Query result using Criteria API Employee 1, Sang Shin, 10000 Employee 2, Bill Clinton, 8000 ------ Query result of "SELECT e FROM Employee e where e.name LIKE 'A%'" Employee 3, Angela Caicedo, 6000 Employee 4, Annie Song, 5000 ******* Query result using Criteria API Employee 3, Angela Caicedo, 6000 Employee 4, Annie Song, 5000 ------ Query result of "SELECT e FROM Employee e where e.name IN ('Sang Shin', 'Bill Clinton', 'Some name')" Employee 1, Sang Shin, 10000 Employee 2, Bill Clinton, 8000 ******* Query result using Criteria API Employee 1, Sang Shin, 10000 |
(5.2) Study code
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import java.util.List; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); em.getTransaction().begin(); es.createEmployee("Sang Shin", 10000); es.createEmployee("Bill Clinton", 8000); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Song", 4500); em.getTransaction().commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); // Get all employees whose name is 'Sang Shin' String jpql = "SELECT e FROM Employee e"; List<Employee> emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API CriteriaBuilder cbuilder = em.getEntityManagerFactory().getCriteriaBuilder(); CriteriaQuery<Employee> criteria = cbuilder.createQuery(Employee.class); Root<Employee> employee = criteria.from(Employee.class); // ---- Build criteria criteria.select(employee); // ---- Create a query object from Criteria and perform query operation //TypedQuery<Employee> q = em.createQuery(criteria); //emps = q.getResultList(); emps = em.createQuery(criteria).getResultList(); // ---- Display the result displayQueryResult2(emps); // Get all employees whose name is 'Sang Shin' jpql = "SELECT e FROM Employee e where e.name = 'Sang Shin'"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API // ---- Build criteria criteria.select(employee); criteria.where(cbuilder.equal(employee.get("name"), "Sang Shin")); // ---- Create a query object from Criteria and perform query operation emps = em.createQuery(criteria).getResultList(); // ---- Display the result displayQueryResult2(emps); // Get all employees whose name is 'Sang Shin' or whose salary is greater than 7000 jpql = "SELECT e FROM Employee e where e.name = 'Sang Shin' OR e.salary > 7000"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(cbuilder.or(cbuilder.equal(employee.get("name"), "Sang Shin"), cbuilder.greaterThan(employee.get("salary").as(Integer.class), 7000))); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); // Get all emplyees whose name starts with A jpql = "SELECT e FROM Employee e where e.name LIKE 'A%'"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(cbuilder.like(employee.get("name").as(String.class), "A%")); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); // Get all employees whose name is either 'Sang Shin' or 'Bill Clinton" or 'Some name' jpql = "SELECT e FROM Employee e where e.name IN ('Sang Shin', 'Bill Clinton', 'Some name')"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(employee.get("name").in("Sang Shin", "Bill Clinton", "Some name")); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } // Display the query result public static void displayQueryResult2(List<Employee> emps) { System.out.println("\n******* Query result using Criteria API"); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
2. Display and study Javadoc of CriteriaQuery.

(5.3) Criteria API with "orderBy" method
더보기
1. Open jpa2.0_criteria_order_by NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_criteria_order_by.
- Click Open Project.
- Observe that the jpa2.0_criteria_order_by project node appears under Projects tab window.
2. Build and run jpa2.0_criteria_order_by project.
- Right-click jpa2.0_criteria_order_by project and select Run.
- Observe the result in the Output window.

Figure-5.31
(5.4) Study code
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import java.util.List; import javax.persistence.EntityTransaction; import javax.persistence.Query; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); EntityTransaction tx = em.getTransaction(); tx.begin(); es.createEmployee("Sang Shin", 10000); es.createEmployee("Bill Clinton", 8000); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Lannie", 7500); es.createEmployee("Shelley Nichole", 8500); tx.commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); // Perform JPA query with ORDER BY String jpql = "SELECT e FROM Employee e " + "WHERE e.salary > 4000 " + "ORDER BY e.name ASC, e.salary DESC"; Query q = em.createQuery(jpql); List<Employee> emps = q.getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API CriteriaBuilder cbuilder = em.getEntityManagerFactory().getCriteriaBuilder(); CriteriaQuery<Employee> criteria = cbuilder.createQuery(Employee.class); Root<Employee> employee = criteria.from(Employee.class); // Create criteria criteria.select(employee); criteria.where(cbuilder.or(cbuilder.equal(employee.get("name"), "Sang Shin"), cbuilder.greaterThan(employee.get("salary").as(Integer.class), 4000))); criteria.orderBy(cbuilder.asc(employee.get("name")), cbuilder.desc(employee.get("salary"))); // Create query using Criteria and then perform query operation emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } // Display the query result public static void displayQueryResult2(List<Employee> emps) { System.out.println("\n******* Query result using Criteria API"); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
(5.5) Criteria API with relationship traversal
더보기
1. Open jpa2.0_criteria_relation_traversal NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_criteria_relation_traversal.
- Click Open Project.
- Observe that the jpa2.0_criteria_relation_traversal project node appears under Projects tab window.
2. Build and run jpa2.0_criteria_relation_traversal project.
- Right-click jpa2.0_criteria_relation_traversal project and select Run.
- Observe the result in the Output window.

Figure-5.51
(5.6) Study code
| package mypackage; import customer.model.Customer; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import java.util.List; import javax.persistence.Query; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("CustomerServicePU"); EntityManager em = emf.createEntityManager(); // Display the test table JPAUtil.checkData("select CUSTOMER_ID, DISCOUNT_CODE, NAME, EMAIL from CUSTOMER"); JPAUtil.checkData("select * from DISCOUNT_CODE"); // Display all customers whose discount rate is bigger than 10% String jpql = "SELECT c FROM Customer c WHERE c.discountCode.rate > 10"; Query query = em.createQuery(jpql); List<Customer> customers = query.getResultList(); displayQueryResult(jpql, customers); ///////// Perform the same query using Criteria API CriteriaBuilder cbuilder = em.getEntityManagerFactory().getCriteriaBuilder(); CriteriaQuery<Customer> criteria = cbuilder.createQuery(Customer.class); Root<Customer> Customer = criteria.from(Customer.class); // Create criteria criteria.select(Customer); criteria.where(cbuilder.greaterThan(Customer.get("discountCode").get("rate").as(Integer.class), 10)); // Create query using Criteria and then perform query operation customers = em.createQuery(criteria).getResultList(); displayQueryResult2(customers); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Customer> customers) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Customer e : customers) { System.out.println("Customer id = " + e.getCustomerId() + ", name = " + e.getName() + ", discount rate = " + e.getDiscountCode().getRate()); } } // Display the query result public static void displayQueryResult2(List<Customer> customers) { System.out.println("\n******* Query result using Criteria API"); for (Customer e : customers) { System.out.println("Customer id = " + e.getCustomerId() + ", name = " + e.getName() + ", discount rate = " + e.getDiscountCode().getRate()); } } } |
(5.7) Criteria API with inner join
더보기
1. Open jpa2.0_criteria_relation_innerjoin NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_criteria_relation_innerjoin.
- Click Open Project.
- Observe that the jpa2.0_criteria_relation_innerjoin project node appears under Projects tab window.
2. Build and run jpa2.0_criteria_relation_innerjoin project.
- Right-click jpa2.0_criteria_relation_innerjoin project and select Run.
- Observe the result in the Output window.

Figure-5.71
(5.8) Study code
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import java.util.List; import javax.persistence.Query; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Join; import javax.persistence.criteria.Root; import product.client.Manufacturer; import product.client.Product; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { // Display the test table JPAUtil.checkData("select MANUFACTURER_ID, NAME, CITY from MANUFACTURER"); //JPAUtil.checkData("select * from MANUFACTURER"); JPAUtil.checkData("select PRODUCT_ID, MANUFACTURER_ID, MARKUP, DESCRIPTION from PRODUCT"); //JPAUtil.checkData("select * from PRODUCT"); JPAUtil.checkData("select * from PRODUCT_CODE"); // Perform JPA operations EntityManagerFactory emf = Persistence.createEntityManagerFactory("ManufacturerServicePU"); EntityManager em = emf.createEntityManager(); // Display all manufacturers who have products whose markups are greater than 20.0 - same as above String jpql = "SELECT m FROM Manufacturer m " + "INNER JOIN m.productCollection p WHERE p.markup > 20.0"; Query query = em.createQuery(jpql); List<Manufacturer> manufacturers = query.getResultList(); displayQueryResult(jpql, manufacturers); ///////// Perform the same query using Criteria API CriteriaBuilder cbuilder = em.getEntityManagerFactory().getCriteriaBuilder(); CriteriaQuery<Manufacturer> criteria = cbuilder.createQuery(Manufacturer.class); Root<Manufacturer> m = criteria.from(Manufacturer.class); Join<Manufacturer, Product> p = m.join("productCollection"); // Create criteria criteria.select(m); criteria.where(cbuilder.greaterThan(p.get("markup").as(Integer.class), 20)); // Create query using Criteria and then perform query operation manufacturers = em.createQuery(criteria).getResultList(); displayQueryResult2(manufacturers); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Manufacturer> manufacturers) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Manufacturer e : manufacturers) { System.out.println("Manufacturer id = " + e.getManufacturerId() + ", name = " + e.getName() + ", Sales rep = " + e.getRep() ); } } // Display the query result public static void displayQueryResult2(List<Manufacturer> manufacturers) { System.out.println("\n******* Query result using Criteria API"); for (Manufacturer e : manufacturers) { System.out.println("Manufacturer id = " + e.getManufacturerId() + ", name = " + e.getName() + ", Sales rep = " + e.getRep() ); } } } |
Summary
In this exercise, you have explored how to use Criteria API to define queries through the construction of object-based query definition objects, rather than use of the string-based approach of the Java Persistence query language, thus providing type-safe, and portable queries that work regardless of the underlying data store.
Exercise 6: Criteria API (using Metamodel)
더보기
A metamodel class describes the meta information of a persistent class. A metamodel class is canonical if the class describes the meta information of a persistent entity in the exact manner stipulated by the JPA 2.0 specification. A canonical metamodel class is static in the sense all its member variables are declared static (and public). The Person_.age is one such static member variable. You instantiate the canonical class by generating a concrete Person_.java at a source-code level at development time. Through such instantiation, it is possible to refer to persistent attributes of Person at compile time, rather than at run time, in a strongly typed manner.
This Person_ metamodel class is an alternative means of referring to meta information of Person. This alternative is similar to the much-used (some may say, abused) Java Reflection API, but with a major conceptual difference. You can use reflection to obtain the meta information about an instance of a java.lang.Class, but meta information about Person.class cannot be referred to in a way that a compiler can verify. For example, using reflection, you'd refer to the field named age in Person.class with:
(6.1) Open, build, and run "jpa2.0_criteria_where_metamodel1_getMetaModel" sample application
1. Open jpa2.0_criteria_where_metamodel1_getMetaModel NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_criteria_where_metamodel1_getMetaModel.
- Click Open Project.
- Observe that the jpa2.0_criteria_where_metamodel1_getMetaModel project node appears under Projects tab window.
2. Build and run jpa2.0_criteria_where_metamodel1_getMetaModel project.
- Right-click jpa2.0_criteria_where_metamodel1_getMetaModel project and select Run.
- Observe the result in the Output window. Note that this is the same result you see when you ran jpa2.0_criteria_where project.

Figure-6.11
(6.2) Study code
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import java.util.List; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.Metamodel; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); em.getTransaction().begin(); es.createEmployee("Sang Shin", 10000); es.createEmployee("Bill Clinton", 8000); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Song", 4500); em.getTransaction().commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); // Get all employees whose name is 'Sang Shin' String jpql = "SELECT e FROM Employee e"; List<Employee> emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API CriteriaBuilder cbuilder = em.getEntityManagerFactory().getCriteriaBuilder(); CriteriaQuery<Employee> criteria = cbuilder.createQuery(Employee.class); // Use Metamodel - Obtaining a Metamodel Class Dynamically Using the Metamodel.getMetamodel Method Metamodel m = em.getMetamodel(); EntityType<Employee> Employee_ = m.entity(Employee.class); Root<Employee> employee = criteria.from(Employee_); //Root<Employee> employee = criteria.from(Employee.class); // ---- Build criteria criteria.select(employee); // ---- Create a query object from Criteria and perform query operration //TypedQuery<Employee> q = em.createQuery(criteria); //emps = q.getResultList(); emps = em.createQuery(criteria).getResultList(); // ---- Display the result displayQueryResult2(emps); // Get all employees whose name is 'Sang Shin' jpql = "SELECT e FROM Employee e where e.name = 'Sang Shin'"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API // ---- Build criteria criteria.select(employee); criteria.where(cbuilder.equal(employee.get("name"), "Sang Shin")); // ---- Create a query object from Criteria and perform query operration emps = em.createQuery(criteria).getResultList(); // ---- Display the result displayQueryResult2(emps); // Get all employees whose name is 'Sang Shin' or whose salary is greater than 7000 jpql = "SELECT e FROM Employee e where e.name = 'Sang Shin' OR e.salary > 7000"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(cbuilder.or(cbuilder.equal(employee.get("name"), "Sang Shin"), cbuilder.greaterThan(employee.get("salary").as(Integer.class), 7000))); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); // Get all emplyees whose name starts with A jpql = "SELECT e FROM Employee e where e.name LIKE 'A%'"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(cbuilder.like(employee.get("name").as(String.class), "A%")); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); // Get all employees whose name is either 'Sang Shin' or 'Bill Clinton" or 'Some name' jpql = "SELECT e FROM Employee e where e.name IN ('Sang Shin', 'Bill Clinton', 'Some name')"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(employee.get("name").in("Sang Shin", "Bill Clinton", "Some name")); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } // Display the query result public static void displayQueryResult2(List<Employee> emps) { System.out.println("\n******* Query result using Criteria API"); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
(6.3) Open, build, and run "jpa2.0_criteria_where_metamodel2_Root_getModel" sample application
더보기
1. Open jpa2.0_criteria_where_metamodel2_Root_getModel NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_criteria_where_metamodel2_Root_getModel.
- Click Open Project.
- Observe that the jpa2.0_criteria_where_metamodel2_Root_getModel project node appears under Projects tab window.
2. Build and run jpa2.0_criteria_where_metamodel2_Root_getModel project.
- Right-click jpa2.0_criteria_where_metamodel2_Root_getModel project and select Run.
- Observe the result in the Output window. Note that this is the same result you see when you ran jpa2.0_criteria_where project.

Figure-6.31
(6.4) Study code
1. Main.java
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import java.util.List; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.Metamodel; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); em.getTransaction().begin(); es.createEmployee("Sang Shin", 10000); es.createEmployee("Bill Clinton", 8000); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Song", 4500); em.getTransaction().commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); // Get all employees whose name is 'Sang Shin' String jpql = "SELECT e FROM Employee e"; List<Employee> emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API CriteriaBuilder cbuilder = em.getEntityManagerFactory().getCriteriaBuilder(); CriteriaQuery<Employee> criteria = cbuilder.createQuery(Employee.class); // Use Metamodel - Obtaining a Metamodel Class Dynamically Using the Root<T>.getModel Method Root<Employee> employee = criteria.from(Employee.class); EntityType<Employee> Employee_ = employee.getModel(); employee = criteria.from(Employee_); // ---- Build criteria criteria.select(employee); // ---- Create a query object from Criteria and perform query operration //TypedQuery<Employee> q = em.createQuery(criteria); //emps = q.getResultList(); emps = em.createQuery(criteria).getResultList(); // ---- Display the result displayQueryResult2(emps); // Get all employees whose name is 'Sang Shin' jpql = "SELECT e FROM Employee e where e.name = 'Sang Shin'"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API // ---- Build criteria criteria.select(employee); criteria.where(cbuilder.equal(employee.get("name"), "Sang Shin")); // ---- Create a query object from Criteria and perform query operration emps = em.createQuery(criteria).getResultList(); // ---- Display the result displayQueryResult2(emps); // Get all employees whose name is 'Sang Shin' or whose salary is greater than 7000 jpql = "SELECT e FROM Employee e where e.name = 'Sang Shin' OR e.salary > 7000"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(cbuilder.or(cbuilder.equal(employee.get("name"), "Sang Shin"), cbuilder.greaterThan(employee.get("salary").as(Integer.class), 7000))); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); // Get all emplyees whose name starts with A jpql = "SELECT e FROM Employee e where e.name LIKE 'A%'"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(cbuilder.like(employee.get("name").as(String.class), "A%")); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); // Get all employees whose name is either 'Sang Shin' or 'Bill Clinton" or 'Some name' jpql = "SELECT e FROM Employee e where e.name IN ('Sang Shin', 'Bill Clinton', 'Some name')"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); ///////// Perform the same query using Criteria API criteria.select(employee); criteria.where(employee.get("name").in("Sang Shin", "Bill Clinton", "Some name")); emps = em.createQuery(criteria).getResultList(); displayQueryResult2(emps); em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } // Display the query result public static void displayQueryResult2(List<Employee> emps) { System.out.println("\n******* Query result using Criteria API"); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
Summary
In this exercise, you have explored how to use Criteria API with metamodel class.
Exercise 7: Locking
더보기
Optimistic locking lets concurrent transactions process simultaneously, but detects and prevent collisions, this works best for applications where most concurrent transactions do not conflict. JPA Optimistic locking allows anyone to read and update an entity, however a version check is made upon commit and an exception is thrown if the version was updated in the database since the entity was read. In JPA for Optimistic locking you annotate an attribute with @Version.
The Version attribute will be incremented with a successful commit. The Version attribute can be an int, short, long, or timestamp.
Pessimistic concurrency locks the database row when data is read, this is the equivalent of a (SELECT . . . FOR UPDATE [NOWAIT]) . Pessimistic locking ensures that transactions do not update the same entity at the same time, which can simplify application code, but it limits concurrent access to the data which can cause bad scalability and may cause deadlocks. Pessimistic locking is better for applications with a higher risk of contention among concurrent transactions.
(7.1) Open, build, and run "locking" sample application (from "glassfish-samples")
1. Open locking NetBeans project (from "glassfish samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/samples/javaee6/jpa directory directory.
- Select locking.
- Click Open Project.

Figure-7.11
- Observe that the locking project node appears under Projects tab window.
2. Check the path to your server application installation.
- Browse to <GlassFish-v3-Installation-Directory>/glassfish/samples/bp-project directory and
open build.properties file with a text editor. - Check that in the second line javaee.home is set to the directory where GlassFish is installed.
For example, on a standard Mac OS X installation, it should be set to: /Applications/NetBeans
3. Build and run locking project.
- Right-click locking project and select Run.
- Observe the result in the Output window.
| locking-test.runjavaclient: LockingJavaClient: Test is starting Calling URL:http://localhost:8080/locking/test/?tc=initData&nc=6&ns=3&np=3 Starting parallel updates with 9 users for operation: updateWOL Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=1 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=3 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=5 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=8 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=6 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=4 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=2 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=9 Calling URL:http://localhost:8080/locking/test/?tc=updateWOL&uid=7 Result for operation updateWOL for userId 6 is Success Result for operation updateWOL for userId 8 is Success Result for operation updateWOL for userId 3 is Success Result for operation updateWOL for userId 5 is Failure Result for operation updateWOL for userId 9 is Success Result for operation updateWOL for userId 1 is Failure Result for operation updateWOL for userId 4 is Success Result for operation updateWOL for userId 7 is Success Result for operation updateWOL for userId 2 is Failure Parallel updates executed with 9 users for operation: updateWOL Time taken:7630 miliseconds Starting parallel updates with 9 users for operation: updateWPL Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=1 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=3 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=5 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=7 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=9 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=8 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=2 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=6 Calling URL:http://localhost:8080/locking/test/?tc=updateWPL&uid=4 Result for operation updateWPL for userId 7 is Success Result for operation updateWPL for userId 9 is Success Result for operation updateWPL for userId 4 is Success Result for operation updateWPL for userId 6 is Success Result for operation updateWPL for userId 5 is Success Result for operation updateWPL for userId 3 is Success Result for operation updateWPL for userId 1 is Success Result for operation updateWPL for userId 8 is Success Result for operation updateWPL for userId 2 is Success Parallel updates executed with 9 users for operation: updateWPL Time taken:11625 miliseconds LockingJavaClient: Test is ended |

Figure-7.12

(7.2) Study the code
1. Part.java
| /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package enterprise.locking.entity; import javax.persistence.*; import java.util.Set; @Entity @Table(name = "T_PART") public class Part implements java.io.Serializable { // Instance variables private int id; private String name; private int amount; private int verNum; private Set<User> users; public Part() { } public Part(int id, String name) { this.id = id; this.name = name; } public Part(int id, String name, int amount) { this.id = id; this.name = name; this.amount = amount; } // ================================================== // getters and setters for the state fields @Id @Column(name = "PID") public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(length = 20, name = "PNAME") public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(name = "AMOUNT") public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } @Version @Column(name = "VER") public int getVerNum() { return verNum; } public void setVerNum(int verNum) { this.verNum = verNum; } // =========================================================== // getters and setters for the association fields @OneToMany(cascade = CascadeType.ALL, mappedBy = "part") public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } public String toString() { return "Product id=" + getId() + ", amount=" + getAmount(); } } |

Figure-7.21

Figure-7.22
2. User.java
| /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package enterprise.locking.entity; import javax.persistence.*; @Entity @Table(name = "T_USER") public class User implements java.io.Serializable { public enum UserType { CONSUMER, SUPPLIER } private int id; private String firstName; private String lastName; private UserType userType; private int count; private Part part; public User() { } public User(int id, String firstName, String lastName) { this.id = id; this.firstName = firstName; this.lastName = lastName; } public User(int id, String firstName, String lastName, UserType userType) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.userType = userType; } //======================================================= // getters and setters for the state fields @Id @Column(name = "UID") public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(length = 20, name = "FNAME") public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } @Column(length = 20, name = "LNAME") public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Column(name = "UTYPE") public UserType getUserType() { return userType; } public void setUserType(UserType userType) { this.userType = userType; } @Column(name = "COUNT") public int getCount() { return count; } public void setCount(int count) { this.count = count; } // =========================================================== // getters and setters for the association fields @ManyToOne @JoinColumn(name = "PID") public Part getPart() { return part; } public void setPart(Part part) { this.part = part; } public String toString() { return "User id=" + getId() + ", lastName=" + getLastName() + ", userType=" + getUserType(); } } |
3. StatelessSessionBean.java
| /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package enterprise.locking.ejb; import enterprise.locking.entity.Part; import enterprise.locking.entity.User; import javax.ejb.Stateless; import javax.persistence.*; import java.util.Random; @Stateless public class StatelessSessionBean { @PersistenceContext private EntityManager em; private String name = "foo"; public String getName() { return name; } public void setName(String name) { this.name = name; } /** * Initializes data for given number of consumers, suppliers and parts */ public void initData(int numberOfConsumers, int numberOfSuppliers, int numberOfParts) { // user info int uid = 0; String fName = null; String lName = null; User u = null; int pid = 0; String pName = null; Part p = null; Part partRef[] = new Part[numberOfParts]; for (int i = 0; i < numberOfParts; i++) { pid++; pName = "p" + pid; p = new Part(pid, pName); p.setAmount(500); partRef[i] = p; em.persist(p); } int partIndex = 1; Random randomGenerator = new Random(); for (int i = 0; i < numberOfConsumers; i++) { uid++; fName = "f" + uid; lName = "l" + uid; u = new User(uid, fName, lName); u.setUserType(User.UserType.CONSUMER); u.setCount(2); // randam int from 0, ..., NT-1 partIndex = randomGenerator.nextInt(numberOfParts); u.setPart(partRef[partIndex]); em.persist(u); } for (int i = 0; i < numberOfSuppliers; i++) { uid++; fName = "f" + uid; lName = "l" + uid; u = new User(uid, fName, lName); u.setUserType(User.UserType.SUPPLIER); u.setCount(10); partIndex = randomGenerator.nextInt(numberOfParts); u.setPart(partRef[partIndex]); em.persist(u); } } /** * A find followed by some think time, followed by update. */ public boolean updateWithOptimisticLock(int uID, int s) { boolean updateSuccessfull = true; User u = em.find(User.class, uID); int pID = u.getPart().getId(); Part p = em.find(Part.class, pID); // Simulate think time to allow parallel threads to find Usrs in parallel. simulateThinkTimeForSecond(s); int uCount = u.getCount(); int pAmount = p.getAmount(); // update part if (u.getUserType() == User.UserType.CONSUMER) { p.setAmount(pAmount - uCount); } else { p.setAmount(pAmount + uCount); } try { em.flush(); } catch (OptimisticLockException e) { System.out.println("Got OptimisticLockException while updating with Optimistic Lock. " + "The transaction will be rolled back"); updateSuccessfull = false; } catch (PersistenceException e ) { System.out.println("Got Exception while updating with optimstic lock" + e); updateSuccessfull = false; } return updateSuccessfull; } /** * A find with pessimistic lock followed by some think time, followed by update. */ public boolean updateWithPessimisticLock(int uID, int s) { boolean updateSuccessfull = true; User u = em.find(User.class, uID); int pID = u.getPart().getId(); // Using Pessimistic lock to find the part object. Part p = em.find(Part.class, pID, LockModeType.PESSIMISTIC_WRITE); // Simulate think time to allow parallel threads to find in parallel. simulateThinkTimeForSecond(s); int uCount = u.getCount(); int pAmount = p.getAmount(); // update part if (u.getUserType() == User.UserType.CONSUMER) { p.setAmount(pAmount - uCount); } else { p.setAmount(pAmount + uCount); } try { em.flush(); } catch (PersistenceException e) { updateSuccessfull = false; } return updateSuccessfull; } public void simulateThinkTimeForSecond(int sec) { //TODO check if sleep is allowed by EE spec try { Thread.sleep(sec * 1000); } catch (Exception ex) { System.out.println("get exp in sleep"); } } } |


Summary
In this exercise, you have experimented with both optimistic locking and pessimistic locking.
더보기
(8.1) Open, build, and run "jpa2.0_cache" sample application
1. Open jpa2.0_cache NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_jpa2.0/samples directory.
- Select jpa2.0_cache.
- Click Open Project.
- Observe that the jpa2.0_cache project node appears under Projects tab window.
2. Build and run jpa2.0_cache project.
- Right-click jpa2.0_cache project and select Run.
- Observe the result in the Output window.

Figure-8.11
(8.2) Study code
| package mypackage; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import examples.model.Employee; import examples.model.EmployeeService; import java.util.List; import javax.persistence.Cache; import util.JPAUtil; public class Main { public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService"); EntityManager em = emf.createEntityManager(); EmployeeService es = new EmployeeService(em); em.getTransaction().begin(); es.createEmployee("Sang Shin", 10000); es.createEmployee("Bill Clinton", 8000); es.createEmployee("Angela Caicedo", 6000); es.createEmployee("Annie Song", 5000); es.createEmployee("Charles Song", 4500); em.getTransaction().commit(); // Display the table JPAUtil.checkData("select * from EMPLOYEE"); // Get all employees whose name is 'Sang Shin' String jpql = "SELECT e FROM Employee e"; List<Employee> emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); // Get all employees whose name is 'Sang Shin' jpql = "SELECT e FROM Employee e where e.name = 'Sang Shin'"; emps = em.createQuery(jpql).getResultList(); displayQueryResult(jpql, emps); // Perform cache operations Cache cache = emf.getCache(); System.out.println("cache.contains(Employee.class, 100) = " + cache.contains(Employee.class, 100)); // false System.out.println("cache.contains(Employee.class, 1) before evict = " + cache.contains(Employee.class, 1)); // true cache.evict(Employee.class, 1); System.out.println("cache.contains(Employee.class, 1) after evict = " + cache.contains(Employee.class, 1)); // false em.close(); emf.close(); } // Display the query result public static void displayQueryResult(String jpql, List<Employee> emps) { System.out.println("\n------ Query result of \"" + jpql + "\""); for (Employee e : emps) { System.out.println("Employee " + e.getId() + ", " + e.getName() + ", " + e.getSalary()); } } } |
2. Employee.java
| package examples.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import org.eclipse.persistence.annotations.Cache; import org.eclipse.persistence.annotations.CacheType; @Entity @Cache(type=CacheType.FULL) public class Employee { @Id @GeneratedValue @Column(name="EMPLOYEE_ID") private int id; private String name; private long salary; public Employee() {} public Employee(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } @Overrride public String toString() { return "Employee id: " + getId() + " name: " + getName() + " salary: " + getSalary(); } } |
Summary
In this exercise, you have explored with newly introduced Caching API.
더보기
In this exercise, you are going to build and run "order" sample application from Java EE 6 tutorial. For detailed description of this example, please see "The order Application" section of the tutorial.
(9.1) Open, build, and run "order" sample application (from "Java EE 6 tutorial")
1. Open order NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/docs/javaee-tutorial/examples/persistence directory. (This is "Java EE 6 tutorial" examples.)
- Select order.
- Click Open Project.

Figure-9.11
- Observe that the order project node appears under Projects tab window.
2. Change the Relative URL to order.xhtml. (This is the URL that gets accessed when the application starts.) If you don't take this step, the application will try to display index.xhtml, which does not exist.

Figure-9.12

Figure-9.13
3. Build and run order project.
- Right-click order project and select Run.
- Observe that browser gets displayed.

Figure-9.14

Figure-9.15

Figure-9.16

Figure-9.17

Figure-9.18

Figure-9.19

Figure-9.20
Trouble-shooting: If you experience the problem below, it is because you have not changed the Relative URL as described above.
Figure-9.21
(9.2) Control flow of "viewing all orders"
1. The order.xhtml is accessed. The #{orderManager.orders} calls getOrders() method of the OrderManager class.
| ... <h:dataTable var="order" value="#{orderManager.orders}" rules="all" cellpadding="5"> <h:column> <f:facet name="header"> <h:outputText value="Order ID" /> </f:facet> <h:form> <h:commandLink id="order_id_link" action="lineItem"> <h:outputText value="#{order.orderId}" /> <f:setPropertyActionListener target="#{orderManager.currentOrder}" value="#{order.orderId}" /> </h:commandLink> </h:form> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Shipment Info" /> </f:facet> <h:outputText value="#{order.shipmentInfo}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Status" /> </f:facet> <h:outputText value="#{order.status}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Last Updated" /> </f:facet> <h:outputText value="#{order.lastUpdate}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Discount" /> </f:facet> <h:outputText value="#{order.discount}%" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Actions" /> </f:facet> <h:form> <h:commandLink value="Delete" actionListener="#{orderManager.removeOrder}" action="order"> <f:param name="deleteOrderId" value="#{order.orderId}" /> </h:commandLink> </h:form> </h:column> </h:dataTable> ... |
2. The getOrders() method of the OrderManager class calls getOrders() method of the RequestBean class. Note that the RequestBean is injected.
| ... @ManagedBean @SessionScoped public class OrderManager { private static Logger logger = Logger.getLogger("order.web.OrderManager"); private Boolean findVendorTableDisabled = true; private Boolean partsTableDisabled = true; private Integer currentOrder; private Integer newOrderId; private List<Part> newOrderParts; private List<Part> newOrderSelectedParts; private List<Order> orders; private List<String> vendorSearchResults; private Long selectedVendorPartNumber; @EJB private RequestBean request; private String newOrderShippingInfo; private String selectedPartNumber; private String vendorName; private char newOrderStatus; private int newOrderDiscount; private int selectedPartRevision; /** * @return the orders */ public List<Order> getOrders() { try { this.orders = request.getOrders(); } catch (Exception e) { e.printStackTrace(); } return orders; } ... |
3. The getOrders() method of the RequestBean class calls a Named query called "findAllOrders", which is defined in the Order class.
| ... public List<Order> getOrders() { try { return (List<Order>) em.createNamedQuery("findAllOrders") .getResultList(); } catch (Exception e) { throw new EJBException(e.getMessage()); } } ... |
4. The "findAllOrders" Named query performs JPQL "SELECT o FROM Order o ORDER BY o.orderId".
| ... @Entity @Table(name = "PERSISTENCE_ORDER_ORDER") @NamedQuery(name = "findAllOrders", query = "SELECT o FROM Order o " + "ORDER BY o.orderId") public class Order implements java.io.Serializable { private Collection<LineItem> lineItems; private Date lastUpdate; private Integer orderId; private String shipmentInfo; private char status; private int discount; public Order() { this.lastUpdate = new Date(); this.lineItems = new ArrayList<LineItem>(); } ... |
(9.3) Control flow of "creating an order"

1. The submitOrder(..) method of the OrderManager class is invoked when a user submits an order.
| ... <ui:define name="newOrderForm"> <h:form> <h:outputLabel for="orderIdInputText" rendered="true" value="Order ID: " /> <h:inputText id="orderIdInputText" required="true" value="#{orderManager.newOrderId}" /><br /> <h:outputLabel for="shipmentInfoInputText" rendered="true" value="Shipment Info: " /> <h:inputText id="shipmentInfoInputText" required="true" value="#{orderManager.newOrderShippingInfo}" /><br /> <h:outputLabel for="statusMenu" rendered="true" value="Status: " /> <h:selectOneMenu id="statusMenu" required="true" value="#{orderManager.newOrderStatus}"> <f:selectItem itemValue="Y" itemLabel="Complete" /> <f:selectItem itemValue="N" itemLabel="Pending" /> </h:selectOneMenu><br /> <h:outputLabel for="discountMenu" rendered="true" value="Discount: " /> <h:selectOneMenu id="discountMenu" required="true" value="#{orderManager.newOrderDiscount}"> <f:selectItem itemValue="0" itemLabel="0 %" /> <f:selectItem itemValue="5" itemLabel="5 %" /> <f:selectItem itemValue="10" itemLabel="10 %" /> <f:selectItem itemValue="15" itemLabel="15 %" /> <f:selectItem itemValue="20" itemLabel="20 %" /> <f:selectItem itemValue="25" itemLabel="25 %" /> <f:selectItem itemValue="30" itemLabel="30 %" /> <f:selectItem itemValue="35" itemLabel="35 %" /> <f:selectItem itemValue="40" itemLabel="40 %" /> </h:selectOneMenu><br /> <h:commandButton value="Submit" action="#{orderManager.submitOrder}" /> </h:form> </ui:define> ... |
2. The submitOrder() method calls createOrder(..) method of the RequestBean class.
| ... @EJB private RequestBean request; ... public void submitOrder() { try { request.createOrder( newOrderId, newOrderStatus, newOrderDiscount, newOrderShippingInfo); logger.info( "Created new order with order ID " + newOrderId + ", status " + newOrderStatus + ", discount " + newOrderDiscount + ", and shipping info " + newOrderShippingInfo + "."); this.newOrderId = null; this.newOrderDiscount = 0; this.newOrderParts = null; this.newOrderShippingInfo = null; } catch (Exception e) { logger.warning("Problem creating order in submitOrder."); } } ... |
3. The createOrder(..) method of the RequestBean creates an order and persists it.
| ... public void createOrder( Integer orderId, char status, int discount, String shipmentInfo) { try { Order order = new Order(orderId, status, discount, shipmentInfo); em.persist(order); } catch (Exception e) { throw new EJBException(e.getMessage()); } } ... |
Summary
In this exercise, you have explored with the "order" sample application that comes with Java EE 6 tutorial.
Exercise 10: Build and run "roster" sample application (from "Java EE 6 tutorial")
더보기
In this exercise, you are going to build and run "roster" sample application from Java EE 6 tutorial. For detailed description of this example, please see "The roster Application" section of the tutorial.
- Open, build, and run "roster" sample application
- Study code of the roster-app-client project
- Study code of the roster-ejb project
(10.1) Open, build, and run "roster" sample application (from "Java EE 6 tutorial")
1. Open roster NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/docs/javaee-tutorial/examples/persistence directory. (This is "Java EE 6 tutorial" examples.)
- Select roster.
- Check Open Required Projects
- Click Open Project.
2. Open required projects.

- Observe that the roster-app-client and roster-ejb projects are opened.

3. Build and run roster project.
- Right-click roster project and select Run.
- Observe the result in the Output window.

Figure-10.11
(10.2) Study "roster-app-client" project
1. RosterClient.java

Figure-10.21
| /* * Copyright 2009 Sun Microsystems, Inc. * All rights reserved. You may not modify, use, * reproduce, or distribute this software except in * compliance with the terms of the License at: * http://developer.sun.com/berkeley_license.html */ package roster.client; import java.util.Iterator; import java.util.List; import javax.ejb.EJB; import roster.request.Request; import roster.util.LeagueDetails; import roster.util.PlayerDetails; import roster.util.TeamDetails; public class RosterClient { @EJB private static Request request; public RosterClient(String[] args) { } public static void main(String[] args) { RosterClient client = new RosterClient(args); try { client.insertInfo(); client.getSomeInfo(); client.getMoreInfo(); client.removeInfo(); System.exit(0); } catch (Exception ex) { System.err.println("Caught an exception:"); ex.printStackTrace(); } } private void insertInfo() { try { // Leagues request.createLeague(new LeagueDetails("L1", "Mountain", "Soccer")); request.createLeague( new LeagueDetails("L2", "Valley", "Basketball")); request.createLeague( new LeagueDetails("L3", "Foothills", "Soccer")); request.createLeague( new LeagueDetails("L4", "Alpine", "Snowboarding")); // Teams request.createTeamInLeague( new TeamDetails("T1", "Honey Bees", "Visalia"), "L1"); request.createTeamInLeague( new TeamDetails("T2", "Gophers", "Manteca"), "L1"); request.createTeamInLeague( new TeamDetails("T5", "Crows", "Orland"), "L1"); request.createTeamInLeague( new TeamDetails("T3", "Deer", "Bodie"), "L2"); request.createTeamInLeague( new TeamDetails("T4", "Trout", "Truckee"), "L2"); request.createTeamInLeague( new TeamDetails("T6", "Marmots", "Auburn"), "L3"); request.createTeamInLeague( new TeamDetails("T7", "Bobcats", "Grass Valley"), "L3"); request.createTeamInLeague( new TeamDetails("T8", "Beavers", "Placerville"), "L3"); request.createTeamInLeague( new TeamDetails("T9", "Penguins", "Incline Village"), "L4"); request.createTeamInLeague( new TeamDetails("T10", "Land Otters", "Tahoe City"), "L4"); // Players, Team T1 request.createPlayer("P1", "Phil Jones", "goalkeeper", 100.00); request.addPlayer("P1", "T1"); request.createPlayer("P2", "Alice Smith", "defender", 505.00); request.addPlayer("P2", "T1"); request.createPlayer("P3", "Bob Roberts", "midfielder", 65.00); request.addPlayer("P3", "T1"); request.createPlayer("P4", "Grace Phillips", "forward", 100.00); request.addPlayer("P4", "T1"); request.createPlayer("P5", "Barney Bold", "defender", 100.00); request.addPlayer("P5", "T1"); // Players, Team T2 request.createPlayer("P6", "Ian Carlyle", "goalkeeper", 555.00); request.addPlayer("P6", "T2"); request.createPlayer( "P7", "Rebecca Struthers", "midfielder", 777.00); request.addPlayer("P7", "T2"); request.createPlayer("P8", "Anne Anderson", "forward", 65.00); request.addPlayer("P8", "T2"); request.createPlayer("P9", "Jan Wesley", "defender", 100.00); request.addPlayer("P9", "T2"); request.createPlayer("P10", "Terry Smithson", "midfielder", 100.00); request.addPlayer("P10", "T2"); // Players, Team T3 request.createPlayer("P11", "Ben Shore", "point guard", 188.00); request.addPlayer("P11", "T3"); request.createPlayer( "P12", "Chris Farley", "shooting guard", 577.00); request.addPlayer("P12", "T3"); request.createPlayer( "P13", "Audrey Brown", "small forward", 995.00); request.addPlayer("P13", "T3"); request.createPlayer( "P14", "Jack Patterson", "power forward", 100.00); request.addPlayer("P14", "T3"); request.createPlayer("P15", "Candace Lewis", "point guard", 100.00); request.addPlayer("P15", "T3"); // Players, Team T4 request.createPlayer( "P16", "Linda Berringer", "point guard", 844.00); request.addPlayer("P16", "T4"); request.createPlayer( "P17", "Bertrand Morris", "shooting guard", 452.00); request.addPlayer("P17", "T4"); request.createPlayer("P18", "Nancy White", "small forward", 833.00); request.addPlayer("P18", "T4"); request.createPlayer("P19", "Billy Black", "power forward", 444.00); request.addPlayer("P19", "T4"); request.createPlayer("P20", "Jodie James", "point guard", 100.00); request.addPlayer("P20", "T4"); // Players, Team T5 request.createPlayer("P21", "Henry Shute", "goalkeeper", 205.00); request.addPlayer("P21", "T5"); request.createPlayer("P22", "Janice Walker", "defender", 857.00); request.addPlayer("P22", "T5"); request.createPlayer( "P23", "Wally Hendricks", "midfielder", 748.00); request.addPlayer("P23", "T5"); request.createPlayer("P24", "Gloria Garber", "forward", 777.00); request.addPlayer("P24", "T5"); request.createPlayer("P25", "Frank Fletcher", "defender", 399.00); request.addPlayer("P25", "T5"); // Players, Team T9 request.createPlayer("P30", "Lakshme Singh", "downhill", 450.00); request.addPlayer("P30", "T9"); request.createPlayer("P31", "Mariela Prieto", "freestyle", 420.00); request.addPlayer("P31", "T9"); // Players, Team T10 request.createPlayer("P32", "Soren Johannsen", "freestyle", 375.00); request.addPlayer("P32", "T10"); request.createPlayer("P33", "Andre Gerson", "freestyle", 396.00); request.addPlayer("P33", "T10"); request.createPlayer("P34", "Zoria Lepsius", "downhill", 431.00); request.addPlayer("P34", "T10"); // Players, no team request.createPlayer("P26", "Hobie Jackson", "pitcher", 582.00); request.createPlayer("P27", "Melinda Kendall", "catcher", 677.00); // Players, multiple teams request.createPlayer( "P28", "Constance Adams", "substitute", 966.00); request.addPlayer("P28", "T1"); request.addPlayer("P28", "T3"); // Adding existing players to second soccer league request.addPlayer("P24", "T6"); request.addPlayer("P21", "T6"); request.addPlayer("P9", "T6"); request.addPlayer("P7", "T5"); } catch (Exception ex) { System.err.println("Caught an exception:"); ex.printStackTrace(); } } private void getSomeInfo() { try { List<PlayerDetails> playerList; List<TeamDetails> teamList; List<LeagueDetails> leagueList; System.out.println("List all players in team T2:"); playerList = request.getPlayersOfTeam("T2"); printDetailsList(playerList); System.out.println(); System.out.println("List all teams in league L1:"); teamList = request.getTeamsOfLeague("L1"); printDetailsList(teamList); System.out.println(); System.out.println("List all defenders:"); playerList = request.getPlayersByPosition("defender"); printDetailsList(playerList); System.out.println(); System.out.println("List the leagues of player P28"); leagueList = request.getLeaguesOfPlayer("P28"); printDetailsList(leagueList); System.out.println(); } catch (Exception ex) { System.err.println("Caught an exception:"); ex.printStackTrace(); } } // getSomeInfo private void getMoreInfo() { try { LeagueDetails leagueDetails; TeamDetails teamDetails; PlayerDetails playerDetails; List<PlayerDetails> playerList; List<TeamDetails> teamList; List<LeagueDetails> leagueList; List<String> sportList; System.out.println("Details of league L1:"); leagueDetails = request.getLeague("L1"); System.out.println(leagueDetails.toString()); System.out.println(); System.out.println("Details of team T3:"); teamDetails = request.getTeam("T3"); System.out.println(teamDetails.toString()); System.out.println(); System.out.println("Details of player P20:"); playerDetails = request.getPlayer("P20"); System.out.println(playerDetails.toString()); System.out.println(); System.out.println("List all teams in league L3:"); teamList = request.getTeamsOfLeague("L3"); printDetailsList(teamList); System.out.println(); System.out.println("List all players:"); playerList = request.getAllPlayers(); printDetailsList(playerList); System.out.println(); System.out.println("List all players not on a team:"); playerList = request.getPlayersNotOnTeam(); printDetailsList(playerList); System.out.println(); System.out.println("Details of Jack Patterson, a power forward:"); playerList = request.getPlayersByPositionAndName( "power forward", "Jack Patterson"); printDetailsList(playerList); System.out.println(); System.out.println("List all players in the city of Truckee:"); playerList = request.getPlayersByCity("Truckee"); printDetailsList(playerList); System.out.println(); System.out.println("List all soccer players:"); playerList = request.getPlayersBySport("Soccer"); printDetailsList(playerList); System.out.println(); System.out.println("List all players in league L1:"); playerList = request.getPlayersByLeagueId("L1"); printDetailsList(playerList); System.out.println(); System.out.println( "List all players making a higher salary than Ian Carlyle:"); playerList = request.getPlayersByHigherSalary("Ian Carlyle"); printDetailsList(playerList); System.out.println(); System.out.println( "List all players with a salary between 500 and 800:"); playerList = request.getPlayersBySalaryRange(500.00, 800.00); printDetailsList(playerList); System.out.println(); System.out.println("List all players of team T5:"); playerList = request.getPlayersOfTeam("T5"); printDetailsList(playerList); System.out.println(); System.out.println("List all the leagues of player P28:"); leagueList = request.getLeaguesOfPlayer("P28"); printDetailsList(leagueList); System.out.println(); System.out.println("List all the sports of player P28:"); sportList = request.getSportsOfPlayer("P28"); printDetailsList(sportList); System.out.println(); } catch (Exception ex) { System.err.println("Caught an exception:"); ex.printStackTrace(); } } // getMoreInfo private void removeInfo() { try { System.out.println("Removing team T6."); request.removeTeam("T6"); System.out.println(); System.out.println("Removing player P24"); request.removePlayer("P24"); System.out.println(); } catch (Exception ex) { System.err.println("Caught an exception:"); ex.printStackTrace(); } } private static void printDetailsList(List list) { Iterator i = list.iterator(); while (i.hasNext()) { Object details = (Object) i.next(); System.out.println(details.toString()); } System.out.println(); } // printDetailsList } |
2. See the properties of the roster-app-client project.
- Right click the roster-app-client project and select Properties.
- Click Libraries on the left and observe that roster-ejb.jar is in its class path.

Figure-10.22
- Click Run on the left and observe that the roster.client.RosterClient is the Main class meaning main() method of the class gets executed when the project is run.

Figure-10.23
(10.3) Study "roster-ejb" project
1. Request.java.
| /* * Copyright 2009 Sun Microsystems, Inc. * All rights reserved. You may not modify, use, * reproduce, or distribute this software except in * compliance with the terms of the License at: * http://developer.sun.com/berkeley_license.html */ package roster.request; import java.util.List; import javax.ejb.Remote; import roster.util.LeagueDetails; import roster.util.PlayerDetails; import roster.util.TeamDetails; @Remote public interface Request { void addPlayer( String playerId, String teamId); void createLeague(LeagueDetails leagueDetails); void createPlayer( String id, String name, String position, double salary); void createTeamInLeague( TeamDetails teamDetails, String leagueId); void dropPlayer( String playerId, String teamId); List<PlayerDetails> getAllPlayers(); LeagueDetails getLeague(String leagueId); List<LeagueDetails> getLeaguesOfPlayer(String playerId); PlayerDetails getPlayer(String playerId); List<PlayerDetails> getPlayersByCity(String city); List<PlayerDetails> getPlayersByHigherSalary(String name); List<PlayerDetails> getPlayersByLeagueId(String leagueId); List<PlayerDetails> getPlayersByPosition(String position); List<PlayerDetails> getPlayersByPositionAndName( String position, String name); List<PlayerDetails> getPlayersBySalaryRange( double low, double high); List<PlayerDetails> getPlayersBySport(String sport); List<PlayerDetails> getPlayersNotOnTeam(); List<PlayerDetails> getPlayersOfTeam(String teamId); List<String> getSportsOfPlayer(String playerId); TeamDetails getTeam(String teamId); List<TeamDetails> getTeamsOfLeague(String leagueId); void removeLeague(String leagueId); void removePlayer(String playerId); void removeTeam(String teamId); } |
2. RequestBean.java.
| /* * Copyright 2009 Sun Microsystems, Inc. * All rights reserved. You may not modify, use, * reproduce, or distribute this software except in * compliance with the terms of the License at: * http://developer.sun.com/berkeley_license.html */ package roster.request; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.ejb.EJBException; import javax.ejb.Stateful; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Join; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import roster.entity.League; import roster.entity.League_; import roster.entity.Player; import roster.entity.Player_; import roster.entity.SummerLeague; import roster.entity.Team; import roster.entity.Team_; import roster.entity.WinterLeague; import roster.util.IncorrectSportException; import roster.util.LeagueDetails; import roster.util.PlayerDetails; import roster.util.TeamDetails; /** * This is the bean class for the RequestBean enterprise bean. * @author ian */ @Stateful public class RequestBean implements Request { private static final Logger logger = Logger.getLogger( "roster.request.RequestBean"); private CriteriaBuilder cb; @PersistenceContext private EntityManager em; @PostConstruct private void init() { cb = em.getCriteriaBuilder(); } public void createPlayer( String id, String name, String position, double salary) { logger.info("createPlayer"); try { Player player = new Player(id, name, position, salary); em.persist(player); } catch (Exception ex) { throw new EJBException(ex); } } public void addPlayer( String playerId, String teamId) { logger.info("addPlayer"); try { Player player = em.find(Player.class, playerId); Team team = em.find(Team.class, teamId); team.addPlayer(player); player.addTeam(team); } catch (Exception ex) { throw new EJBException(ex); } } public void removePlayer(String playerId) { logger.info("removePlayer"); try { Player player = em.find(Player.class, playerId); Collection<Team> teams = player.getTeams(); Iterator<Team> i = teams.iterator(); while (i.hasNext()) { Team team = i.next(); team.dropPlayer(player); } em.remove(player); } catch (Exception ex) { throw new EJBException(ex); } } ... public List<PlayerDetails> getPlayersByPosition(String position) { logger.info("getPlayersByPosition"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where( cb.equal( player.get(Player_.position), position)); cq.select(player); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getPlayersByHigherSalary(String name) { logger.info("getPlayersByHigherSalary"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player1 = cq.from(Player.class); Root<Player> player2 = cq.from(Player.class); // Get MetaModel from Root //EntityType<Player> Player_ = player1.getModel(); // create a Predicate object that finds players with a salary // greater than player1 Predicate gtPredicate = cb.greaterThan( player1.get(Player_.salary), player2.get(Player_.salary)); // create a Predicate object that finds the player based on // the name parameter Predicate equalPredicate = cb.equal( player1.get(Player_.name), name); // set the where clause with the predicates cq.where(gtPredicate, equalPredicate); // set the select clause, and return only unique entries cq.select(player1) .distinct(true); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getPlayersBySalaryRange( double low, double high) { logger.info("getPlayersBySalaryRange"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where( cb.between( player.get(Player_.salary), low, high)); // set the select clause cq.select(player) .distinct(true); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getPlayersByLeagueId(String leagueId) { logger.info("getPlayersByLeagueId"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); Join<Player, Team> team = player.join(Player_.teams); Join<Team, League> league = team.join(Team_.league); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where( cb.equal( league.get(League_.id), leagueId)); cq.select(player) .distinct(true); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getPlayersBySport(String sport) { logger.info("getPlayersByLeagueId"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); Join<Player, Team> team = player.join(Player_.teams); Join<Team, League> league = team.join(Team_.league); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where( cb.equal( league.get(League_.sport), sport)); cq.select(player) .distinct(true); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getPlayersByCity(String city) { logger.info("getPlayersByCity"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); Join<Player, Team> team = player.join(Player_.teams); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where( cb.equal( team.get(Team_.city), city)); cq.select(player) .distinct(true); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getAllPlayers() { logger.info("getAllPlayers"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); cq.select(player); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getPlayersNotOnTeam() { logger.info("getPlayersNotOnTeam"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where(cb.isEmpty(player.get(Player_.teams))); cq.select(player) .distinct(true); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<PlayerDetails> getPlayersByPositionAndName( String position, String name) { logger.info("getPlayersByPositionAndName"); List<Player> players = null; try { CriteriaQuery<Player> cq = cb.createQuery(Player.class); if (cq != null) { Root<Player> player = cq.from(Player.class); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where( cb.equal( player.get(Player_.position), position), cb.equal( player.get(Player_.name), name)); cq.select(player) .distinct(true); TypedQuery<Player> q = em.createQuery(cq); players = q.getResultList(); } return copyPlayersToDetails(players); } catch (Exception ex) { throw new EJBException(ex); } } public List<LeagueDetails> getLeaguesOfPlayer(String playerId) { logger.info("getLeaguesOfPlayer"); List<LeagueDetails> detailsList = new ArrayList<LeagueDetails>(); List<League> leagues = null; try { CriteriaQuery<League> cq = cb.createQuery(League.class); if (cq != null) { Root<League> league = cq.from(League.class); //EntityType<League> League_ = league.getModel(); Join<League, Team> team = league.join(League_.teams); //EntityType<Team> Team_ = team.getModel(); Join<Team, Player> player = team.join(Team_.players); cq.where( cb.equal( player.get(Player_.id), playerId)); cq.select(league) .distinct(true); TypedQuery<League> q = em.createQuery(cq); leagues = q.getResultList(); } } catch (Exception ex) { throw new EJBException(ex); } Iterator<League> i = leagues.iterator(); while (i.hasNext()) { League league = (League) i.next(); LeagueDetails leagueDetails = new LeagueDetails( league.getId(), league.getName(), league.getSport()); detailsList.add(leagueDetails); } return detailsList; } public List<String> getSportsOfPlayer(String playerId) { logger.info("getSportsOfPlayer"); List<String> sports = new ArrayList<String>(); try { CriteriaQuery<String> cq = cb.createQuery(String.class); if (cq != null) { Root<Player> player = cq.from(Player.class); Join<Player, Team> team = player.join(Player_.teams); Join<Team, League> league = team.join(Team_.league); // Get MetaModel from Root //EntityType<Player> Player_ = player.getModel(); // set the where clause cq.where( cb.equal( player.get(Player_.id), playerId)); cq.select(league.get(League_.sport)) .distinct(true); TypedQuery<String> q = em.createQuery(cq); sports = q.getResultList(); } // Player player = em.find(Player.class, playerId); // Iterator<Team> i = player.getTeams().iterator(); // while (i.hasNext()) { // Team team = i.next(); // League league = team.getLeague(); // sports.add(league.getSport()); // } } catch (Exception ex) { throw new EJBException(ex); } return sports; } ... } |
2. Generated Metamodel classes

Summary
In this exercise, you have explored the "roster" sample application that comes with Java EE 6 tutorial.
Homework Exercise
- Exercise point: Mapping with @ElementCollection
- School entity class have schoolname field, which is String type, and district field, which is District class. See a snippet of the School class below.
| ... @Entity public class School implements Serializable { @Id @GeneratedValue @Column(name = "SCHOOL_ID") private int id; private String schoolname; private District district; |
- The District class is Embeddable type and has a set of Student's. It also has districtname field, which is String type. See a snippet of District class below.
| ... @Embeddable public class District implements Serializable{ private String districtname; @OneToMany(cascade=CascadeType.ALL, mappedBy="school") private Set<Student> students; ... |
- The Student class is an entity class and has studentname field, which is String type, and grade field, which is double type. See a snippet of Student class below.
| ... @Entity @Table(name = "STUDENT_TABLE") public class Student implements Serializable { @Id @Column(name = "STUDENT_ID") @GeneratedValue private int id; private String studentname; private double grade; // Bi-directional one-to-many relationship @ManyToOne(optional = true) private School school; ... |
- In the Main.java, as samples, add at least 3 schools. Each district of corresponding school has at least 2 students.
- Exercise point: Criteria API
- In the Main.java, perform both JPQL and Criteria API as following. Metamodel class does not have to be used.
- Get all schools who have students whose grade is 3.0 or above
- Zip file of the the my_jpa2.0 NetBeans project. (Someone else should be able to open and run it as a NetBeans project.) You can use your favorite zip utility or you can use "jar" utility that comes with JDK as following.
- cd <parent directory that contains my_jpa2.0 directory> (assuming you named your project as my_jpa2.0)
- jar cvf my_jpa2.0.zip my_jpa2.0 (my_jpa2.0 should contain nbproject directory)
- Captured output screen - name it as homework_javaee6_jpa2.0.gif or homework_javaee6_jpa2.0.jpg (or homework_javaee6_jpa2.0.<whatever graphics format>)
- Any screen capture that shows that your program is working is good enough.
'BOOK Study > J2EE' 카테고리의 다른 글
| 세번째 자바 이야기 - Professional Java Sservlets 2.3 (0) | 2010/01/25 |
|---|---|
| 06. Java EE 6 - EJB 3.1 (0) | 2010/01/17 |
| 05. Java EE 6 - JPA 2.0 (0) | 2010/01/16 |
| 04. Java EE 6: DI (JSR 330) and CDI (JSR 299) (0) | 2010/01/14 |
| 02. Servlet 3.0 (0) | 2010/01/12 |
| 01. Java EE 6 Overrview & Getting Java EE 6 sample codes (0) | 2010/01/11 |
- 04. Java EE 6: DI (JSR 330) and CDI (JSR 299)
- BOOK Study/J2EE
- 2010/01/14 10:40
- Posted by 들기름왕자
Lab Exercises
For the sake of the simplicity of the lab, most exercises are provided in the form of "ready-to-open-and-run" NetBeans projects. (Many of them are borrowed from "glassfish-samples" and "Java EE 6 tutorial".) Please feel free to create them from scratch if you want to.
It is strongly encouraged, leveraging what is provided in this lab, you do your own experimentation meaning creating/adding your own code as much as you can.
If you have written some code that might help everyone else, please feel free to share them on this codecamp email alias or directly send them to the instructors. Your name will be recognized in this lab if your sample code is chosen to be included. For the tasks that need to be done, please see the "Things to be done" section above.)
- Exercise 1: @Inject simple usages (20 minutes)
- Exercise 2: @Inject with @Qualifier (20 minutes)
- Exercise 3: Scope (20 minutes)
- Exercise 4: Producer method (20 minutes)
- Exercise 5: ManagedBean with lifecycle methods (20 minutes)
- Exercise 6: Build and run "weld-servlet" sample application (20 minutes)
- Exercise 7: Build and run "weld-guess" sample application (20 minutes)
- Exercise 8: Event (20 minutes)
- Homework Exercise
Before you start this lab, you have to get sample applications from "glassfish-samples" and "Java EE tutorial" as described in LAB-4530: Java EE 6 - Examples.Exercise 1: @Inject simple usages
더보기
The container injects references to contextual instances to the following kinds of injection point:
- Any injected field of a bean class
- Any parameter of a bean constructor, initializer method, producer method or disposer method
- Any parameter of an observer method, except for the event parameter
- Inject a bean to a field: "inject_bean_to_field" sample application
- Study the code
- Inject a bean via constructor method: "inject_bean_via_constructor" sample application
- Study the code
- Inject a bean via init method: "inject_bean_via_init" sample application
- Study the code
- Inject a bean to a field: "inject_bean_to_field_using_interface" sample application
- Study the code
- Inject an EJB to a field: "inject_ejb_to_field" sample application
- Study the code
(1.1) Inject a bean to a field: "inject_bean_to_field" sample application
1. Open inject_bean_to_field NetBeans project (from "Lab samples")
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Windows: If you unzipped the 4531_javaee6_injection.zip file under C:\ directory, the directory to which you want to browse down should be C:\javaee6_injection\samples.
- Solaris/Linux/Mac: If you unzipped the 4531_javaee6_injection.zip file under $HOME directory, the directory to which you want to browse down should be $HOME/javaee6_injection/samples.
- Select inject_bean_to_field.
- Click Open Project.
- Observe that the inject_bean_to_field project node appears under Projects tab window.
2. Build and run inject_bean_to_field project.
- Right-click inject_bean_to_field project and select Run.
- Observe that the browser gets displayed.

Figure-1.11
(1.2) Study the code of the project
| package mypackage; import java.io.IOException; import java.io.PrintWriter; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="HelloServlet", urlPatterns={"/HelloServlet"}) public class HelloServlet extends HttpServlet { // You need an empty beans.xml in the WEB-INF directory to enable Weld // Inject Greeting object @Inject Greeting greeting; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // out.println("<html>"); out.println("<head>"); out.println("<title>Servlet HelloServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Calling a method of an injected class: " + greeting.greet("Codecamper!") + "</h1>"); out.println("</body>"); out.println("</html>"); // } finally { out.close(); } } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; }// </editor-fold> } |
- Display context senstive Javadoc on @Inject.

Figure-1.21

Figure-1.22
2. Study Greeting.java.
| package mypackage; public class Greeting { public String greet(String name){ return "Hello " + name; } } |
3. Study beans.xml.
An application that uses CDI must have a file named beans.xml. The file can be completely empty (it has content only in certain limited situations), but it must be present. For a web application, the beans.xml file can be in either the WEB-INF directory or the WEB-INF/classes/META-INF directory. For EJB modules or JAR files, the beans.xml file must be in the META-INF directory.
| <?xml version="1.0" encoding="UTF-8"?> <beans/> |

Figure-1.21
(1.3) Inject a bean via constructor method: "inject_bean_via_constructor" sample application
1. Open inject_bean_via_constructor NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select inject_bean_via_constructor.
- Click Open Project.
- Observe that the inject_bean_via_constructor project node appears under Projects tab window.
2. Build and run inject_bean_via_constructor project.
- Right-click inject_bean_via_constructor project and select Run.
- Observe that the browser gets displayed.

Figure-1.31
(1.4) Study code
1. HelloServlet.java
| package mypackage; import java.io.IOException; import java.io.PrintWriter; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="HelloServlet", urlPatterns={"/HelloServlet"}) public class HelloServlet extends HttpServlet { private Greeting greeting; // Use constructor method injection @Inject void HelloServlet(Greeting greeting){ this.greeting = greeting; } /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // out.println("<html>"); out.println("<head>"); out.println("<title>Servlet HelloServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Calling a method of an injected class: " + greeting.greet("Codecamper!") + "</h1>"); out.println("</body>"); out.println("</html>"); // } finally { out.close(); } } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; }// </editor-fold> } |
(1.5) Inject a bean via init method: "inject_bean_via_init" sample application
1. Open inject_bean_via_init NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select inject_bean_via_init.
- Click Open Project.
- Observe that the inject_bean_via_init project node appears under Projects tab window.
2. Build and run inject_bean_via_init project.
- Right-click inject_bean_via_init project and select Run.
- Observe that the browser gets displayed.

Figure-1.51
(1.6) Study code
1. Study the code - HelloServlet.java.
| package mypackage; import java.io.IOException; import java.io.PrintWriter; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="HelloServlet", urlPatterns={"/HelloServlet"}) public class HelloServlet extends HttpServlet { private Greeting greeting; // Use initializer method injection @Inject void init(Greeting greeting){ this.greeting = greeting; } /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // out.println("<html>"); out.println("<head>"); out.println("<title>Servlet HelloServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Calling a method of an injected class: " + greeting.greet("Codecamper!") + "</h1>"); out.println("</body>"); out.println("</html>"); // } finally { out.close(); } } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; }// </editor-fold> } |
(1.7) Inject a bean to a field: "inject_bean_to_field_using_interface" sample application
In this exercise, you are going to inject a bean whose type is a Java interface.
1. Open inject_bean_to_field_using_interface NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select inject_bean_to_field_using_interface.
- Click Open Project.
- Observe that the inject_bean_to_field_using_interface project node appears under Projects tab window.
2. Build and run inject_bean_to_field_using_interface project.
- Right-click inject_bean_to_field_using_interface project and select Run.
- Observe that the browser gets displayed.

Figure-1.71
(1.8) Study code
1. GreetingInterface.java
| package mypackage; public interface GreetingInterface { public String greet(String name); } |
2. FormalGreeting.java
| package mypackage; public class FormalGreeting implements GreetingInterface { public String greet(String name){ return "Formal Hello " + name; } } |
3. HelloServlet.java
| package mypackage; import java.io.IOException; import java.io.PrintWriter; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="HelloServlet", urlPatterns={"/HelloServlet"}) public class HelloServlet extends HttpServlet { // You need an empty beans.xml in the WEB-INF directory to enable Weld // Inject GreetingInterface object @Inject GreetingInterface greeting; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // out.println("<html>"); out.println("<head>"); out.println("<title>Servlet HelloServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Calling a method of an injected class: " + greeting.greet("Codecamper!") + "</h1>"); out.println("</body>"); out.println("</html>"); // } finally { out.close(); } } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; }// </editor-fold> } |
(1.9) Inject an EJB to a field: "inject_ejb_to_field" sample application
In this exercise, you are going to inject EJB object (instead of regular bean) into a field. Given that you can inject an EJB through @Inject, you might have a question - "Is there any reason to use @Inject or @EJB when injecting EJB?" The answer from Ken Saks (EJB 3.1 spec lead) is as following:
"Yes, @EJB provides a static mapping to the target EJB component based on Java type and any specific linking metadata like beanName() or lookup(). The result of the injection is the actual EJB reference. (Note that this is still distinct from a
target bean *instance*)
@Inject adds an additional level of indirection by way of CDI, where the target EJB component is resolved via CDI's type-safe resolution algorithm. The result of injection is a CDI object that has an internal run-time mapping to a particular EJB reference. This allows whatever CDI scope is in context at the time of invocation to determine the target EJB reference.
Basically, if you want the additional CDI semantics to apply, use @Inject. Otherwise, use @EJB."
1. Open inject_ejb_to_field NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select inject_ejb_to_field.
- Click Open Project.
- Observe that the inject_ejb_to_field project node appears under Projects tab window.
2. Build and run inject_ejb_to_field project.
- Right-click inject_ejb_to_field project and select Run.
- Observe that the browser gets displayed.

Figure-1.91
(1.10) Study code
1. Greeting.java. Greeting is a stateless EJB.
| package mypackage; import javax.ejb.Stateless; @Stateless public class Greeting { public String greet(String name){ return "Hello " + name; } } |
Summary
In this exercise, you have learned how to inject a bean to a field, through constructor and init methods through @Inject annotation. You also learned how to inject EJB through @EJB annotation.
Exercise 2: @Inject usage with @Qualifier
더보기
For a given bean type, there may be multiple beans which implement the type. You can use qualifiers to provide different implementations of a particular bean type. A qualifier is an annotation that you apply to a bean. A qualifier type is a Java annotation defined as @Target({METHOD, FIELD, PARAMETER, TYPE}) and @Retention(RUNTIME).
(2.1) Experience "ambiguity" error condition
In this step, you are going to add InformalGreeting class which implements GreetingInterface to the inject_bean_to_field_using_interface project. In other words, there are two classes, FormalGreeting and InformalGreeting classes which implement GreetingInterface interface. This will cause ambiguity error condition.
1. Add InformalGreeting.java. InformalGreeting class is added as the second class that implements GreetingInterface interface.

Figure-2.11

Figure-2.12
3. Modify the IDE generated InformalGreeting.java with the code below. Note that InformalGreeting implements GreetingInterface.
| package mypackage; public class InformalGreeting implements GreetingInterface { public String greet(String name){ return "Informal Hello " + name; } } |
4. Build and run and observe error condition.
- Right click the project and select Run.
- Observe the AmbiguousResolutionException occurred as expected.

Figure-2.13
Note: The completed version of this step is available as inject_qualifier_ambiguitycase project under <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory. You can just build and run it to see the above result.
(2.2) User qualifier
In this step, you are going to define @Formal and @Informal qualifier types and apply them to FormalGreeting and InformalGreeting classes, which are the implementations of the GreetingInterface interface.
If you define a bean with no qualifier, it automatically has the qualifier @Default.
1. Add @Formal qualifier definition. This is a marker interface that does not require a processor action. If you are not sure how to define an annotation, please study Java Annotaiton.
| package mypackage; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RUNTIME) @Target({ TYPE, METHOD, FIELD, PARAMETER }) public @interface Formal { } |
2. Add @Informal qualifier definition.
| package mypackage; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RUNTIME) @Target({ TYPE, METHOD, FIELD, PARAMETER }) public @interface Informal { } |
3. Modify FormalGreeting class to get annotated with @Formal qualifier.
| package mypackage; @Formal public class FormalGreeting implements GreetingInterface { public String greet(String name){ return "Formal Hello " + name; } } |
4. Modify InformalGreeting class to get annotated with @Informal qualifier.
| package mypackage; @Informal public class InformalGreeting implements GreetingInterface { public String greet(String name){ return "Informal Hello " + name; } } |
5. Modify HelloServlet class to inject the Formal qualified type of the GreetingInterface
| package mypackage; import java.io.IOException; import java.io.PrintWriter; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="HelloServlet", urlPatterns={"/HelloServlet"}) public class HelloServlet extends HttpServlet { // You need an empty beans.xml in the WEB-INF directory to enable Weld // Inject GreetingInterface object using qualifier @Inject @Formal GreetingInterface greeting; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // out.println("<html>"); out.println("<head>"); out.println("<title>Servlet HelloServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Calling a method of an injected class: " + greeting.greet("Codecamper!") + "</h1>"); out.println("</body>"); out.println("</html>"); // } finally { out.close(); } } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; }// </editor-fold> } |
6. Run the project.

Figure-2.21
Solution: The completed version is available as inject_qualifier project under <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory. You can just build and run it to see the above result.
Summary
In this exercise, you have learned how to use qualifier when there are multiple implementations of a particular bean type.
Exercise 3: Scope
더보기
- @RequestScoped
- A user's interaction with a web application in a single HTTP request
- @SessionScoped
- A user's interaction with a web application across multiple HTTP requests
- @ApplicationScoped
- Shared state across all users' interactions with a web application
- @Dependent
- The default scope if none is specified; it means that an object exists to serve exactly one client (bean), and has the same lifecycle as that client (bean)
- @ConversationScoped
- A user's interaction with a JavaServer Faces application, within explicit boundaries controlled by the developer that extend the scope across multiple invocations of the JavaServer Faces life cycle. All long-running conversations are scoped to a particular HTTP servlet session and may not cross session boundaries.
(3.1) Use @RequestScoped
In this exercise, you are going to see a bean - Printer bean - whose scope is defined with @RequestScoped annotation.
1. Open inject_scope_request NetBeans project (from "Lab samples")
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select inject_scope_request.
- Click Open Project.
- Observe that the inject_scope_request project node appears under Projects tab window.
2. Build and run inject_scope_request project.
- Right-click inject_scope_request project and select Run.
- Observe that the browser gets displayed.
- For the Enter your name field, enter <your name>.
- Click Say Hello button.

Figure-3.11

Figure-3.12
(3.2) Study the code
| <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"> <ui:composition template="/template.xhtml"> <ui:define name="title">Simple Greeting</ui:define> <ui:define name="head">Simple Greeting</ui:define> <ui:define name="content"> <h:form id="greetme"> <p><h:outputLabel value="Enter your name: " for="name"/> <h:inputText id="name" value="#{printer.name}"/></p> <p><h:commandButton value="Say Hello" action="#{printer.createSalutation}"/></p> <p><h:outputText value="printer.salutation = #{printer.salutation}"/> </p> </h:form> </ui:define> </ui:composition> </html> |
2. Printer.java.
| import javax.inject.Inject; import javax.enterprise.context.RequestScoped; import javax.inject.Named; @Named @RequestScoped public class Printer { @Inject @Informal Greeting greeting; private String name; private String salutation = "nothing yet!"; public void createSalutation() { this.salutation = greeting.greet(name); } public String getSalutation() { return salutation; } public void setName(String name) { this.name = name; } public String getName() { return name; } } |
(3.3) Use @ConversationScoped
1. Open inject_scope_conversation NetBeans project (from "Lab samples")
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select inject_scope_conversation.
- Click Open Project.
- Observe that the inject_scope_conversation project node appears under Projects tab window.
2. Build and run inject_scope_conversation project.
- Right-click inject_scope_conversation project and select Run.
- Observe that the browser gets displayed.

Figure-3.31

Figure-3.32

Figure-3.33

Figure-3.34
4. Run the application in Conversation scope.
- Click Start Conversation button. This will start the conversation scope.

Figure-3.35
- Observe that the conversation scope is on.

Figure-3.36
- For the Enter your name field, enter a name.
- Click Say Hello button.

Figure-3.37

Figure-3.38

Figure-3.39

Figure-3.40
5. Turn off the conversation.

Figure-3.41

Figure-3.42

Figure-3.43

Figure-3.44
(3.4) Study code
1. index.html
| <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"> <ui:composition template="/template.xhtml"> <ui:define name="title">Simple Greeting</ui:define> <ui:define name="head">Simple Greeting</ui:define> <ui:define name="content"> <h:form id="greetme"> <p><h:outputLabel value="Enter your name: " for="name"/> <h:inputText id="name" value="#{printer.name}"/></p> <p><h:commandButton value="Say Hello" action="#{printer.createSalutation}"/></p> <p><h:commandButton value="Start conversation" action="#{printer.startConversation}"/></p> <p><h:commandButton value="End conversation" action="#{printer.endConversation}"/></p> <p><h:outputText value="printer.salutation = #{printer.salutation}"/> </p> <p><h:outputText value="printer.old_salutation = #{printer.old_salutation}"/> </p> <p><h:outputText value="myConversationStatus.conversationSattus = #{myConversationStatus.conversationSattus}"/> </p> </h:form> </ui:define> </ui:composition> </html> |
2. Printer.java
| package greetings; import java.io.Serializable; import javax.enterprise.context.Conversation; import javax.enterprise.context.ConversationScoped; import javax.inject.Inject; import javax.inject.Named; @Named @ConversationScoped public class Printer implements Serializable { @Inject @Informal Greeting greeting; @Inject Conversation conversation; @Inject MyConversationStatus cstatus; private String name; private String salutation = "nothing yet!"; private String old_salutation = "nothing yet!"; public void startConversation() { cstatus.setConversationSattus("on"); conversation.begin(); } public void endConversation() { cstatus.setConversationSattus("off"); conversation.end(); } public void createSalutation() { this.old_salutation = salutation; this.salutation = greeting.greet(name); } public String getSalutation() { return salutation; } public void setName(String name) { this.name = name; } public String getName() { return name; } /** * @return the old_salutation */ public String getOld_salutation() { return old_salutation; } /** * @param old_salutation the old_salutation to set */ public void setOld_salutation(String old_salutation) { this.old_salutation = old_salutation; } } |
Summary
In this exercise, you have learned, for a web application to use a bean that injects another bean class, how to use scope for holding state over the duration of the user's interaction with the application.
Exercise 4: Producer Methods
더보기
Producer methods provide a way to inject objects that are not beans, objects whose values may vary at run time, and objects that require custom initialization.
(4.1) Open, build, and run "inject_producer_businesslogic" sample application
1. Open inject_producer_businesslogic NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select inject_producer_businesslogic.
- Click Open Project.
- Observe that the inject_producer_businesslogic project node appears under Projects tab window.
2. Build and run inject_producer_businesslogic project.
- Right-click inject_producer_businesslogic project and select Run.
- Observe that the browser gets displayed.

Figure-4.11
(4.2) Study code
1. HelloServlet.java
| package mypackage; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "HelloServlet", urlPatterns = {"/HelloServlet"}) public class HelloServlet extends HttpServlet { @Inject @Formal String greetingMessage; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // out.println("<html>"); out.println("<head>"); out.println("<title>Servlet HelloServlet</title>"); out.println("</head>"); out.println("<body>"); //out.println("<h1>Calling a method of an injected class: " + greeting.greet("Codecamper!") + "</h1>"); out.println("<h1>" + new Date() + ": " + greetingMessage + "</h1>"); out.println("</body>"); out.println("</html>"); // } finally { out.close(); } } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; }// </editor-fold> } |
2. FormalGreeting.java. Note that the @Formal annotation is used not with the FormalGreeting class but with the getFormalGreeting() method, in which you can produce and return an object of @Formal type.
| package mypackage; import java.util.Calendar; import java.util.GregorianCalendar; import javax.enterprise.inject.Produces; public class FormalGreeting { String formalGreeting; // Produces greeting message based on business logic. @Produces @Formal public String getFormalGreeting() { GregorianCalendar todaysDate = new GregorianCalendar(); int hour_of_day = todaysDate.get(Calendar.HOUR_OF_DAY); if (hour_of_day < 12) { formalGreeting = "Good morning!"; } if (hour_of_day > 11 && hour_of_day < 17) { formalGreeting = "Good afternoon!"; } if (hour_of_day >= 17 && hour_of_day < 22) { formalGreeting = "Good evening!"; } if (hour_of_day >= 22) { formalGreeting = "Good night!"; } return formalGreeting; } } |
Summary
In this exercise, you have learned how to provide a way to inject objects whose values may vary at run time based on business logic through @Produces annotation.
Exercise 5: Managed Bean with Lifecycle methods
더보기
The ManagedBean annotation marks a POJO (Plain Old Java Object) as a ManagedBean. A ManagedBean supports a small set of basic services such as resource injection, lifecycle callbacks and interceptors.
- Open, build, and run "managedbean_lifecycle_defaultscope" sample application
- Study the code
- Open, build, and run "managedbean_lifecycle_requestscope" sample application
- Study the code
- Open, build, and run "managedbean_interceptor" sample application
- Study the code
(5.1) Open, build, and run "managedbean_lifecycle_defaultscope" sample application (from "Lab samples")
1. Open managedbean_lifecycle_defaultscope NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select managedbean_lifecycle_defaultscope.
- Click Open Project.
- Observe that the managedbean_lifecycle_defaultscope project node appears under Projects tab window.
2. Build and run managedbean_lifecycle_defaultscope project.
- Right-click managedbean_lifecycle_defaultscope project and select Run.
- Observe that the browser gets displayed.

Figure-5.11

Figure-5.12

Figure-5.13

Figure-5.14
(5.2) Study code
1. Greeting.java
| package mypackage; import javax.annotation.ManagedBean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @ManagedBean public class Greeting { public String greet(String name) { return "Hello " + name; } @PostConstruct private void init() { System.out.println("\n=======> init() method is called as PostConstruct"); } @PreDestroy private void release() { System.out.println("=======> release() method is called as PreDestroy"); } } |
(5.3) Open, build, and run "managedbean_lifecycle_requestscope" sample application
1. Open managedbean_lifecycle_requestscope NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select managedbean_lifecycle_requestscope.
- Click Open Project.
- Observe that the managedbean_lifecycle_requestscope project node appears under Projects tab window.
2. Build and run managedbean_lifecycle_requestscope project.
- Right-click managedbean_lifecycle_requestscope project and select Run.
- Observe that the browser gets displayed.

Figure-5.31
(5.4) Study code
| package mypackage; import javax.annotation.ManagedBean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.RequestScoped; @ManagedBean @RequestScoped public class Greeting { public String greet(String name) { return "Hello " + name; } @PostConstruct private void init() { System.out.println("\n=======> init() method is called as PostConstruct"); } @PreDestroy private void release() { System.out.println("=======> release() method is called as PreDestroy"); } } |
(5.5) Open, build, and run "managedbean_interceptor" sample application
1. Open managedbean_interceptor NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select managedbean_interceptor.
- Click Open Project.
- Observe that the managedbean_interceptor project node appears under Projects tab window.
2. Build and run managedbean_interceptor project.
- Right-click managedbean_interceptor project and select Run.
- Observe that the browser gets displayed.

Figure-5.51
(5.6) Study code
1. Greeting.java
| package mypackage; import javax.annotation.ManagedBean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.RequestScoped; import javax.interceptor.Interceptors; @ManagedBean @RequestScoped @Interceptors(LoggingInterceptor.class) public class Greeting { public String greet(String name) { return "Hello " + name; } @PostConstruct private void init() { System.out.println("\n=======> init() method is called as PostConstruct"); } @PreDestroy private void release() { System.out.println("=======> release() method is called as PreDestroy"); } } |
2. LoggingInterceptor.java
| package mypackage; import java.util.logging.Logger; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; // This class will be used as an interceptor. public class LoggingInterceptor { private Logger logger = Logger.getLogger("mypackage"); @AroundInvoke public Object logMethod(InvocationContext ic) throws Exception { logger.info("------> " + ic.getTarget().getClass() + ", method name: " + ic.getMethod().getName()); try { return ic.proceed(); } finally { logger.info("<------ " + ic.getTarget().getClass() + ", method name: " + ic.getMethod().getName()); } } } |
Summary
In this exercise, you have learned how to use managed bean with lifecycle methods. You also leraned how to use interceptor with a managed bean.
Exercise 6: Build and run "weld-servlet" sample application
더보기
The "weld-servlet" sample application is provided as a sample application from "glassfish-samples". The description of this sample application is available from "Context and Dependency Injection And Servlets" blog by Roger Kitain.
(6.1) Open, build, and run "weld-servlet" sample application (from "glassfish-samples")
1. Open weld-servlet NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/samples/javaee6/weld directory.
- Select weld-servlet.
- Click Open Project.

Figure-6.11
- Observe that the weld-servlet project node appears under Projects tab window.
2. Build and run weld-servlet project.
- Right-click weld-servlet project and select Run.
- Observe that the browser gets displayed.
- For the User Name field, enter <your name>.
- For the Password field, enter whatever password of your choice.
- Click Submit button.

Figure-6.12
- Observe that "Successfully Logged In As: <your name>" message gets displayed at the bottom.

Figure-6.13
(6.2) Study the code
1. web.xml
| <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> |
2. index.jsp
| <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Weld Servlet Injection</title> <script type="text/javascript" src="resources/ajax.js"> </script> <link type="text/css" rel="stylesheet" href="/weld-servlet/resources/stylesheet.css" /> </head> <body> <form name="myForm" method="POST" action="LoginServlet"> <table class="title-panel"> <tbody> <tr> <td><span class="title-panel-text">Login Servlet</span></td> </tr> <tr> <td><span class="title-panel-subtext">Powered By Servlet 3.0 and Weld</span></td> </tr> </tbody> </table> <table height="30" style="font-size: 16px"> <tr> <td>Enter any value for user name and password.</td> </tr> </table> <table style="font-size: 16px"> <tr> <td style="color:red">*</td> <td>Denotes required entry.</td> </tr> </table> <table height="30"> <table border="1" style="font-size: 18px"> <tr> <td>User Name:</td> <td><input type="text" name="username" id="username" /></td> <td style="color:red">*</td> </tr> <tr> <td>Password:</td> <td><input type="password" name="password" id="password" /></td> <td style="color:red">*</td> </tr> </table> <table border="1"> <tr> <td colspan="2"><input type="button" value="Submit" onclick="ajaxFunction();" /></td> <td colspan="2"><input type="button" value="Reset" onclick="resetFunction();" /></td> </tr> </table> </table> <table height="20"> <tr> <td><div id="message" style="color:red;font-size: 14px"></td> </tr> </table> </form> </body> </html> |
3. LoginServlet.java
| package weldservlet; import java.io.IOException; import java.io.PrintWriter; import javax.enterprise.inject.spi.BeanManager; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * This Servlet class demonstrates Weld injection. */ @WebServlet(name="LoginServlet", urlPatterns={"/LoginServlet"}) public class LoginServlet extends HttpServlet { // BeanManager interface allows a portable extension to interact directly with // the container. Provides operations for obtaining contextual references for // beans, along with many other operations of use to portable extensions. // It is not used in this application. // Inject Weld Bean Manager. @Inject BeanManager m; // Inject The Credentials Weld bean. @Inject Credentials credentials; // Inject the Login Weld bean. @Inject Login login; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); // Because credentials variable is injected with Credentials object by the container, // you can use it here without yourself assigning it. credentials.setUsername(request.getParameter("username")); credentials.setPassword(request.getParameter("password")); // Because login variable is injected with Login object by the container, // you can use it here without yourself assigning it. login.login(); try { if (login.isLoggedIn()) { out.println("Successfully Logged In As: " + credentials.getUsername()); } else { out.println("Login Failed: Check username and/or password."); } } finally { out.close(); } } /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; } } |
4. Credentials.java.
| package weldservlet; import java.io.Serializable; import javax.enterprise.context.RequestScoped; import javax.enterprise.inject.Default; import javax.inject.Named; /** * This is just a simple container class Weld bean for the username * and password entry values. */ @Named @RequestScoped @Default public class Credentials implements Serializable { private String username = null; private String password = null; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } |
5. Login.java.
| package weldservlet; import java.io.Serializable; import javax.enterprise.context.SessionScoped; import javax.enterprise.inject.Default; import javax.inject.Inject; import javax.inject.Named; /** * A simple Weld Bean that performs a login operation with user's * credentials. */ @Named @SessionScoped @Default public class Login implements Serializable { // Credential object is already initialized with // username and password input parameters // is placed in the request scope object. @Inject Credentials credentials; private boolean loggedIn = false; /** * This is where you could potentially access a database. */ public void login() { if ((credentials.getUsername() != null && credentials.getUsername().trim().length() > 0) && (credentials.getPassword() != null && credentials.getPassword().trim().length() > 0)) { loggedIn = true; } } public boolean isLoggedIn() { return loggedIn; } } |
Summary
In this exercise, you have played with a sample application that uses dependency injection.
Exercise 7: Build and run "weld-guess" sample application
더보기
The description of of this example is provided as part of Java EE 6 tutorial.
(7.1) Open, build, and run "weld-guess" sample application (from "glassfish-samples")
1. Open weld-guess NetBeans project.
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <GlassFish-v3-Installation-Directory>/glassfish/samples/javaee6/weld directory.
- Select weld-guess.
- Click Open Project.
- Observe that the weld-guess project node appears under Projects tab window.
2. Build and run weld-guess project.
- Right-click weld-guess project and select Run.
- Browser gets displayed.

Figure-7.11

Figure-7.12

Figure-7.13
(7.2) Study the code
| <html> <head> <meta http-equiv="Refresh" content="0; URL=home.jsf"> </head> </html> |
2. home.xhtml
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>JSF 2.0 Weld Example</title> </h:head> <h:body> <h:form id="NumberGuessMain"> <h:panelGrid styleClass="title-panel"> <h:outputText value="Guess Number" styleClass="title-panel-text"/> <h:outputText value="Powered By JavaServer Faces 2.0 and Weld" styleClass="title-panel-subtext"/> </h:panelGrid> <div style="color: black; font-size: 24px;"> I'm thinking of a number between <span style="color: blue">#{game.smallest}</span> and <span style="color: blue">#{game.biggest}</span>. You have <span style="color: blue">#{game.remainingGuesses}</span> guesses. </div> <h:panelGrid border="1" columns="5" style="font-size: 18px;"> Number: <h:inputText id="inputGuess" value="#{game.guess}" required="true" size="3" disabled="#{game.number eq game.guess}" validator="#{game.validateNumberRange}"> </h:inputText> <h:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/> <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" /> <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}" style="color: red"/> <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}" style="color: red"/> </h:panelGrid> <div style="color: red; font-size: 14px;"> <h:messages id="messages" globalOnly="false"/> </div> <h:outputStylesheet name="stylesheet.css" /> </h:form> </h:body> </html> |
3. Game.java.
| package weldguess; import java.io.Serializable; import javax.annotation.PostConstruct; import javax.enterprise.context.SessionScoped; import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.inject.Named; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; @Named @SessionScoped public class Game implements Serializable { private static final long serialVersionUID = 1L; private int number; private int guess; private int smallest; // Inject an object which is qualified with // @MaxNumber qualifier. @MaxNumber @Inject private int maxNumber; private int biggest; private int remainingGuesses; // Inject an object which is qualified with // @Random qualifier. @Random @Inject Instance<Integer> randomNumber; public Game() { } public int getNumber() { return number; } public int getGuess() { return guess; } public void setGuess(int guess) { this.guess = guess; } public int getSmallest() { return smallest; } public int getBiggest() { return biggest; } public int getRemainingGuesses() { return remainingGuesses; } public String check() throws InterruptedException { if (guess>number) { biggest = guess - 1; } if (guess<number) { smallest = guess + 1; } if (guess == number) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!")); } remainingGuesses--; return null; } @PostConstruct public void reset() { this.smallest = 0; this.guess = 0; this.remainingGuesses = 10; this.biggest = maxNumber; this.number = randomNumber.get(); } public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) { if (remainingGuesses <= 0) { FacesMessage message = new FacesMessage("No guesses left!"); context.addMessage(toValidate.getClientId(context), message); ((UIInput)toValidate).setValid(false); return; } int input = (Integer) value; if (input < smallest || input > biggest) { ((UIInput)toValidate).setValid(false); FacesMessage message = new FacesMessage("Invalid guess"); context.addMessage(toValidate.getClientId(context), message); } } } |
4. Generator.java.
| package weldguess; import java.io.Serializable; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; @ApplicationScoped public class Generator implements Serializable { private static final long serialVersionUID = -7213673465118041882L; private java.util.Random random = new java.util.Random( System.currentTimeMillis() ); private int maxNumber = 100; java.util.Random getRandom() { return random; } @Produces @Random int next() { return getRandom().nextInt(maxNumber); } @Produces @MaxNumber int getMaxNumber() { return maxNumber; } } |
5. MaxNumber.java.
| package weldguess; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; // Define @MaxNumber qualifier annotation @Target( { TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface MaxNumber { } |
6. Random.java.
| package weldguess; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; // Define @Random qualifier annotation @Target( { TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface Random { } |
Summary
In this exercise, you have played with a sample application that uses dependency injection.
Exercise 8: Event
더보기
Beans may produce and consume events. This facility allows beans to interact in a completely decoupled fashion, with no
compile-time dependency between the interacting beans. Most importantly, it allows stateful beans in one architectural tier
of the application to synchronize their internal state with state changes that occur in a different tier.
An event comprises:
- A Java object—the event object
- A (possibly empty) set of instances of qualifier types—the event qualifiers
The event object acts as a payload, to propagate state from producer to consumer. The event qualifiers act as topic selectors,
allowing the consumer to narrow the set of events it observes.
An observer method acts as event consumer, observing events of a specific type—the observed event type—with a specific
set of qualifiers—the observed event qualifiers. An observer method will be notified of an event if the event object is assignable
to the observed event type, and if all the observed event qualifiers are event qualifiers of the event.
- Open, build, and run "weld-servlet-event" sample application
- Study the code
- Add more event handlers
- Fire @Admin qualified event
(8.1) Open, build, and run "weld-servlet-event" sample application
1. Open weld-servlet-event NetBeans project (from "Lab samples").
- Select File->Open Project (Ctrl+Shift+O).
- Observe that the Open Project dialog box appears.
- Browse down to <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/samples directory.
- Select weld-servlet-event.
- Click Open Project.
- Observe that the weld-servlet-event project node appears under Projects tab window.
2. Build and run weld-servlet-event project.
- Right-click weld-servlet-event project and select Run.
- Browser gets displayed.
- For the User Name field, enter sangshin (or whatever user name of your choce).
- For the Password field, enter whatever password of your choice.
- Click Submit button.

Figure-8.11
- Observe that "Successfully Logged In As: <your user name>" message gets displayed at the bottom.

Figure-8.12
3. Observe that the event handler is invoked.
- Click GlassFish v3 Domain tab under Outout window.
- Observe that "INFO: ----afterLogin() method is called, .." message is displayed.

Figure-8.13
(8.2) Study code
| package weldservlet; import java.io.Serializable; import javax.enterprise.context.SessionScoped; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; import javax.inject.Inject; import javax.inject.Named; /** * A simple Weld Bean that performs a login operation with user's * credentials. */ @Named @SessionScoped @Default public class Login implements Serializable { @Inject Credentials credentials; // Inject LoggedEvent @Inject @Any Event<LoggedInEvent> loggedInEvent; private boolean loggedIn = false; /** * This is where you could potentially access a database. */ public void login() { if ((credentials.getUsername() != null && credentials.getUsername().trim().length() > 0) && (credentials.getPassword() != null && credentials.getPassword().trim().length() > 0)) { loggedIn = true; // Fire an event when successful login loggedInEvent.fire(new LoggedInEvent(credentials.getUsername())); } } public boolean isLoggedIn() { return loggedIn; } // This methog gets invoked when LoggedInEvent is fired public void afterLogin(@Observes LoggedInEvent event) { System.out.println("----afterLogin() method is called, event = " + event); } } |
2. LoggedInEvent.java
| package weldservlet; public class LoggedInEvent { private String user; public LoggedInEvent(String user) { this.user = user; } } |
(8.3) Add more event handlers
1. Add Admin.java. This is to define @Admin qualifier marker annotation.
| package weldservlet; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; @Target( { TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface Admin { } |

Figure-8.31
2. Modify Login.java as shown below. The modification is to add two extra event handlers. The code fragments that need to be added are highlighted in bold and red-colored font.
| package weldservlet; import java.io.Serializable; import javax.enterprise.context.SessionScoped; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; import javax.inject.Inject; import javax.inject.Named; /** * A simple Weld Bean that performs a login operation with user's * credentials. */ @Named @SessionScoped @Default public class Login implements Serializable { @Inject Credentials credentials; // Inject LoggedEvent @Inject @Any Event<LoggedInEvent> loggedInEvent; private boolean loggedIn = false; /** * This is where you could potentially access a database. */ public void login() { if ((credentials.getUsername() != null && credentials.getUsername().trim().length() > 0) && (credentials.getPassword() != null && credentials.getPassword().trim().length() > 0)) { loggedIn = true; // Fire an event when successful login loggedInEvent.fire(new LoggedInEvent(credentials.getUsername())); } } public boolean isLoggedIn() { return loggedIn; } // This methog gets invoked when LoggedInEvent is fired public void afterLogin(@Observes LoggedInEvent event) { System.out.println("----afterLogin() method is called, event = " + event); } // Capture any event (same as above) public void afterAnyLogin(@Observes @Any LoggedInEvent event) { System.out.println("----afterAnyLogin() method is called, event = " + event); } // Capture only @Admin qualified event public void afterAdminLogin(@Observes @Admin LoggedInEvent event) { System.out.println("----afterAdminLogin() method is called, event = " + event); } } |

Figure-8.32
3. Build and run the application.
- Right-click weld-servlet-event-qualifier project and select Run.
- Browser gets displayed.
- For the User Name field, enter sangshin (or whatever user name of your choce).
- For the Password field, enter whatever password of your choice.
- Click Submit button.
- Observe that "Successfully Logged In As: <your user name>" message gets displayed at the bottom.
- Click GlassFish v3 Domain tab under Outout window.
- Observe that "INFO: ----afterLogin() method is called, .." message is displayed.
- Observe that "INFO: ----afterAnyLogin() method is called, .." message is displayed.

Figure-8.33
(8.4) Fire qualified event
1. Modify Login.java as shown below. The modification is to fire @Admin qualified event.
| package weldservlet; import java.io.Serializable; import javax.enterprise.context.SessionScoped; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; import javax.inject.Inject; import javax.inject.Named; /** * A simple Weld Bean that performs a login operation with user's * credentials. */ @Named @SessionScoped @Default public class Login implements Serializable { @Inject Credentials credentials; // Inject LoggedEvent @Inject @Admin Event<LoggedInEvent> loggedInEvent; private boolean loggedIn = false; /** * This is where you could potentially access a database. */ public void login() { if ((credentials.getUsername() != null && credentials.getUsername().trim().length() > 0) && (credentials.getPassword() != null && credentials.getPassword().trim().length() > 0)) { loggedIn = true; // Fire an event when successful login loggedInEvent.fire(new LoggedInEvent(credentials.getUsername())); } } public boolean isLoggedIn() { return loggedIn; } // This methog gets invoked when LoggedInEvent is fired public void afterLogin(@Observes LoggedInEvent event) { System.out.println("----afterLogin() method is called, event = " + event); } // Capture any event (same as above) public void afterAnyLogin(@Observes @Any LoggedInEvent event) { System.out.println("----afterAnyLogin() method is called, event = " + event); } // Capture only @Admin qualified event public void afterAdminLogin(@Observes @Admin LoggedInEvent event) { System.out.println("----afterAdminLogin() method is called, event = " + event); } } |
- Right-click weld-servlet-event-qualifier project and select Run.
- Browser gets displayed.
- For the User Name field, enter sangshin (or whatever user name of your choce).
- For the Password field, enter whatever password of your choice.
- Click Submit button.
- Observe that "Successfully Logged In As: <your user name>" message gets displayed at the bottom.
- Click GlassFish v3 Domain tab under Outout window.
- Observe that "INFO: ----afterAdminLogin() method is called, .." message is also displayed along with the other two. This shows that afterAdminLogin(@Observes @Admin LoggedInEvent event) event handler gets called only when @Admin qualified event is fired.

Figure-8.41
Solution: The solution up to this step is captured as "ready to open and build" NetBeans project as weld-servlet-event-qualifer project under <LAB_UNZIPPED_DIRECTORY>/javaee6_injection/solutions directory.
Summary
In this exercise, you have learned how beans may produce and consume events. You also learned how to use qualifer.
Homework Exercise
- Goal: Exercising qualifier
- Define another qualifier called @SemiFormal.
- Define SemiFormalGreeting class with @SemiFormal annotation
- Modify HelloServlet class to inject @SemiFormal greeting object.
- Goal: Exercising scope
- Create a bean called my_application_scope_bean with application scope, which has a field called my_application_scope_counter. Use the my_application_scope_counter to keep track of how many times the Say Hello button was clicked.
- Display the value of my_application_scope_counter.
- Create another bean called my_conversation_scope_bean with conversation scope, which has a field called my_conversation_scope_counter. Now every time my_application_scope_counter hits multiple of 5, for example, 5, 10, 15, ..., start a conversation. Every time my_application_scope_counter hits multiple of 5 plus 4, for example, 9, 14, 19, ..., stop the conversation.
- The my_conversation_scope_counter gets incremented each time the Say Hello button is clicked but starting from a new random number whenever a new coversation scope gets started.
- Display the value of my_conversation_scope_counter.
- Create a bean called my_application_scope_bean with application scope, which has a field called my_application_scope_counter. Use the my_application_scope_counter to keep track of how many times the Say Hello button was clicked.
- Goal: Exercising event handling
- Every time my_application_scope_bean hits the prime numbers up to 20, fire a event. The event handler should display a message "Prime number x is hit!". This message can be displayed either HTML response message or system log.
| <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"> <ui:composition template="/template.xhtml"> <ui:define name="title">Simple Greeting</ui:define> <ui:define name="head">Simple Greeting</ui:define> <ui:define name="content"> <h:form id="greetme"> <p><h:outputLabel value="Enter your name: " for="name"/> <h:inputText id="name" value="#{printer.name}"/></p> <p><h:commandButton value="Say Hello" action="#{printer.createSalutation}"/></p> <p><h:commandButton value="Start conversation" action="#{printer.startConversation}"/></p> <p><h:commandButton value="End conversation" action="#{printer.endConversation}"/></p> <p><h:outputText value="printer.salutation = #{printer.salutation}"/> </p> <p><h:outputText value="printer.old_salutation = #{printer.old_salutation}"/> </p> <p><h:outputText value="myConversationStatus.conversationSattus = #{myConversationStatus.conversationSattus}"/> </p> <p><h:outputText value="my_application_scope_bean.my_application_scope_counter = #{my_application_scope_bean.my_application_scope_counter}"/> </p> <p><h:outputText value="my_conversation_scope_bean.my_conversation_scope_counter = #{my_conversation_scope_bean.my_conversation_scope_counter}"/> </p> </h:form> </ui:define> </ui:composition> </html> |
- Zip files of the the my_inject_qualifier and my_inject_scope_conversation NetBeans projects. (Someone else should be able to open and run them as NetBeans projects.) You can use your favorite zip utility or you can use "jar" utility that comes with JDK as following.
- cd <parent directory that contains my_inject_qualifier directory> (assuming you named your project as my_inject_qualifier)
- jar cvf my_inject_qualifier.zip my_inject_qualifier (my_inject_qualifier should contain nbproject directory)
- cd <parent directory that contains my_inject_qualifier directory> (assuming you named your project as my_inject_qualifier)
- Captured output screens - name it as homework_javaee6_injection1.gif orhomework_javaee6_injection1.jpg (or homework_javaee6_injection1.<whatver graphics format>) for the first part and homework_javaee6_injection2.gif orhomework_javaee6_injection2.jpg (or homework_javaee6_injection2.<whatver graphics format>)
- Any screen capture that shows that your program is working is good enough.
'BOOK Study > J2EE' 카테고리의 다른 글
| 06. Java EE 6 - EJB 3.1 (0) | 2010/01/17 |
|---|---|
| 05. Java EE 6 - JPA 2.0 (0) | 2010/01/16 |
| 04. Java EE 6: DI (JSR 330) and CDI (JSR 299) (0) | 2010/01/14 |
| 02. Servlet 3.0 (0) | 2010/01/12 |
| 01. Java EE 6 Overrview & Getting Java EE 6 sample codes (0) | 2010/01/11 |
| [java ee programming] Java EE 6 "1-day" Online Codecamp (on Jan. 12th, 2010) (0) | 2010/01/04 |
- 02. 변수 part 02
- BOOK Study/C/C++
- 2010/01/13 22:28
- Posted by 들기름왕자
ㅇ 포인터 변수 복습
변수의 값을 바꾸는 방법에는 두가지가 있습니다.
첫번째는 변수 자체의 이름을 이용하는 방법
두번째는 변수가 할당된 주소를 이용하는 방법
ㅇ 포인터 맴버에 접근
struct BANK
{
int gender;
int nPhone;
bank.pBirth //1번
bank.gender //2번
1번 코드는 포인터 멤버에 접근할때 2번 코드는 값 맴버에 접근할때의 코드입니다.
bank.gender변수의 자료형은 gender 맴버의 자료형인 int가 됩니다. 그렇다면 bank.pBirth 변수의 자료형도 마찬기지로 pBirth맴버의 자료형인 int*가 됩니다.
struct Bank bank;
printf("%d %d %d", *bank.pBirth, bank.gender, bank.nPhone);
int nBirth = 0;
struct BANK bank = {NULL};
bank
pBirth ->0
gender -> 0
nPhone -> 0
nBirth -> 0
bank.pBirth = &nBirth;
bank
pBirth ->&nBirth
gender -> 0
nPhone -> 0
nBirth -> 0
scanf("%d", bank.pBirth);
bank
pBirth ->&nBirth
gender -> 1
nPhone -> 12345678
nBirth -> 1225
ㅇ 구조체 포인터 변수 입출력 예제
#incldue<stdio.h>
struct KITCHEN
{
char chSink;
int nTable;
int nGasRange;
};
int main()
{
struct KITCHEN* pKitchen = NULL;
struct KITCHEN kitchen ={'\0'};
pKitchen = &kitchen;
printf( "싱크대"); scanf(%c &(*pKitchen).chSink);
printf( "식탁"); scanf(%d &(*pKitchen).nTable);
printf( "가스"); scanf(%d &(*pKitchen).nGasRange);
printf( "[부엌]");
printf( "싱크대 : %c", (*pKitchen).chSink);
printf( "싱크대 : %d", (*pKitchen).nTable);
printf( "싱크대 : %d", (*pKitchen).nGasRange);
return 0;
}
첫번째 줄에서 구조체 포인터 변수 pKitchen 을 선언하고, 널 포인터로 초기화시킨 이후에 kitchen 변수의주소로 변경했습니다.
다음은 scanf함수에 전달한 코드를 해석하는 순서입니다.
1. 구조체 포인터 변수로 부터 값을 구합니다.
*pKitchen //이값은 kitchen 구조체 변수를 가리킵니다 .
2. 값 변수를 이용해 맴버에 접근합니다.
(*pKitchen).chSink // 이값은 kitchen.chSink 맴버 변수를 가리킵니다.
3. 맴버 주소에 접근합니다.
&(*pKitchen).chSink //이주소는 &kitchen.chSink와 같은 주소를 가리킵니다.
단, 점 연산자가 & 연산자보다 우선순위가 높다는 것은 알고 있어야 합니다.
ㅇ * 와 & 연산자의 상쇄
간혹 *와 &연산자가 중복될 경우, 서로 상쇄되는 경우가 있습니다.
int N = 7;
int *pN = &N;
printf("주소 : %d", &(*pN);
*pN은 pN이 가리키는 곳의 값으로 N이 됩니다. 여기에 & 연산자를 붙였기 때문에, 결국 &(*pN)은 &N과 같은 코드를 말합니다. 그런데 바로 윗줄에서 pN과 &N이 같다고 했으므로, &N 대신 pN이라고 쓰는것도 가능합니다. 그래서 다음코드도 괜찮습니다.
printf("주소 : %d", pN);
&와 *연산자가 붙여서 사용된 경우, 지금처럼 없앨수 있는 경우가 있다는 말입니다.
05 중첩 구조체와 포인터
ㅇ 중첩 구조체 선언 및 초기화
구조체 맴버를 갖는 구조체 변수에 초기값을 주는 방법에는 두가지가 있습니다.
struct HOUSE housw1 = {3,2,{'b', 6, 4}};
struct HOUSE housw2 = {3, 2,'b', 6, 4};
ㅇ 중첩 구조체의 맴버로 존재하는 구조체에 접근
struct HOUSE house ={ 0 };
이와 같이 선언된 house 구조체 변수에는 kitchen 구조체 맴버가 들어있습니다. kitchen맴버에 접근하기 위해서는 점 연산자를 사용합니다. 이것이 지금까지 배운 전부입니다.
struct HOUSE house={0};
struct KITCHEN hansem;
hansem.chSink ='B'; // house.kitchen.chSink ='b';
ㅇ 더깊이 들어간 중첩 구조체
부억(KITCHEN)을 구성하는 맴버중에서 가스레인지를 구조체로 만들어 보았습니다.
struct GASRANGE
{
int nFire;
char chGrill;
};
struct KITCHEN
{
char chSink;
int nTable;
struct GASRANGE gasrange;
};
struct HOUSE house = { 0 };
struct KITCHEN hansem;
hansem.gasrange.nFire = 4; //house.kitchen.gasrange.nFire = 4;
------------------------------------------------
struct KITCHEN
{
char chSink;
int nTable;
int nGasRange;
};
struct HOUSE
{
int nRooms;
int nRestRooms;
struct KITCHEN kitchen;
};
struct HOUSE house = { '\0' };
struct HOUSE* pHouse = &house;
(*pHouse).nRooms = 5; // house.nRooms=5;
ㅇ -> 연산자, 두번째 구조체 맴버 연산자
pHouse->kitchen =friend; //(*pHouse).kitchen = friend;
//house.kitchen = friend;
-> 연산자는 * 연산자와 ()를 대신해서 사용합니다. -> 연산자는 * 연산자에 ()를 더한 코드와 오나전히 같습니다. -> 연산자는 없어도 되지만, 단지 *연산자와 ()가 주는 복잡함 때문에 도입되었습니다. .연산자는 왼쪽에 오는 이름이 구조체 값 변수 이름이기를 바라고, -> 연산자는 구조체 포인터 변수 이름이기를 바랍니다.
구조체에서 자료형은 오른쪽의 맴버가 결정한다는 사실만 기억하면 됩니다.
1. 구조체 포인터 변수로부터 값을 구합니다.
pHouse-> // 이값은 hosue 구조체 변수를 가리킵니다.
2. 값 변수를 이요해 맴버에 접근합니다.
pHouse->kitchen // 이값은 house.kitchen 변수를 가리킵니다.
3. 맴버의 맴버에 접근합니다.
pHouse->kitchen.nGasRange // 이값은 house.kitchen.nGasRange 변수를 가리킵니다.
4. 맴버 주소에 접근합니다.
&pHouse -> kitchen.nGasRange // 이주소는 house.kitchen.nGasRange 변수의 주소를 가리킵니다.
작동됩니다. 어떻게 ?
hosue 구조체와 pHouse구조체 포인터 변수는 모두 0으로 초기화 되었고, pHouse와 hosue 변수는 아무런 관련이 없습니다. pHouse 포인터 변수를 초기화 시킨 NULL 상수는 숫자 0을 가리키고 house 구조체 변수의 kitchen.chSink 맴버에 저장한 '\0' 숫자 0을 가리키고, 결국 메모리 전체를 수사자 0으로 채운 셈입니다.
hosue 구조체 변수의 주소를 pHouse 구조체 포인터 변수에 치환한 상태로 pHouse 구조체 포인터 변수가 house 구조체 변수를 가리키고 있습니다. pHouse 구조체 포인터 변수만 변경되었고, 나머지는 변화가 없습니다
scanf 함수로 입력받은 상태ㅡㄹ 보여줍니다. pHouse 구조체 포인터 변수를 통해 입력 받았음에도 불구하고, pHouse 구조체 포인터 변수의 값은 변하지 않았고 hosue 구조체 변수의 값이 바뀌었습니다. pHouse 구조체 포인터 변수를 통해서 house 구조체 변수에 간접적으로 접근하는 모습을 보여줍니다.
pHouse->pKitchen->nTable=4;의 과정 모습
(*pHouse0>pKitchen).nTable=4;
(*(*pHouse).pKitchen).nTable =4;
ㅇ 코드흐름에 따른 구조체 포인터 변수들의 메모리 상태 변화
ㅇ 코드가 흘러가는 순서에 따라 메모리의 상태가 어떻게 바뀌는지 보여줍니다. 왼쪽은 메모리에 할당된 변수들의 값을 보여주고, 오른쪽은 왼쪽 그림을 만든 코드를 보여줍니다.
struct HOUSE *pHosue = NULL;
struct HOUSE house = {0};
struct KITCHEN kitchen = {'0'};
pHouse house
0 0 nRooms
0 nRestRooms
0 pKitchen
kitchen
0 chSink
0 nTable
0 nGasRange
--------------------------------------------
pHouse =&house;
pHouse->pKitchen=&kitchen;
pHouse house
0 0 nRooms
0 nRestRooms
&kitchen pKitchen
kitchen
0 chSink
0 nTable
0 nGasRange
-----------------------------------------------
scanf(%d", &pHouse->nRooms);
scanf(%d", &pHouse->nRestRooms);
scanf(%d", &pHouse->pKitchen->chSink);
scanf(%d", &pHouse->pKitchen->nTable);
scanf(%d", &pHouse->pKitchen->nGasRange);
pHouse house
&hosue 3 nRooms
2 nRestRooms
&kitchen pKitchen
kitchen
B chSink
6 nTable
4 nGasRange
---------------------------------------------------------
1. house와 kitchen 구조체, pHouse 구조체 포인터 변수는 모두 0으로 초기화 되었고, pHouse와 hosue, kitchen 변수는 아무런 관련이 없습니다. pHouse와 house.pKitchen포인터 변수를 초기화 시킨 NULL 상수는 숫자 0을 가리키고, kitchen구조체 변수의 chSink 맴버에 저장한 '\0' 문자 역시 숫자 0을 가리키므로, 결국 메모리 전체를 숫자 0으로 채운셈입니다.
2. hosue 구조체 변수의 주소를 pHouse 구조체 포인터 변수에, kitchen 구조체를 house.pKitchen 포인터 변수 치환한 상태를 보여줍니다. pHouse포인터 변수를 house.로 먼저 초기화 시킨이후에 pKitchen 포인터 맴버를 초기화해야만 한다는 것을 알수 있습니다.
3. scanf 함수로 입력받은 후의 상태를 보여줍니다. pHouse와 pHouse->pKitchen 구조체 포인터 변수를 통해 입력 받았음에도 불구하고, pHouse와 pHouse->pKitchen 고주체 포인터 변수의 값은 변하지 않았고 hosue와 kitchen 구조체 변수의 값이 바뀌었습니다. 구조체 포인터 변수를 통해서 구조체 변수에 간접적으로 접근하는 모습을 보여줍니다.
06. 구조체 패딩과 스왑
ㅇ 맴버 정렬에 따른 구조체 크기 변화
1. struct PAD11
{
char ch;
double dbl;
};
--------> 16byte
2. struct PAD2
{
char ch;
int n:
};
--------------> 8Byte
int 자료형이므로 4로 나누어 떨어지느 주소가 시작주소이고 두번째 구조체는 double 자료형으로 8로 나누어 떨어지는 주소가 시작주소가 됩니다.
첫번째 구조체에서 ch 맴버는 첫번째 맴버이고 1바이트 자료형이므로, 어떤 주소라도 상관없습니다.
두번째 맴버인 dbl은 8바이트로 나누어 떨어져야 하므로 시작 주소에서부터 8바이트 떨어진 주소에 할당됩니다. 그래서 구조체 전체는 16바이트를 사용하니다. 두번쨰 구조체에서 ch 맴버는 4로 나누어 떨지는 구조체 주소와 같은 주소에 할당됩니다. 다음으로 N맴버는 시작주소에서 4만큼 떨어진 주소에 할당되므로 전체크기는 89이 되니다.
ㅇ메모리 절약을 위한 효율적인 맴버 배치
1번
struct PAD1
{
char ch;
int n;
double dbl;
};
2번
struct PAD2
{
char ch;
double dbl;
int n;
};
3번
struct PAD3
{
double dbl;
char ch;
int n;
};
4번
struct PAD4
{
int n;
char ch;
double dbl;
};
2번 구조체는 24바이트를 사용하고, 나머지는 모두 16바이트 입니다. 2번 구조체는 할당 주소의 기준이 되는 double 맴버가 중간에 끼어 있기 때문에 24바이트를 사용하는것입니다.
전체 구조에서 가장 중요한 것은 double 자료 맴버인 dbl이 8의 배수가 되는 주소에 들어가야 된다는 사실입니다. 그래서 double 자료형 맴버가 가운데 있게 되면, 앞뒤로 8바이트씩의 메모리가 더 필요하게 되고, 총 24바이트의 메모리가 할당됩니다. 참고로 패딩은 맴버 가운데 들어가는 것이 일반적이지만, 마지막으로 추가된다는 것을 기억해야 하니다.
다음은 닷넷 컴파일러에서 메모리에 할당된 구조체 맴버의 주소를 출력한 결과입니다. 결과를 분석하기에는 괜히 어렵고 귀찮아 보이지만, 출력된 주소가 구조체 정의에 나타난 맴버들의 순서라는 것만 기억하면 쉽습니다. 주소 확인 char 자료형은 11의 배수, int 자료형은 4의 배수, double 자료형은 8의 배수인지 계산기로 검사합니다.
그러나 맴버 배치에 있어 가장 중요한 것은 패딩의 효과적인 방지 일수도 있지만, 연관성있는 맴버끼리 붙여놓은 것이 더욱 중요합니다. 같은 구조체 안에 있어도 더 관련이 있고 덜 관련이 있는 맴버들이 있습니다. 이들을 구분해서 패딩을 제거해 나갈때 가장 훌륭한 구조체 정의가 탄생합니다.
ㅇ 구조체 포인터 변수 간접 교환 구현 예제
#include<stdio.h>
struct BANK
{
int nBirth;
int gender;
int nPhone;
};
int main()
{
struct BANK hana = {1225, 1, 12345678},
woori = {1003, 0, 87654321};
struct BANK* pHana = NULL;
* pWoori = NULL;
* pTemp = NULL;
pHana = &hana;
pWoori = &woori;
printf("[원본]");
printf("hana : %d %d %d", pHana->nBirth, pHana->gender, pHana->nPhone);
printf("woori : %d %d %d", pWoori->nBirth, pWoori->gender, pWoori->nPhone);
pTemp = pHana;
pHana - pWoori;
pWoori = pTemp;
/*
nTemp = hana.nBirth;
hana.nBirth = woori.nBirth;
woori.nBirth = nTemp;
*/
printf("[교환]");
printf("hana : %d %d %d", pHana->nBirth, pHana->gender, pHana->nPhone);
printf("woori : %d %d %d", pWoori->nBirth, pWoori->gender, pWoori->nPhone);
'BOOK Study > C/C++' 카테고리의 다른 글
| 02. 변수 part 02 (0) | 2010/01/13 |
|---|---|
| 02. 변수 part 01 (0) | 2010/01/12 |
| 01. 개요 (0) | 2010/01/12 |
| C언어의 내용을 파헤쳐 보는 첫번째 수준 높은 예제로 풀어보는 포인터와 함께하는 C의 아름다움 (0) | 2010/01/12 |


4534_javaee6_ejb3.1.zip
Session4EJB31.pdf
derbyclient.jar


Recent comment